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

4 KiB
Raw Blame History

会话 API 实现逻辑

LobeChat 的大模型 AI 实现主要依赖于 OpenAI 的 API包括后端的核心会话 API 和前端的集成 API。接下来我们将分别介绍后端和前端的实现思路和代码。

后端实现

以下代码中移除了鉴权、错误处理等逻辑,仅保留了核心的主要功能逻辑。

核心会话 API

src/app/api/openai/chat/handler.ts 文件中,我们定义了 POST 方法,该方法首先从请求中解析出 payload 数据(即客户端发送的会话内容),然后从请求中获取 OpenAI 的授权信息。之后,我们创建一个 openai 对象,并调用 createChatCompletion 方法,该方法负责发送会话请求到 OpenAI 并返回结果。

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 中的 OpenAIStream 将返回的结果转化为流式响应。

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 接口,并将请求结果返回。

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 回调函数处理数据块,进而实现打字机输出效果。

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 功能。