mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-10-03 00:26:40 +08:00
Merge 429e8abdc1
into b4dc4d34eb
This commit is contained in:
commit
69bfc8ba4e
@ -58,7 +58,7 @@ export interface ChatOptions {
|
|||||||
config: LLMConfig;
|
config: LLMConfig;
|
||||||
|
|
||||||
onUpdate?: (message: string, chunk: string) => void;
|
onUpdate?: (message: string, chunk: string) => void;
|
||||||
onFinish: (message: string) => void;
|
onFinish: (message: string, finishedReason?: string) => void;
|
||||||
onError?: (err: Error) => void;
|
onError?: (err: Error) => void;
|
||||||
onController?: (controller: AbortController) => void;
|
onController?: (controller: AbortController) => void;
|
||||||
onBeforeTool?: (tool: ChatMessageTool) => void;
|
onBeforeTool?: (tool: ChatMessageTool) => void;
|
||||||
|
@ -26,6 +26,10 @@ export const ChatControllerPool = {
|
|||||||
return Object.values(this.controllers).length > 0;
|
return Object.values(this.controllers).length > 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getPendingMessageId() {
|
||||||
|
return Object.keys(this.controllers).map((v) => v.split(",").at(-1));
|
||||||
|
},
|
||||||
|
|
||||||
remove(sessionId: string, messageId: string) {
|
remove(sessionId: string, messageId: string) {
|
||||||
const key = this.key(sessionId, messageId);
|
const key = this.key(sessionId, messageId);
|
||||||
delete this.controllers[key];
|
delete this.controllers[key];
|
||||||
|
@ -255,7 +255,7 @@ export class ClaudeApi implements LLMApi {
|
|||||||
runTools[index]["function"]["arguments"] +=
|
runTools[index]["function"]["arguments"] +=
|
||||||
chunkJson?.delta?.partial_json;
|
chunkJson?.delta?.partial_json;
|
||||||
}
|
}
|
||||||
return chunkJson?.delta?.text;
|
return { delta: chunkJson?.delta?.text };
|
||||||
},
|
},
|
||||||
// processToolMessage, include tool_calls message and tool call results
|
// processToolMessage, include tool_calls message and tool call results
|
||||||
(
|
(
|
||||||
|
@ -144,7 +144,7 @@ export class MoonshotApi implements LLMApi {
|
|||||||
runTools[index]["function"]["arguments"] += args;
|
runTools[index]["function"]["arguments"] += args;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return choices[0]?.delta?.content;
|
return { delta: choices[0]?.delta?.content };
|
||||||
},
|
},
|
||||||
// processToolMessage, include tool_calls message and tool call results
|
// processToolMessage, include tool_calls message and tool call results
|
||||||
(
|
(
|
||||||
|
@ -260,6 +260,7 @@ export class ChatGPTApi implements LLMApi {
|
|||||||
content: string;
|
content: string;
|
||||||
tool_calls: ChatMessageTool[];
|
tool_calls: ChatMessageTool[];
|
||||||
};
|
};
|
||||||
|
finish_reason?: string;
|
||||||
}>;
|
}>;
|
||||||
const tool_calls = choices[0]?.delta?.tool_calls;
|
const tool_calls = choices[0]?.delta?.tool_calls;
|
||||||
if (tool_calls?.length > 0) {
|
if (tool_calls?.length > 0) {
|
||||||
@ -280,7 +281,10 @@ export class ChatGPTApi implements LLMApi {
|
|||||||
runTools[index]["function"]["arguments"] += args;
|
runTools[index]["function"]["arguments"] += args;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return choices[0]?.delta?.content;
|
return {
|
||||||
|
delta: choices[0]?.delta?.content,
|
||||||
|
finishReason: choices[0]?.finish_reason,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
// processToolMessage, include tool_calls message and tool call results
|
// processToolMessage, include tool_calls message and tool call results
|
||||||
(
|
(
|
||||||
|
@ -9,6 +9,7 @@ import React, {
|
|||||||
RefObject,
|
RefObject,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
|
import ContinueIcon from "../icons/continue.svg";
|
||||||
import SendWhiteIcon from "../icons/send-white.svg";
|
import SendWhiteIcon from "../icons/send-white.svg";
|
||||||
import BrainIcon from "../icons/brain.svg";
|
import BrainIcon from "../icons/brain.svg";
|
||||||
import RenameIcon from "../icons/rename.svg";
|
import RenameIcon from "../icons/rename.svg";
|
||||||
@ -460,7 +461,16 @@ export function ChatActions(props: {
|
|||||||
|
|
||||||
// stop all responses
|
// stop all responses
|
||||||
const couldStop = ChatControllerPool.hasPending();
|
const couldStop = ChatControllerPool.hasPending();
|
||||||
const stopAll = () => ChatControllerPool.stopAll();
|
const stopAll = () => {
|
||||||
|
const stopList = ChatControllerPool.getPendingMessageId();
|
||||||
|
ChatControllerPool.stopAll();
|
||||||
|
chatStore.updateCurrentSession(
|
||||||
|
(session) =>
|
||||||
|
(session.messages = session.messages.map((v) =>
|
||||||
|
stopList.includes(v.id) ? { ...v, finishedReason: "aborted" } : v,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// switch model
|
// switch model
|
||||||
const currentModel = chatStore.currentSession().mask.modelConfig.model;
|
const currentModel = chatStore.currentSession().mask.modelConfig.model;
|
||||||
@ -1044,6 +1054,12 @@ function _Chat() {
|
|||||||
// stop response
|
// stop response
|
||||||
const onUserStop = (messageId: string) => {
|
const onUserStop = (messageId: string) => {
|
||||||
ChatControllerPool.stop(session.id, messageId);
|
ChatControllerPool.stop(session.id, messageId);
|
||||||
|
chatStore.updateCurrentSession(
|
||||||
|
(session) =>
|
||||||
|
(session.messages = session.messages.map((v) =>
|
||||||
|
v.id === messageId ? { ...v, finishedReason: "aborted" } : v,
|
||||||
|
)),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -1170,6 +1186,18 @@ function _Chat() {
|
|||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onContinue = (messageID: string) => {
|
||||||
|
chatStore.updateCurrentSession(
|
||||||
|
(session) =>
|
||||||
|
(session.messages = session.messages.map((v) =>
|
||||||
|
v.id === messageID ? { ...v, streaming: true } : v,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
chatStore
|
||||||
|
.onContinueBotMessage(messageID)
|
||||||
|
.finally(() => setIsLoading(false));
|
||||||
|
};
|
||||||
|
|
||||||
const onPinMessage = (message: ChatMessage) => {
|
const onPinMessage = (message: ChatMessage) => {
|
||||||
chatStore.updateCurrentSession((session) =>
|
chatStore.updateCurrentSession((session) =>
|
||||||
session.mask.context.push(message),
|
session.mask.context.push(message),
|
||||||
@ -1723,6 +1751,15 @@ function _Chat() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
{["length", "aborted"].includes(
|
||||||
|
message.finishedReason ?? "",
|
||||||
|
) ? (
|
||||||
|
<ChatAction
|
||||||
|
text={Locale.Chat.Actions.Continue}
|
||||||
|
icon={<ContinueIcon />}
|
||||||
|
onClick={() => onContinue(message.id)}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
1
app/icons/continue.svg
Normal file
1
app/icons/continue.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1726395286651" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10075" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M427.84 911.648a79.616 79.616 0 0 1-79.68-79.712V191.328a79.68 79.68 0 0 1 122.24-67.36l506.784 320.448a79.296 79.296 0 0 1 37.056 67.328c0 27.488-13.888 52.672-37.12 67.328L470.368 899.328a79.424 79.424 0 0 1-42.528 12.32z m16.32-690.688v581.376l459.808-290.624L444.16 220.96zM65.728 911.648a48 48 0 0 1-48-48v-704a48 48 0 1 1 96 0v704a48 48 0 0 1-48 48z" fill="#040000" p-id="10076"></path></svg>
|
After Width: | Height: | Size: 730 B |
@ -45,6 +45,7 @@ const ar: PartialLocaleType = {
|
|||||||
Edit: "تحرير",
|
Edit: "تحرير",
|
||||||
RefreshTitle: "تحديث العنوان",
|
RefreshTitle: "تحديث العنوان",
|
||||||
RefreshToast: "تم إرسال طلب تحديث العنوان",
|
RefreshToast: "تم إرسال طلب تحديث العنوان",
|
||||||
|
Continue: "استمر",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "دردشة جديدة",
|
new: "دردشة جديدة",
|
||||||
|
@ -45,6 +45,7 @@ const bn: PartialLocaleType = {
|
|||||||
Edit: "সম্পাদনা করুন",
|
Edit: "সম্পাদনা করুন",
|
||||||
RefreshTitle: "শিরোনাম রিফ্রেশ করুন",
|
RefreshTitle: "শিরোনাম রিফ্রেশ করুন",
|
||||||
RefreshToast: "শিরোনাম রিফ্রেশ অনুরোধ পাঠানো হয়েছে",
|
RefreshToast: "শিরোনাম রিফ্রেশ অনুরোধ পাঠানো হয়েছে",
|
||||||
|
Continue: "চালিয়ে যান",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "নতুন চ্যাট",
|
new: "নতুন চ্যাট",
|
||||||
|
@ -45,6 +45,7 @@ const cn = {
|
|||||||
FullScreen: "全屏",
|
FullScreen: "全屏",
|
||||||
RefreshTitle: "刷新标题",
|
RefreshTitle: "刷新标题",
|
||||||
RefreshToast: "已发送刷新标题请求",
|
RefreshToast: "已发送刷新标题请求",
|
||||||
|
Continue: "继续",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "新建聊天",
|
new: "新建聊天",
|
||||||
|
@ -45,6 +45,7 @@ const cs: PartialLocaleType = {
|
|||||||
Edit: "Upravit",
|
Edit: "Upravit",
|
||||||
RefreshTitle: "Obnovit název",
|
RefreshTitle: "Obnovit název",
|
||||||
RefreshToast: "Požadavek na obnovení názvu byl odeslán",
|
RefreshToast: "Požadavek na obnovení názvu byl odeslán",
|
||||||
|
Continue: "Pokračovat",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Nová konverzace",
|
new: "Nová konverzace",
|
||||||
|
@ -45,6 +45,7 @@ const de: PartialLocaleType = {
|
|||||||
Edit: "Bearbeiten",
|
Edit: "Bearbeiten",
|
||||||
RefreshTitle: "Titel aktualisieren",
|
RefreshTitle: "Titel aktualisieren",
|
||||||
RefreshToast: "Anfrage zur Titelaktualisierung gesendet",
|
RefreshToast: "Anfrage zur Titelaktualisierung gesendet",
|
||||||
|
Continue: "Fortsetzen",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Neues Gespräch",
|
new: "Neues Gespräch",
|
||||||
|
@ -47,6 +47,7 @@ const en: LocaleType = {
|
|||||||
FullScreen: "FullScreen",
|
FullScreen: "FullScreen",
|
||||||
RefreshTitle: "Refresh Title",
|
RefreshTitle: "Refresh Title",
|
||||||
RefreshToast: "Title refresh request sent",
|
RefreshToast: "Title refresh request sent",
|
||||||
|
Continue: "Continue",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Start a new chat",
|
new: "Start a new chat",
|
||||||
|
@ -46,6 +46,7 @@ const es: PartialLocaleType = {
|
|||||||
Edit: "Editar",
|
Edit: "Editar",
|
||||||
RefreshTitle: "Actualizar título",
|
RefreshTitle: "Actualizar título",
|
||||||
RefreshToast: "Se ha enviado la solicitud de actualización del título",
|
RefreshToast: "Se ha enviado la solicitud de actualización del título",
|
||||||
|
Continue: "Continuar",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Nueva conversación",
|
new: "Nueva conversación",
|
||||||
|
@ -45,6 +45,7 @@ const fr: PartialLocaleType = {
|
|||||||
Edit: "Modifier",
|
Edit: "Modifier",
|
||||||
RefreshTitle: "Actualiser le titre",
|
RefreshTitle: "Actualiser le titre",
|
||||||
RefreshToast: "Demande d'actualisation du titre envoyée",
|
RefreshToast: "Demande d'actualisation du titre envoyée",
|
||||||
|
Continue: "Continuer",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Nouvelle discussion",
|
new: "Nouvelle discussion",
|
||||||
|
@ -45,6 +45,7 @@ const id: PartialLocaleType = {
|
|||||||
Edit: "Edit",
|
Edit: "Edit",
|
||||||
RefreshTitle: "Segarkan Judul",
|
RefreshTitle: "Segarkan Judul",
|
||||||
RefreshToast: "Permintaan penyegaran judul telah dikirim",
|
RefreshToast: "Permintaan penyegaran judul telah dikirim",
|
||||||
|
Continue: "Lanjutkan",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Obrolan Baru",
|
new: "Obrolan Baru",
|
||||||
|
@ -45,6 +45,7 @@ const it: PartialLocaleType = {
|
|||||||
Edit: "Modifica",
|
Edit: "Modifica",
|
||||||
RefreshTitle: "Aggiorna titolo",
|
RefreshTitle: "Aggiorna titolo",
|
||||||
RefreshToast: "Richiesta di aggiornamento del titolo inviata",
|
RefreshToast: "Richiesta di aggiornamento del titolo inviata",
|
||||||
|
Continue: "Continua",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Nuova chat",
|
new: "Nuova chat",
|
||||||
|
@ -45,6 +45,7 @@ const jp: PartialLocaleType = {
|
|||||||
Edit: "編集",
|
Edit: "編集",
|
||||||
RefreshTitle: "タイトルを更新",
|
RefreshTitle: "タイトルを更新",
|
||||||
RefreshToast: "タイトル更新リクエストが送信されました",
|
RefreshToast: "タイトル更新リクエストが送信されました",
|
||||||
|
Continue: "続ける",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "新しいチャット",
|
new: "新しいチャット",
|
||||||
|
@ -45,6 +45,7 @@ const ko: PartialLocaleType = {
|
|||||||
Edit: "편집",
|
Edit: "편집",
|
||||||
RefreshTitle: "제목 새로고침",
|
RefreshTitle: "제목 새로고침",
|
||||||
RefreshToast: "제목 새로고침 요청이 전송되었습니다",
|
RefreshToast: "제목 새로고침 요청이 전송되었습니다",
|
||||||
|
Continue: "계속하다",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "새 채팅",
|
new: "새 채팅",
|
||||||
|
@ -46,6 +46,7 @@ const no: PartialLocaleType = {
|
|||||||
Edit: "Rediger",
|
Edit: "Rediger",
|
||||||
RefreshTitle: "Oppdater tittel",
|
RefreshTitle: "Oppdater tittel",
|
||||||
RefreshToast: "Forespørsel om titteloppdatering sendt",
|
RefreshToast: "Forespørsel om titteloppdatering sendt",
|
||||||
|
Continue: "Fortsette",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Ny samtale",
|
new: "Ny samtale",
|
||||||
|
@ -45,6 +45,7 @@ const pt: PartialLocaleType = {
|
|||||||
Edit: "Editar",
|
Edit: "Editar",
|
||||||
RefreshTitle: "Atualizar Título",
|
RefreshTitle: "Atualizar Título",
|
||||||
RefreshToast: "Solicitação de atualização de título enviada",
|
RefreshToast: "Solicitação de atualização de título enviada",
|
||||||
|
Continue: "Continuar",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Iniciar um novo chat",
|
new: "Iniciar um novo chat",
|
||||||
|
@ -45,6 +45,7 @@ const ru: PartialLocaleType = {
|
|||||||
Edit: "Редактировать",
|
Edit: "Редактировать",
|
||||||
RefreshTitle: "Обновить заголовок",
|
RefreshTitle: "Обновить заголовок",
|
||||||
RefreshToast: "Запрос на обновление заголовка отправлен",
|
RefreshToast: "Запрос на обновление заголовка отправлен",
|
||||||
|
Continue: "Продолжить",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Новый чат",
|
new: "Новый чат",
|
||||||
|
@ -46,6 +46,7 @@ const sk: PartialLocaleType = {
|
|||||||
Edit: "Upraviť",
|
Edit: "Upraviť",
|
||||||
RefreshTitle: "Obnoviť názov",
|
RefreshTitle: "Obnoviť názov",
|
||||||
RefreshToast: "Požiadavka na obnovenie názvu bola odoslaná",
|
RefreshToast: "Požiadavka na obnovenie názvu bola odoslaná",
|
||||||
|
Continue: "Pokračovať",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Začať nový chat",
|
new: "Začať nový chat",
|
||||||
|
@ -45,6 +45,7 @@ const tr: PartialLocaleType = {
|
|||||||
Edit: "Düzenle",
|
Edit: "Düzenle",
|
||||||
RefreshTitle: "Başlığı Yenile",
|
RefreshTitle: "Başlığı Yenile",
|
||||||
RefreshToast: "Başlık yenileme isteği gönderildi",
|
RefreshToast: "Başlık yenileme isteği gönderildi",
|
||||||
|
Continue: "Devam et",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Yeni sohbet",
|
new: "Yeni sohbet",
|
||||||
|
@ -45,6 +45,7 @@ const tw = {
|
|||||||
Edit: "編輯",
|
Edit: "編輯",
|
||||||
RefreshTitle: "刷新標題",
|
RefreshTitle: "刷新標題",
|
||||||
RefreshToast: "已發送刷新標題請求",
|
RefreshToast: "已發送刷新標題請求",
|
||||||
|
Continue: "繼續",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "新建聊天",
|
new: "新建聊天",
|
||||||
|
@ -45,6 +45,7 @@ const vi: PartialLocaleType = {
|
|||||||
Edit: "Chỉnh sửa",
|
Edit: "Chỉnh sửa",
|
||||||
RefreshTitle: "Làm mới tiêu đề",
|
RefreshTitle: "Làm mới tiêu đề",
|
||||||
RefreshToast: "Đã gửi yêu cầu làm mới tiêu đề",
|
RefreshToast: "Đã gửi yêu cầu làm mới tiêu đề",
|
||||||
|
Continue: "Tiếp tục",
|
||||||
},
|
},
|
||||||
Commands: {
|
Commands: {
|
||||||
new: "Tạo cuộc trò chuyện mới",
|
new: "Tạo cuộc trò chuyện mới",
|
||||||
|
@ -46,6 +46,7 @@ export type ChatMessage = RequestMessage & {
|
|||||||
id: string;
|
id: string;
|
||||||
model?: ModelType;
|
model?: ModelType;
|
||||||
tools?: ChatMessageTool[];
|
tools?: ChatMessageTool[];
|
||||||
|
finishedReason?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createMessage(override: Partial<ChatMessage>): ChatMessage {
|
export function createMessage(override: Partial<ChatMessage>): ChatMessage {
|
||||||
@ -373,8 +374,10 @@ export const useChatStore = createPersistStore(
|
|||||||
session.messages = session.messages.concat();
|
session.messages = session.messages.concat();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onFinish(message) {
|
onFinish(message, finishedReason) {
|
||||||
botMessage.streaming = false;
|
botMessage.streaming = false;
|
||||||
|
if (finishedReason !== null && finishedReason !== undefined)
|
||||||
|
botMessage.finishedReason = finishedReason;
|
||||||
if (message) {
|
if (message) {
|
||||||
botMessage.content = message;
|
botMessage.content = message;
|
||||||
get().onNewMessage(botMessage);
|
get().onNewMessage(botMessage);
|
||||||
@ -429,6 +432,94 @@ export const useChatStore = createPersistStore(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async onContinueBotMessage(messageID: string) {
|
||||||
|
const session = get().currentSession();
|
||||||
|
const modelConfig = session.mask.modelConfig;
|
||||||
|
|
||||||
|
// get recent messages
|
||||||
|
const recentMessages = get().getMessagesWithMemory(messageID);
|
||||||
|
const messageIndex = get().currentSession().messages.length + 1;
|
||||||
|
|
||||||
|
const botMessage = session.messages.find((v) => v.id === messageID);
|
||||||
|
|
||||||
|
if (!botMessage) {
|
||||||
|
console.error("[Chat] failed to find bot message");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseContent = botMessage.content;
|
||||||
|
|
||||||
|
const api: ClientApi = getClientApi(modelConfig.providerName);
|
||||||
|
// make request
|
||||||
|
api.llm.chat({
|
||||||
|
messages: recentMessages,
|
||||||
|
config: { ...modelConfig, stream: true },
|
||||||
|
onUpdate(message) {
|
||||||
|
botMessage.streaming = true;
|
||||||
|
if (message) {
|
||||||
|
botMessage.content = baseContent + message;
|
||||||
|
}
|
||||||
|
get().updateCurrentSession((session) => {
|
||||||
|
session.messages = session.messages.concat();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onFinish(message, finishedReason) {
|
||||||
|
botMessage.streaming = false;
|
||||||
|
if (finishedReason !== null && finishedReason !== undefined)
|
||||||
|
botMessage.finishedReason = finishedReason;
|
||||||
|
if (message) {
|
||||||
|
botMessage.content = baseContent + message;
|
||||||
|
get().onNewMessage(botMessage);
|
||||||
|
}
|
||||||
|
ChatControllerPool.remove(session.id, botMessage.id);
|
||||||
|
},
|
||||||
|
onBeforeTool(tool: ChatMessageTool) {
|
||||||
|
(botMessage.tools = botMessage?.tools || []).push(tool);
|
||||||
|
get().updateCurrentSession((session) => {
|
||||||
|
session.messages = session.messages.concat();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onAfterTool(tool: ChatMessageTool) {
|
||||||
|
botMessage?.tools?.forEach((t, i, tools) => {
|
||||||
|
if (tool.id == t.id) {
|
||||||
|
tools[i] = { ...tool };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
get().updateCurrentSession((session) => {
|
||||||
|
session.messages = session.messages.concat();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError(error) {
|
||||||
|
const isAborted = error.message?.includes?.("aborted");
|
||||||
|
botMessage.content +=
|
||||||
|
"\n\n" +
|
||||||
|
prettyObject({
|
||||||
|
error: true,
|
||||||
|
message: error.message,
|
||||||
|
});
|
||||||
|
botMessage.streaming = false;
|
||||||
|
botMessage.isError = !isAborted;
|
||||||
|
get().updateCurrentSession((session) => {
|
||||||
|
session.messages = session.messages.concat();
|
||||||
|
});
|
||||||
|
ChatControllerPool.remove(
|
||||||
|
session.id,
|
||||||
|
botMessage.id ?? messageIndex,
|
||||||
|
);
|
||||||
|
|
||||||
|
console.error("[Chat] failed ", error);
|
||||||
|
},
|
||||||
|
onController(controller) {
|
||||||
|
// collect controller for stop/retry
|
||||||
|
ChatControllerPool.addController(
|
||||||
|
session.id,
|
||||||
|
botMessage.id ?? messageIndex,
|
||||||
|
controller,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
getMemoryPrompt() {
|
getMemoryPrompt() {
|
||||||
const session = get().currentSession();
|
const session = get().currentSession();
|
||||||
|
|
||||||
@ -441,12 +532,17 @@ export const useChatStore = createPersistStore(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getMessagesWithMemory() {
|
getMessagesWithMemory(messageID?: string) {
|
||||||
const session = get().currentSession();
|
const session = get().currentSession();
|
||||||
const modelConfig = session.mask.modelConfig;
|
const modelConfig = session.mask.modelConfig;
|
||||||
const clearContextIndex = session.clearContextIndex ?? 0;
|
const clearContextIndex = session.clearContextIndex ?? 0;
|
||||||
const messages = session.messages.slice();
|
const messages = session.messages.slice();
|
||||||
const totalMessageCount = session.messages.length;
|
let messageIdx = session.messages.findIndex((v) => v.id === messageID);
|
||||||
|
if (messageIdx === -1) messageIdx = session.messages.length;
|
||||||
|
const totalMessageCount = Math.min(
|
||||||
|
messageIdx + 1,
|
||||||
|
session.messages.length,
|
||||||
|
);
|
||||||
|
|
||||||
// in-context prompts
|
// in-context prompts
|
||||||
const contextPrompts = session.mask.context.slice();
|
const contextPrompts = session.mask.context.slice();
|
||||||
|
@ -3,7 +3,7 @@ import {
|
|||||||
UPLOAD_URL,
|
UPLOAD_URL,
|
||||||
REQUEST_TIMEOUT_MS,
|
REQUEST_TIMEOUT_MS,
|
||||||
} from "@/app/constant";
|
} from "@/app/constant";
|
||||||
import { RequestMessage } from "@/app/client/api";
|
import { ChatOptions, RequestMessage } from "@/app/client/api";
|
||||||
import Locale from "@/app/locales";
|
import Locale from "@/app/locales";
|
||||||
import {
|
import {
|
||||||
EventStreamContentType,
|
EventStreamContentType,
|
||||||
@ -160,17 +160,21 @@ export function stream(
|
|||||||
tools: any[],
|
tools: any[],
|
||||||
funcs: Record<string, Function>,
|
funcs: Record<string, Function>,
|
||||||
controller: AbortController,
|
controller: AbortController,
|
||||||
parseSSE: (text: string, runTools: any[]) => string | undefined,
|
parseSSE: (
|
||||||
|
text: string,
|
||||||
|
runTools: any[],
|
||||||
|
) => { delta?: string; finishReason?: string },
|
||||||
processToolMessage: (
|
processToolMessage: (
|
||||||
requestPayload: any,
|
requestPayload: any,
|
||||||
toolCallMessage: any,
|
toolCallMessage: any,
|
||||||
toolCallResult: any[],
|
toolCallResult: any[],
|
||||||
) => void,
|
) => void,
|
||||||
options: any,
|
options: ChatOptions,
|
||||||
) {
|
) {
|
||||||
let responseText = "";
|
let responseText = "";
|
||||||
let remainText = "";
|
let remainText = "";
|
||||||
let finished = false;
|
let finished = false;
|
||||||
|
let finishedReason: string | undefined;
|
||||||
let running = false;
|
let running = false;
|
||||||
let runTools: any[] = [];
|
let runTools: any[] = [];
|
||||||
|
|
||||||
@ -254,14 +258,13 @@ export function stream(
|
|||||||
chatApi(chatPath, headers, requestPayload, tools); // call fetchEventSource
|
chatApi(chatPath, headers, requestPayload, tools); // call fetchEventSource
|
||||||
}, 60);
|
}, 60);
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (running) {
|
if (running) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.debug("[ChatAPI] end");
|
console.debug("[ChatAPI] end");
|
||||||
finished = true;
|
finished = true;
|
||||||
options.onFinish(responseText + remainText);
|
options.onFinish(responseText + remainText, finishedReason);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -333,7 +336,11 @@ export function stream(
|
|||||||
try {
|
try {
|
||||||
const chunk = parseSSE(msg.data, runTools);
|
const chunk = parseSSE(msg.data, runTools);
|
||||||
if (chunk) {
|
if (chunk) {
|
||||||
remainText += chunk;
|
if (typeof chunk === "string") remainText += chunk;
|
||||||
|
else {
|
||||||
|
if (chunk.delta) remainText += chunk.delta;
|
||||||
|
finishedReason = chunk.finishReason;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[Request] parse error", text, msg, e);
|
console.error("[Request] parse error", text, msg, e);
|
||||||
|
Loading…
Reference in New Issue
Block a user