# Fumadocs Core (the core library of Fumadocs): Trieve 搜尋
URL: /zh-TW/docs/headless/search/trieve
Source: https://raw.githubusercontent.com/fuma-nama/fumadocs/refs/heads/main/apps/docs/content/docs/headless/search/trieve.zh-TW.mdx

將 Trieve 搜尋整合至 Fumadocs

> 此整合由社群維護。

## 簡介 [#introduction]

Trieve 整合會自動設定 Trieve Search，用於網站搜尋。

預設情況下，它會為文件中的**每個段落**各建立一個 chunk，這也是
Trieve 官方建議的做法。

## 設定 [#setup]

### 安裝相依套件 [#install-dependencies]

```package-install
trieve-ts-sdk trieve-fumadocs-adapter
```

### 註冊 Trieve [#sign-up-on-trieve]

請先註冊並建立一個資料集 (dataset) ，接著取得 2 組 API 金鑰：一組僅有讀取權限，另一組則具備管理員權限，可用來建立及刪除 chunk。
請將資料集 ID 與管理員金鑰存放在 `.env.local` 中，以便進行同步：

```dotenv
TRIEVE_DATASET_ID="dataset ID"
TRIEVE_ADMIN_API_KEY="admin API key"
```

<Callout title="注意">
其中一組 API Key 應僅具備唯讀權限，供對外公開的搜尋使用；另一組則需具備
管理員權限，用於建立及刪除 chunk。
</Callout>

### 同步資料集 [#sync-dataset]

Trieve 會沿用 [Algolia 整合](/docs/headless/search/algolia)的紀錄。請透過預先算繪的 `static.json` 路由匯出這些紀錄，並在每次建置後以指令碼將其同步至 Trieve：

```ts tab="Next.js" title="app/static.json/route.ts"
import { source } from '@/lib/source';
import { toDocuments } from 'fumadocs-core/search/algolia';

export const revalidate = false;

export async function GET() {
  return Response.json(await toDocuments(source));
}

```

```ts tab="Next.js" title="scripts/sync-content.ts"
import * as fs from 'node:fs/promises';
import { sync, type TrieveDocument as DocumentRecord } from 'trieve-fumadocs-adapter/search/sync';
import { TrieveSDK } from 'trieve-ts-sdk';

// Next.js writes it under `route-cache` when built with an adapter, like on Vercel
const [file] = await Array.fromAsync(fs.glob('.next/server/{app,route-cache/*/*/$}/static.json.body'));
const records = JSON.parse(await fs.readFile(file, 'utf-8')) as DocumentRecord[];

const client = new TrieveSDK({
  apiKey: process.env.TRIEVE_ADMIN_API_KEY!,
  datasetId: process.env.TRIEVE_DATASET_ID!,
});

await sync(client, records);

console.log(`search updated: ${records.length} records`);

```

```json tab="Next.js" title="package.json"
{
  "scripts": {
    "build": "next build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
  }
}
```

```ts tab="React Router" title="app/routes/static.json.ts"
import { source } from '@/lib/source';
import { toDocuments } from 'fumadocs-core/search/algolia';

export async function loader() {
  return Response.json(await toDocuments(source));
}

```

```ts tab="React Router" title="app/routes.ts"
import { index, route, type RouteConfig } from '@react-router/dev/routes';

export default [
  index('routes/home.tsx'),
  route('static.json', 'routes/static.json.ts'), // [!code ++:1]
] satisfies RouteConfig;

```

```ts tab="React Router" title="scripts/sync-content.ts"
import * as fs from 'node:fs/promises';
import { sync, type TrieveDocument as DocumentRecord } from 'trieve-fumadocs-adapter/search/sync';
import { TrieveSDK } from 'trieve-ts-sdk';

const records = JSON.parse(await fs.readFile('build/client/static.json', 'utf-8')) as DocumentRecord[];

const client = new TrieveSDK({
  apiKey: process.env.TRIEVE_ADMIN_API_KEY!,
  datasetId: process.env.TRIEVE_DATASET_ID!,
});

await sync(client, records);

console.log(`search updated: ${records.length} records`);

```

```json tab="React Router" title="package.json"
{
  "scripts": {
    "build": "react-router build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
  }
}
```

```ts tab="TanStack Start" title="src/routes/static[.]json.ts"
import { createFileRoute } from '@tanstack/react-router';
import { source } from '@/lib/source';
import { toDocuments } from 'fumadocs-core/search/algolia';

export const Route = createFileRoute('/static.json')({
  server: {
    handlers: {
      GET: async () => Response.json(await toDocuments(source)),
    },
  },
});

```

```ts tab="TanStack Start" title="vite.config.ts"
import { tanstackStart } from '@tanstack/react-start/plugin/vite';
import { nitro } from 'nitro/vite';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    tanstackStart({
      prerender: {
        enabled: true,
      },
      pages: [ // [!code ++:3]
        { path: '/static.json' }
      ],
    }),
    nitro({
      preset: 'vercel',
    }),
  ],
});

```

```ts tab="TanStack Start" title="scripts/sync-content.ts"
import * as fs from 'node:fs/promises';
import { sync, type TrieveDocument as DocumentRecord } from 'trieve-fumadocs-adapter/search/sync';
import { TrieveSDK } from 'trieve-ts-sdk';

const records = JSON.parse(await fs.readFile('.vercel/output/static/static.json', 'utf-8')) as DocumentRecord[];

const client = new TrieveSDK({
  apiKey: process.env.TRIEVE_ADMIN_API_KEY!,
  datasetId: process.env.TRIEVE_DATASET_ID!,
});

await sync(client, records);

console.log(`search updated: ${records.length} records`);

```

```json tab="TanStack Start" title="package.json"
{
  "scripts": {
    "build": "vite build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
  }
}
```

```ts tab="Waku" title="src/pages/_api/static.json.ts"
import { source } from '@/lib/source';
import { toDocuments } from 'fumadocs-core/search/algolia';

export async function GET() {
  return Response.json(await toDocuments(source));
}

export async function getConfig() {
  return {
    render: 'static' as const,
  } as const;
}

```

```ts tab="Waku" title="scripts/sync-content.ts"
import * as fs from 'node:fs/promises';
import { sync, type TrieveDocument as DocumentRecord } from 'trieve-fumadocs-adapter/search/sync';
import { TrieveSDK } from 'trieve-ts-sdk';

const records = JSON.parse(await fs.readFile('dist/public/static.json', 'utf-8')) as DocumentRecord[];

const client = new TrieveSDK({
  apiKey: process.env.TRIEVE_ADMIN_API_KEY!,
  datasetId: process.env.TRIEVE_DATASET_ID!,
});

await sync(client, records);

console.log(`search updated: ${records.length} records`);

```

```json tab="Waku" title="package.json"
{
  "scripts": {
    "build": "waku build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
  }
}
```

```ts tab="Astro" title="src/pages/static.json.ts"
import type { APIRoute } from 'astro';
import { source } from '@/lib/source';
import { toDocuments } from 'fumadocs-core/search/algolia';

export const prerender = true;

export const GET: APIRoute = async () => Response.json(await toDocuments(source));

```

```ts tab="Astro" title="scripts/sync-content.ts"
import * as fs from 'node:fs/promises';
import { sync, type TrieveDocument as DocumentRecord } from 'trieve-fumadocs-adapter/search/sync';
import { TrieveSDK } from 'trieve-ts-sdk';

const records = JSON.parse(await fs.readFile('dist/static.json', 'utf-8')) as DocumentRecord[];

const client = new TrieveSDK({
  apiKey: process.env.TRIEVE_ADMIN_API_KEY!,
  datasetId: process.env.TRIEVE_DATASET_ID!,
});

await sync(client, records);

console.log(`search updated: ${records.length} records`);

```

```json tab="Astro" title="package.json"
{
  "scripts": {
    "build": "astro build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
  }
}
```

`build` 指令碼會在每次建置時進行同步，因此請在您的部署平台上設定相同的變數。

### 搜尋 UI [#search-ui]

您可以使用對方提供的 `SearchDialog` 元件：

```tsx title="components/search.tsx"
'use client';
import type { SharedProps } from 'fumadocs-ui/components/dialog/search';
import SearchDialog from 'trieve-fumadocs-adapter/components/dialog/search';
import { TrieveSDK } from 'trieve-ts-sdk';

const trieveClient = new TrieveSDK({
  apiKey: 'readOnlyApiKey',
  datasetId: 'datasetId',
});

export default function CustomSearchDialog(props: SharedProps) {
  return <SearchDialog trieveClient={trieveClient} {...props} />;
}
```

1. 將 `apiKey` 和 `datasetId` 替換為您要使用的值。

2. 將預設的搜尋對話方塊替換為您新建立的版本。

### 搜尋用戶端 [#search-client]

加入 `useTrieveSearch` hook：

```ts
import { TrieveSDK } from 'trieve-ts-sdk';
import { useTrieveSearch } from 'trieve-fumadocs-adapter/search/trieve';

const client = new TrieveSDK({
  apiKey: 'readOnlyApiKey',
  datasetId: 'datasetId',
});

const { search, setSearch, query } = useTrieveSearch(client);
```

## 選項 [#options]

### 標籤篩選 [#tag-filter]

若要設定標籤篩選，請在索引中加入 `tag` 值。

```js
import { sync } from 'trieve-fumadocs-adapter/search/sync';
import { TrieveSDK } from 'trieve-ts-sdk';

const client = new TrieveSDK({
  apiKey: 'adminApiKey',
  datasetId: 'datasetId',
});

const documents = records.map((index) => ({
  ...index,
  tag: 'value', // [!code highlight]
}));

sync(client, documents);
```

#### 搜尋 UI [#search-ui-1]

啟用標籤篩選。

```tsx title="components/search.tsx"
import SearchDialog from 'trieve-fumadocs-adapter/components/dialog/search';

<SearchDialog
  defaultTag="value"
  tags={[
    {
      name: 'Tag Name',
      value: 'value',
    },
  ]}
/>;
```

#### 搜尋用戶端 [#search-client-1]

`tag_set` 欄位是用於篩選的屬性。若要依標籤篩選索引，請在 Trieve 搜尋用戶端中使用篩選功能。

```json
{
  "must": [
    {
      "field": "tag_set",
      "match": ["value"]
    }
  ]
}
```

或使用 `useTrieveSearch` hook：

```ts
import { TrieveSDK } from 'trieve-ts-sdk';
import { useTrieveSearch } from 'trieve-fumadocs-adapter/search/trieve';

const client = new TrieveSDK({
  apiKey: 'readOnlyApiKey',
  datasetId: 'datasetId',
});

const { search, setSearch, query } = useTrieveSearch(client, undefined, '<your tag value>');
```