From 40236fb2e58c81d90912ae38a16c6cccebb93189 Mon Sep 17 00:00:00 2001 From: dailin01 Date: Thu, 1 Aug 2024 20:50:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E7=99=BE=E5=BA=A6?= =?UTF-8?q?=E5=8D=83=E5=B8=86SDK=20stream?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/client/platforms/baidu.ts | 170 +++++----------------------------- 1 file changed, 23 insertions(+), 147 deletions(-) diff --git a/app/client/platforms/baidu.ts b/app/client/platforms/baidu.ts index bc2224957a1..f6f741f92aa 100644 --- a/app/client/platforms/baidu.ts +++ b/app/client/platforms/baidu.ts @@ -1,27 +1,10 @@ "use client"; -import { - ApiPath, - Baidu, - BAIDU_BASE_URL, - REQUEST_TIMEOUT_MS, -} from "@/app/constant"; +import { ApiPath, Baidu, BAIDU_BASE_URL } from "@/app/constant"; import { useAccessStore, useAppConfig, useChatStore } from "@/app/store"; import { getAccessToken } from "@/app/utils/baidu"; import { ChatCompletion } from "@baiducloud/qianfan"; -import { - ChatOptions, - getHeaders, - LLMApi, - LLMModel, - MultimodalContent, -} from "../api"; -import Locale from "../../locales"; -import { - EventStreamContentType, - fetchEventSource, -} from "@fortaine/fetch-event-source"; -import { prettyObject } from "@/app/utils/format"; +import { ChatOptions, LLMApi, LLMModel, MultimodalContent } from "../api"; import { getClientConfig } from "@/app/config/client"; import { getMessageTextContent } from "@/app/utils"; @@ -132,141 +115,34 @@ export class ErnieApi implements LLMApi { } } } - const chatPayload = { - method: "POST", - body: JSON.stringify(requestPayload), - signal: controller.signal, - headers: getHeaders(), - }; - // make a fetch request - const requestTimeoutId = setTimeout( - () => controller.abort(), - REQUEST_TIMEOUT_MS, + // SDK替换 + const accessStore = useAccessStore.getState(); + const client = new ChatCompletion({ + QIANFAN_AK: accessStore.baiduApiKey, + QIANFAN_SK: accessStore.baiduSecretKey, + QIANFAN_BASE_URL: `${window.location.origin}${ + accessStore.baiduUrl || "/api/baidu" + }`, + }); + + const stream = await client.chat( + { + ...requestPayload, + }, + modelConfig.model.toUpperCase(), ); + let result = ""; if (shouldStream) { - let responseText = ""; - let remainText = ""; - let finished = false; - - // animate response to make it looks smooth - function animateResponseText() { - if (finished || controller.signal.aborted) { - responseText += remainText; - console.log("[Response Animation] finished"); - if (responseText?.length === 0) { - options.onError?.(new Error("empty response from server")); - } - return; - } - - if (remainText.length > 0) { - const fetchCount = Math.max(1, Math.round(remainText.length / 60)); - const fetchText = remainText.slice(0, fetchCount); - responseText += fetchText; - remainText = remainText.slice(fetchCount); - options.onUpdate?.(responseText, fetchText); - } - - requestAnimationFrame(animateResponseText); + for await (const chunk of stream) { + result = result + chunk?.result || ""; } - - // start animaion - animateResponseText(); - - const finish = () => { - if (!finished) { - finished = true; - options.onFinish(responseText + remainText); - } - }; - - controller.signal.onabort = finish; - - fetchEventSource(chatPath, { - ...chatPayload, - async onopen(res) { - clearTimeout(requestTimeoutId); - const contentType = res.headers.get("content-type"); - console.log("[Baidu] request response content type: ", contentType); - - if (contentType?.startsWith("text/plain")) { - responseText = await res.clone().text(); - return finish(); - } - - if ( - !res.ok || - !res.headers - .get("content-type") - ?.startsWith(EventStreamContentType) || - res.status !== 200 - ) { - const responseTexts = [responseText]; - let extraInfo = await res.clone().text(); - try { - const resJson = await res.clone().json(); - extraInfo = prettyObject(resJson); - } catch {} - - if (res.status === 401) { - responseTexts.push(Locale.Error.Unauthorized); - } - - if (extraInfo) { - responseTexts.push(extraInfo); - } - - responseText = responseTexts.join("\n\n"); - - return finish(); - } - }, - onmessage(msg) { - if (msg.data === "[DONE]" || finished) { - return finish(); - } - const text = msg.data; - try { - const json = JSON.parse(text); - const delta = json?.result; - if (delta) { - remainText += delta; - } - } catch (e) { - console.error("[Request] parse error", text, msg); - } - }, - onclose() { - finish(); - }, - onerror(e) { - options.onError?.(e); - throw e; - }, - openWhenHidden: true, - }); } else { - // SDK替换 - const accessStore = useAccessStore.getState(); - const client = new ChatCompletion({ - QIANFAN_AK: accessStore.baiduApiKey, - QIANFAN_SK: accessStore.baiduSecretKey, - QIANFAN_BASE_URL: `${window.location.origin}${ - accessStore.baiduUrl || "/api/baidu" - }`, - }); - - const resp = await client.chat( - { - ...requestPayload, - }, - modelConfig.model.toUpperCase(), - ); - - options.onFinish(resp?.result); + result = stream?.result || ""; } + + options.onFinish(result); } catch (e) { console.log("[Request] failed to make a chat request", e); options.onError?.(e as Error);