lobehub/docs/Development/Chat-API.zh-CN.md
CanisMinor d1df19a498
🔨 chore: Add docs workflow (#658)
* 🔧 chore: Add docs workflow and update docs files

* 📝 docs: Update wiki docs link
2023-12-14 17:17:43 +08:00

127 lines
4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 会话 API 实现逻辑
LobeChat 的大模型 AI 实现主要依赖于 OpenAI 的 API包括后端的核心会话 API 和前端的集成 API。接下来我们将分别介绍后端和前端的实现思路和代码。
## 后端实现
以下代码中移除了鉴权、错误处理等逻辑,仅保留了核心的主要功能逻辑。
### 核心会话 API
`src/app/api/openai/chat/handler.ts` 文件中,我们定义了 `POST` 方法,该方法首先从请求中解析出 payload 数据(即客户端发送的会话内容),然后从请求中获取 OpenAI 的授权信息。之后,我们创建一个 `openai` 对象,并调用 `createChatCompletion` 方法,该方法负责发送会话请求到 OpenAI 并返回结果。
```ts
export const POST = async (req: Request) => {
const payload = await req.json();
const { apiKey, endpoint } = getOpenAIAuthFromRequest(req);
const openai = createOpenai(apiKey, endpoint);
return createChatCompletion({ openai, payload });
};
```
### 会话结果处理
`src/app/api/openai/chat/createChatCompletion.ts` 文件中,我们定义了 `createChatCompletion` 方法,该方法首先对 payload 数据进行预处理,然后调用 OpenAI 的 `chat.completions.create` 方法发送请求,并使用 [Vercel AI SDK](https://sdk.vercel.ai/docs) 中的 `OpenAIStream` 将返回的结果转化为流式响应。
```ts
import { OpenAIStream, StreamingTextResponse } from 'ai';
export const createChatCompletion = async ({ payload, openai }: CreateChatCompletionOptions) => {
const { messages, ...params } = payload;
const formatMessages = messages.map((m) => ({
content: m.content,
name: m.name,
role: m.role,
}));
const response = await openai.chat.completions.create(
{
messages: formatMessages,
...params,
stream: true,
},
{ headers: { Accept: '*/*' } },
);
const stream = OpenAIStream(response);
return new StreamingTextResponse(stream);
};
```
## 前端实现
### 前端集成
`src/services/chatModel.ts` 文件中,我们定义了 `fetchChatModel` 方法,该方法首先对 payload 数据进行前置处理,然后发送 POST 请求到后端的 `/chat` 接口,并将请求结果返回。
```ts
export const fetchChatModel = (
{ plugins: enabledPlugins, ...params }: Partial<OpenAIStreamPayload>,
options?: FetchChatModelOptions,
) => {
const payload = merge(
{
model: initialLobeAgentConfig.model,
stream: true,
...initialLobeAgentConfig.params,
},
params,
);
const filterFunctions: ChatCompletionFunctions[] = pluginSelectors.enabledSchema(enabledPlugins)(
usePluginStore.getState(),
);
const functions = filterFunctions.length === 0 ? undefined : filterFunctions;
return fetch(OPENAI_URLS.chat, {
body: JSON.stringify({ ...payload, functions }),
headers: createHeaderWithOpenAI({ 'Content-Type': 'application/json' }),
method: 'POST',
signal: options?.signal,
});
};
```
### 使用流式获取结果
`src/utils/fetch.ts` 文件中,我们定义了 `fetchSSE` 方法,该方法使用流式方法获取数据,当读取到新的数据块时,会调用 `onMessageHandle` 回调函数处理数据块,进而实现打字机输出效果。
```ts
export const fetchSSE = async (fetchFn: () => Promise<Response>, options: FetchSSEOptions = {}) => {
const response = await fetchFn();
if (!response.ok) {
const chatMessageError = await getMessageError(response);
options.onErrorHandle?.(chatMessageError);
return;
}
const returnRes = response.clone();
const data = response.body;
if (!data) return;
const reader = data.getReader();
const decoder = new TextDecoder();
let done = false;
while (!done) {
const { value, done: doneReading } = await reader.read();
done = doneReading;
const chunkValue = decoder.decode(value);
options.onMessageHandle?.(chunkValue);
}
return returnRes;
};
```
以上就是 LobeChat 会话 API 的核心实现。在理解了这些核心代码的基础上,便可以进一步扩展和优化 LobeChat 的 AI 功能。