跳至內容
Fumadocs

Mixedbread

將 Mixedbread Search 整合至 Fumadocs

Mixedbread 提供語意搜尋功能,讓使用者能以自然語言搜尋,依照語意而非關鍵字找到內容。

設定

安裝相依套件:

npm install @mixedbread/sdk

API 金鑰

請先在 Mixedbread 註冊,並為您的文件建立一組 API 金鑰和一個儲存區,再將兩者存放到 .env.local 中:

MXBAI_API_KEY="your API key"
MIXEDBREAD_STORE_ID="your store ID"

搜尋會在您的伺服器上執行,因此 API 金鑰絕不會暴露給瀏覽器。

同步文件

預先算繪 static.json 路由,以便在建置時匯出搜尋文件,並在每次建置後透過指令碼將這些文件同步至您的儲存區:

app/static.json/route.ts
import { source } from '@/lib/source';
import { toDocuments } from 'fumadocs-core/search/mixedbread';

export const revalidate = false;

export async function GET() {
  return Response.json(await toDocuments(source));
}
scripts/sync-content.ts
import * as fs from 'node:fs/promises';
import { type DocumentRecord, sync } from 'fumadocs-core/search/mixedbread';
import Mixedbread from '@mixedbread/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[];

await sync(new Mixedbread(), {
  storeIdentifier: process.env.MIXEDBREAD_STORE_ID!,
  documents: records,
});

console.log(`search updated: ${records.length} records`);
package.json
{
  "scripts": {
    "build": "next build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
  }
}

sync() 會為每個頁面上傳一個檔案,並略過自上次同步後未變更的頁面。已移除頁面的檔案也會一併刪除,因此請使用專供您的文件使用的儲存區。build 指令碼會在每次建置時進行同步,請在您的部署平台上設定相同的變數。

搜尋 API

建立用來搜尋您儲存區的路由:

app/api/search/route.ts
import { createMixedbreadSearchAPI } from 'fumadocs-core/search/mixedbread';
import Mixedbread from '@mixedbread/sdk';

export const { GET } = createMixedbreadSearchAPI({
  client: new Mixedbread(), // 會讀取 `MXBAI_API_KEY`
  storeIdentifier: process.env.MIXEDBREAD_STORE_ID!,
});

搜尋 UI

您可以考慮以下幾種實作 UI 的方式:

  • 使用 Fumadocs UI 搜尋對話方塊。

  • 透過內建的搜尋用戶端 hook 自行打造:

    import {  } from 'fumadocs-core/search/client';
    
    const { , , ,  } = ({
      : '/api/search',
      // 每次搜尋都會向 Mixedbread 發送一次請求
      : 300,
    });

選項

標籤篩選

若要設定標籤篩選,請在 static.json 路由中將 tag 傳入 toDocuments():

toDocuments(source, { tag: (page) => page.slugs[0] });

接著更新您的搜尋用戶端:

  • Fumadocs UI:在搜尋 UI 中啟用標籤篩選。

  • 搜尋用戶端:將標籤傳入 useFetchSearch()。

    import { useFetchSearch } from 'fumadocs-core/search/client';
    
    const { search, onSearchChange, isLoading, data } = useFetchSearch({
      tag: '<your tag value>', 
      // ...
    });

國際化

文件會包含所屬頁面的語系,傳入 locale 即可搜尋特定語言的內容:

import { useI18n } from 'fumadocs-ui/contexts/i18n';
import { useFetchSearch } from 'fumadocs-core/search/client';

const { locale } = useI18n();
const { search, onSearchChange, isLoading, data } = useFetchSearch({
  locale, 
  // ...
});

運作原理

每個頁面都是一個以 URL 為鍵的檔案,並以頁面標題、URL、Breadcrumb、標籤和語系作為中繼資料。頁面的區塊 (chunk) 包括頁面標題、各個標題與段落,而每筆搜尋結果都是一個區塊:

區塊中繼資料說明
kindpage、heading 或 text
heading所屬標題的 ID (選用)
table表格列所屬的表格 (選用)

How is this guide?

最後更新於