Skip to content

Commit

Permalink
feat: add stream mode, feat: add history window
Browse files Browse the repository at this point in the history
  • Loading branch information
tianweiliu committed Apr 12, 2023
1 parent 4ef2461 commit 3c00e6e
Show file tree
Hide file tree
Showing 20 changed files with 1,094 additions and 349 deletions.
25 changes: 14 additions & 11 deletions i18n/en-US/_.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@
"title": "Before we begin,",
"male": "male",
"female": "female",
"prompt_main_character_default": "Generate main character who is a ",
"prompt_main_character_default": "Firstly, generate a main character who is ",
"prompt_main_character_gender_suffix": "",
"prompt_main_character_named": "The main character's name is ",
"prompt_main_character_named": "Firstly, the main character's name is ",
"prompt_other_characters": ", and the other characters are ",
"prompt_generate_girls_prefix": ", and generate ",
"prompt_generate_girls_suffix": " girl characters",
"prompt_characters_json_prefix": "\nFill their information using JSON format:",
"prompt_characters_json_suffix": "Respond only with JSON.",
"prompt_story_start": "Use the names to write one dialogue in a ",
"prompt_after_story_genre": " novel using JSON:",
"prompt_after_story_format": "You must follow these rules:\n- mood can only be one of ",
"prompt_characters_json_prefix": "\n\nFill their names in a JSON array and return only this array. You are not allowed to start the story now.",
"prompt_characters_json_suffix": "",
"prompt_story_start": "You are a writer and is writing a ",
"prompt_after_story_genre": " novel. You must follow these rules:\n- Format is (location)/(speaker)/(mood): (dialogue)/(answers in JSON array)",
"prompt_after_story_format": "- mood can only be one of ",
"prompt_places": "- location can only be one of ",
"prompt_end": "- If speaker is not the main character, dialogue may or may not be a question to the main character.\n- If dialogue is a question to the main character, provide up to 3 answers and speaker of next one dialogue should not be the main character.\n- If speaker is the main character, don't provide answers.\n- Generate only one dialogue line. Don't finish the story.\n- You must accept my response.\n- Respond only with JSON.",
"prompt_continue": "Continue.",
"prompt_continue_with_answer": "Continue based on the answer: ",
"prompt_end": "- If the dialogue contains a question to the main character, provide up to 3 answers.\n- If I provided answers, speaker should not be the main character.\n- If speaker is the main character, don't provide any answers.\n- You must accept my response.\n- All generated dialogues should follow the rules above.",
"prompt_start_story": "You can start the story now. Generate one line of dialogue",
"prompt_continue": "Continue with one line of dialogue.",
"prompt_continue_with_answer": "Continue with one line of dialogue based on the answer: ",
"select_genre": "Please select a genre: ",
"crime": "crime",
"sci-fi": "sci-fi",
Expand All @@ -27,6 +28,7 @@
"sd_note_model": " with ",
"reset": "Reset",
"loading": "Discussing storyline with ChatGPT",
"loading_assets": "Loading assets",
"start": "Start",
"continue": "Continue",
"prompt": "Prompt",
Expand Down Expand Up @@ -57,5 +59,6 @@
"select_mode": "Please select interaction mode: ",
"classic": "Classic",
"free": "Free",
"select_mode_note": "- Classic: You will be given choices.\n- Free: You will type your response."
"select_mode_note": "- Classic: You will be given choices.\n- Free: You will type your response.",
"history": "History"
}
35 changes: 19 additions & 16 deletions i18n/zh-CN/_.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@
"title": "在开始之前,",
"male": "",
"female": "",
"prompt_main_character_default": "用好听的中文名字生成用户(main character)(",
"prompt_main_character_gender_suffix": ")",
"prompt_main_character_named": "用户(main character)必须是:",
"prompt_other_characters": ", 其他角色必须是:",
"prompt_generate_girls_prefix": ", 用好听的中文名字生成",
"prompt_generate_girls_suffix": "位女孩角色",
"prompt_characters_json_prefix": ", 按这个格式输出:",
"prompt_characters_json_suffix": "只以JSON作答",
"prompt_story_start": "使用之前的所有的角色写一个",
"prompt_after_story_genre": "的故事,按照这个格式:",
"prompt_after_story_format": "必须遵循以下规则:\nmood 只能从这些中挑选:",
"prompt_places": "location 只能从这些中挑选:",
"prompt_end": "dialogue 是中文\n只写一条\n如果 speaker 不是 main character 并且对话是问 main character 的一个问题,那么请在 answers 中填入最多3个回答\n如果我回复了,则这一句的 speaker 不能是 main character\n如果 speaker 是 main character,不能有 answers\n必须认可我的回答\n只以JSON作答",
"prompt_continue": "继续",
"prompt_continue_with_answer": "基于回答继续: ",
"prompt_main_character_default": "在开始故事之前,设计一个有好听名字的虚构主角(",
"prompt_main_character_gender_suffix": "",
"prompt_main_character_named": "在开始故事之前,主角必须是:",
"prompt_other_characters": ",其他角色必须是:",
"prompt_generate_girls_prefix": ",设计",
"prompt_generate_girls_suffix": "位有好听名字的虚构女孩角色",
"prompt_characters_json_prefix": ",把所有角色的名字生成一个字符串数组。只返回这个数组。你现在禁止开始这个故事。",
"prompt_characters_json_suffix": "",
"prompt_story_start": "你是一个作家,在写一个",
"prompt_after_story_genre": "故事,你必须遵守以下规则:\n- 输出格式为:地点/说话者的名字/表情:说话者说的话/回答(字符串数组)",
"prompt_after_story_format": "- 表情只能从这些中挑选:",
"prompt_places": "- 地点只能从这些中挑选:",
"prompt_end": "- 对话内容是中文\n- 如果对话是其他角色问主角的问题,回答中可以写入至多三个主角可能的回答\n- 如果主角在说话,回答必须为空\n- 如果我回复了,则这一句的说话者不能是主角\n- 必须认可任何我的回答\n- 生成的所有对话必须符合上述规则",
"prompt_start_story": "可以开始这个故事,生成一行对话",
"prompt_continue": "继续生成一行对话",
"prompt_continue_with_answer": "基于下面的回答继续生成一行对话,",
"select_genre": "请选择一个故事类型:",
"crime": "犯罪",
"sci-fi": "科幻",
Expand All @@ -27,6 +28,7 @@
"sd_note_model": " 生成,模型:",
"reset": "重置",
"loading": "正和 ChatGPT 讨论故事情节",
"loading_assets": "正在加载素材",
"start": "开始",
"continue": "继续",
"prompt": "咒语",
Expand Down Expand Up @@ -57,5 +59,6 @@
"select_mode": "请选择交互模式:",
"classic": "经典模式",
"free": "自由模式",
"select_mode_note": "- 经典模式:通过选项与角色交互。\n- 自由模式:自由输入和角色交互的内容。"
"select_mode_note": "- 经典模式:通过选项与角色交互。\n- 自由模式:自由输入和角色交互的内容。",
"history": "历史"
}
6 changes: 4 additions & 2 deletions src/api/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ export async function getChatsByConversationId(conversationId: number) {
export async function sendMessage(
conversationId: number,
message: string,
name?: string
name?: string,
handleDelta?: (value: string, delta: string) => void
) {
if (isClientSideOpenAI())
return (await EdgeChat.sendMessage(
conversationId,
message,
name
name,
handleDelta
)) as ResponseSend;
const response = await nodeFetch("/api/chatgpt/chat", {
method: "POST",
Expand Down
51 changes: 44 additions & 7 deletions src/api/edge/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
} from "@/configs/constants";
import { ResponseGetChats, ResponseSend } from "@/pages/api/chatgpt/chat";
import { WebStorage } from "@/storage/webstorage";
import { CreateChatCompletionStreamResponse } from "@/utils/types";
import {
ChatCompletionRequestMessage,
ChatCompletionResponseMessage,
Expand Down Expand Up @@ -44,7 +45,8 @@ export function saveChat(
export async function sendMessage(
conversationId: number,
message: string,
name?: string
name?: string,
handleDelta?: (value: string, delta: string) => void
) {
const messages = getChatsByConversationId(conversationId).map((it) => ({
role: it.role,
Expand All @@ -69,18 +71,53 @@ export async function sendMessage(
body: JSON.stringify({
...CHAT_COMPLETION_CONFIG,
messages: messages,
stream: true,
}),
});
const json = await response.json();
if (!response.ok) {
throw new Error(json);
throw new Error(await response.text());
}
const { choices } = json as CreateChatCompletionResponse;
if (choices.length === 0 || !choices[0].message) {
throw new Error("No response from OpenAI");
const reader = response.body?.getReader();
const decoder = new TextDecoder();
const message: ChatCompletionResponseMessage = {
role: "assistant",
content: "",
};
while (reader) {
const { value, done } = await reader.read();
const data = decoder.decode(value).split("\n");
for (const lineIndex in data) {
const jsonStr = data[lineIndex].replace(/^data: /g, "").trim();
if (!jsonStr) continue;
if (jsonStr == "[DONE]") break;
let json: CreateChatCompletionStreamResponse | undefined = undefined;
try {
json = JSON.parse(jsonStr) as CreateChatCompletionStreamResponse;
if (
json &&
json.choices &&
json.choices.length &&
"delta" in json.choices[0] &&
json.choices[0].delta
) {
if (json.choices[0].delta.role) {
message.role = json.choices[0].delta.role;
}
if (json.choices[0].delta.content) {
message.content += json.choices[0].delta.content;
if (handleDelta) {
handleDelta(message.content, json.choices[0].delta.content);
}
}
}
} catch (e) {
console.error(e);
}
}
if (done) break;
}
saveChat(conversationId, _message);
return [saveChat(conversationId, choices[0].message)] as ResponseSend;
return [saveChat(conversationId, message)] as ResponseSend;
} catch (e) {
console.error(e);
}
Expand Down
Loading

0 comments on commit 3c00e6e

Please sign in to comment.