This commit is contained in:
2023-10-25 11:34:02 +08:00
parent 717c76f4dd
commit 2e8e8e008c
7 changed files with 254 additions and 71 deletions

View File

@@ -5,6 +5,7 @@ import { calculate_token_length, Message } from "./chatgpt";
import getDefaultParams from "./getDefaultParam"; import getDefaultParams from "./getDefaultParam";
import ChatBOX from "./chatbox"; import ChatBOX from "./chatbox";
import models from "./models"; import models from "./models";
import { Tr, langCodeContext, LANG_OPTIONS } from "./translate";
import CHATGPT_API_WEB_VERSION from "./CHATGPT_API_WEB_VERSION"; import CHATGPT_API_WEB_VERSION from "./CHATGPT_API_WEB_VERSION";
@@ -245,7 +246,7 @@ export function App() {
className="bg-violet-300 p-1 rounded hover:bg-violet-400" className="bg-violet-300 p-1 rounded hover:bg-violet-400"
onClick={handleNewChatStore} onClick={handleNewChatStore}
> >
NEW {Tr("NEW")}
</button> </button>
<ul> <ul>
{allChatStoreIndexes {allChatStoreIndexes
@@ -303,7 +304,7 @@ export function App() {
setAllChatStoreIndexes([...newAllChatStoreIndexes]); setAllChatStoreIndexes([...newAllChatStoreIndexes]);
}} }}
> >
DEL {Tr("DEL")}
</button> </button>
</div> </div>
<ChatBOX <ChatBOX

View File

@@ -1,3 +1,4 @@
import { Tr, langCodeContext, LANG_OPTIONS } from "./translate";
import structuredClone from "@ungap/structured-clone"; import structuredClone from "@ungap/structured-clone";
import { createRef } from "preact"; import { createRef } from "preact";
import { StateUpdater, useEffect, useState } from "preact/hooks"; import { StateUpdater, useEffect, useState } from "preact/hooks";
@@ -281,7 +282,7 @@ export default function ChatBOX(props: {
: chatStore.systemMessageContent} : chatStore.systemMessageContent}
</button>{" "} </button>{" "}
<button className="underline"> <button className="underline">
{chatStore.streamMode ? "STREAM" : "FETCH"} {chatStore.streamMode ? Tr("STREAM") : Tr("FETCH")}
</button> </button>
</div> </div>
<div className="text-xs"> <div className="text-xs">
@@ -293,14 +294,14 @@ export default function ChatBOX(props: {
</span> </span>
</span>{" "} </span>{" "}
<span> <span>
Cut:{" "} {Tr("Cut")}:{" "}
<span className="underline"> <span className="underline">
{chatStore.postBeginIndex}/ {chatStore.postBeginIndex}/
{chatStore.history.filter(({ hide }) => !hide).length} {chatStore.history.filter(({ hide }) => !hide).length}
</span>{" "} </span>{" "}
</span>{" "} </span>{" "}
<span> <span>
Cost:{" "} {Tr("Cost")}:{" "}
<span className="underline">${chatStore.cost.toFixed(4)}</span> <span className="underline">${chatStore.cost.toFixed(4)}</span>
</span> </span>
</div> </div>
@@ -308,12 +309,12 @@ export default function ChatBOX(props: {
<div className="grow overflow-scroll"> <div className="grow overflow-scroll">
{!chatStore.apiKey && ( {!chatStore.apiKey && (
<p className="opacity-60 p-6 rounded bg-white my-3 text-left dark:text-black"> <p className="opacity-60 p-6 rounded bg-white my-3 text-left dark:text-black">
(OPENAI) API KEY {Tr("Please click above to set")} (OpenAI) API KEY
</p> </p>
)} )}
{!chatStore.apiEndpoint && ( {!chatStore.apiEndpoint && (
<p className="opacity-60 p-6 rounded bg-white my-3 text-left dark:text-black"> <p className="opacity-60 p-6 rounded bg-white my-3 text-left dark:text-black">
API Endpoint {Tr("Please click above to set")} API Endpoint
</p> </p>
)} )}
{templateAPIs.length > 0 && {templateAPIs.length > 0 &&
@@ -321,7 +322,7 @@ export default function ChatBOX(props: {
!chatStore.apiEndpoint || !chatStore.apiEndpoint ||
!chatStore.apiKey) && ( !chatStore.apiKey) && (
<p className="break-all opacity-80 p-3 rounded bg-white my-3 text-left dark:text-black"> <p className="break-all opacity-80 p-3 rounded bg-white my-3 text-left dark:text-black">
<h2> API </h2> <h2>{Tr("Saved API templates")}</h2>
<hr className="my-2" /> <hr className="my-2" />
<div className="flex flex-wrap"> <div className="flex flex-wrap">
{templateAPIs.map((t, index) => ( {templateAPIs.map((t, index) => (
@@ -377,7 +378,7 @@ export default function ChatBOX(props: {
{templates.length > 0 && {templates.length > 0 &&
chatStore.history.filter((msg) => !msg.example).length == 0 && ( chatStore.history.filter((msg) => !msg.example).length == 0 && (
<p className="break-all opacity-80 p-3 rounded bg-white my-3 text-left dark:text-black"> <p className="break-all opacity-80 p-3 rounded bg-white my-3 text-left dark:text-black">
<h2>Templates</h2> <h2>{Tr("Saved prompt templates")}</h2>
<hr className="my-2" /> <hr className="my-2" />
<div className="flex flex-wrap"> <div className="flex flex-wrap">
{templates.map((t, index) => ( {templates.map((t, index) => (
@@ -439,21 +440,15 @@ export default function ChatBOX(props: {
)} )}
{chatStore.history.length === 0 && ( {chatStore.history.length === 0 && (
<p className="break-all opacity-60 p-6 rounded bg-white my-3 text-left dark:text-black"> <p className="break-all opacity-60 p-6 rounded bg-white my-3 text-left dark:text-black">
{Tr("No chat history here")}
<br /> <br />{Tr("Model")}: {chatStore.model}
Model: {chatStore.model} <br />{Tr("Click above to change the settings of this chat")}
<br /> <br />{Tr("Click the conor to create a new chat")}
<br />
<br /> {Tr(
NEW "All chat history and settings are stored in the local browser"
<br /> )}
使 ChatGPT API <br />{Tr("Documents and source code are avaliable here")}:{" "}
API
<br />
<br />
:{" "}
<a <a
className="underline" className="underline"
href="https://github.com/heimoshuiyu/chatgpt-api-web" href="https://github.com/heimoshuiyu/chatgpt-api-web"
@@ -473,7 +468,7 @@ export default function ChatBOX(props: {
))} ))}
{showGenerating && ( {showGenerating && (
<p className="p-2 my-2 animate-pulse dark:text-white message-content"> <p className="p-2 my-2 animate-pulse dark:text-white message-content">
{generatingMessage || "生成中,最长可能需要一分钟,请保持网络稳定"} {generatingMessage || Tr("Generating...")}
... ...
</p> </p>
)} )}
@@ -495,7 +490,7 @@ export default function ChatBOX(props: {
await complete(); await complete();
}} }}
> >
Re-Generate {Tr("Re-Generate")}
</button> </button>
)} )}
{chatStore.develop_mode && chatStore.history.length > 0 && ( {chatStore.develop_mode && chatStore.history.length > 0 && (
@@ -506,25 +501,29 @@ export default function ChatBOX(props: {
await complete(); await complete();
}} }}
> >
Completion {Tr("Completion")}
</button> </button>
)} )}
</p> </p>
<p className="p-2 my-2 text-center opacity-50 dark:text-white"> <p className="p-2 my-2 text-center opacity-50 dark:text-white">
{chatStore.responseModelName && ( {chatStore.responseModelName && (
<>Generated by {chatStore.responseModelName}</> <>
{Tr("Generated by")} {chatStore.responseModelName}
</>
)} )}
{chatStore.postBeginIndex !== 0 && ( {chatStore.postBeginIndex !== 0 && (
<> <>
<br /> <br />
{chatStore.postBeginIndex} {Tr("Info: chat history is too long, forget messages")}:{" "}
{chatStore.postBeginIndex}
</> </>
)} )}
</p> </p>
{chatStore.chatgpt_api_web_version < "v1.3.0" && ( {chatStore.chatgpt_api_web_version < "v1.3.0" && (
<p className="p-2 my-2 text-center dark:text-white"> <p className="p-2 my-2 text-center dark:text-white">
<br /> <br />
{chatStore.chatgpt_api_web_version} {Tr("Warning: current chatStore version")}:{" "}
{chatStore.chatgpt_api_web_version} {"< v1.3.0"}
<br /> <br />
v1.3.0 v1.3.0
使 使
@@ -535,8 +534,8 @@ export default function ChatBOX(props: {
{chatStore.chatgpt_api_web_version < "v1.4.0" && ( {chatStore.chatgpt_api_web_version < "v1.4.0" && (
<p className="p-2 my-2 text-center dark:text-white"> <p className="p-2 my-2 text-center dark:text-white">
<br /> <br />
{chatStore.chatgpt_api_web_version} {"< v1.4.0"} {Tr("Warning: current chatStore version")}:{" "}
{chatStore.chatgpt_api_web_version} {"< v1.4.0"}
<br /> <br />
v1.4.0 使 v1.4.0 使
<br /> <br />
@@ -546,7 +545,9 @@ export default function ChatBOX(props: {
{chatStore.chatgpt_api_web_version < "v1.6.0" && ( {chatStore.chatgpt_api_web_version < "v1.6.0" && (
<p className="p-2 my-2 text-center dark:text-white"> <p className="p-2 my-2 text-center dark:text-white">
<br /> <br />
{chatStore.chatgpt_api_web_version} {"< v1.6.0"} {chatStore.chatgpt_api_web_version}
{Tr("Warning: current chatStore version")}:{" "}
{chatStore.chatgpt_api_web_version} {"< v1.6.0"}
<br /> <br />
v1.6.0 apiKey apiEndpoint v1.6.0 apiKey apiEndpoint
@@ -564,7 +565,7 @@ export default function ChatBOX(props: {
await complete(); await complete();
}} }}
> >
Retry {Tr("Retry")}
</button> </button>
</p> </p>
)} )}
@@ -594,7 +595,7 @@ export default function ChatBOX(props: {
send(inputMsg); send(inputMsg);
}} }}
> >
Send {Tr("Send")}
</button> </button>
{chatStore.whisper_api && {chatStore.whisper_api &&
(chatStore.whisper_key || chatStore.apiKey) && ( (chatStore.whisper_key || chatStore.apiKey) && (
@@ -721,7 +722,7 @@ export default function ChatBOX(props: {
setChatStore({ ...chatStore }); setChatStore({ ...chatStore });
}} }}
> >
Assistant {Tr("Assistant")}
</button> </button>
)} )}
{chatStore.develop_mode && ( {chatStore.develop_mode && (
@@ -741,7 +742,7 @@ export default function ChatBOX(props: {
setChatStore({ ...chatStore }); setChatStore({ ...chatStore });
}} }}
> >
User {Tr("User")}
</button> </button>
)} )}
</div> </div>

View File

@@ -1,4 +1,16 @@
import { render } from 'preact' import { render } from "preact";
import { App } from './app' import { App } from "./app";
import { useState } from "preact/hooks";
import { Tr, langCodeContext, LANG_OPTIONS } from "./translate";
render(<App />, document.getElementById('app') as HTMLElement) function Base() {
const [langCode, setLangCode] = useState("en-US");
return (
/* @ts-ignore */
<langCodeContext.Provider value={{ langCode, setLangCode }}>
<App />
</langCodeContext.Provider>
);
}
render(<Base />, document.getElementById("app") as HTMLElement);

View File

@@ -1,3 +1,4 @@
import { Tr, langCodeContext, LANG_OPTIONS } from "./translate";
import { useState, useEffect, StateUpdater } from "preact/hooks"; import { useState, useEffect, StateUpdater } from "preact/hooks";
import { ChatStore, ChatStoreMessage } from "./app"; import { ChatStore, ChatStoreMessage } from "./app";
import { calculate_token_length } from "./chatgpt"; import { calculate_token_length } from "./chatgpt";
@@ -54,7 +55,7 @@ function EditMessage(props: EditMessageProps) {
setShowEdit(false); setShowEdit(false);
}} }}
> >
Close {Tr("Close")}
</button> </button>
</div> </div>
</div> </div>
@@ -101,7 +102,7 @@ export default function Message(props: Props) {
"bg-purple-400 p-1 rounded shadow-md absolute z-20 left-1/2 top-3/4 transform -translate-x-1/2 -translate-y-1/2" "bg-purple-400 p-1 rounded shadow-md absolute z-20 left-1/2 top-3/4 transform -translate-x-1/2 -translate-y-1/2"
} }
> >
Message Copied to clipboard! {Tr("Message copied to clipboard!")}
</span> </span>
); );
@@ -212,13 +213,13 @@ export default function Message(props: Props) {
setChatStore({ ...chatStore }); setChatStore({ ...chatStore });
}} }}
> >
<label className="dark:text-white">example</label> <label className="dark:text-white">{Tr("example")}</label>
<input type="checkbox" checked={chat.example} /> <input type="checkbox" checked={chat.example} />
</span> </span>
<span <span
onClick={(event: any) => setRenderWorkdown(!renderMarkdown)} onClick={(event: any) => setRenderWorkdown(!renderMarkdown)}
> >
<label className="dark:text-white">render</label> <label className="dark:text-white">{Tr("render")}</label>
<input type="checkbox" checked={renderMarkdown} /> <input type="checkbox" checked={renderMarkdown} />
</span> </span>
</div> </div>

View File

@@ -1,8 +1,9 @@
import { createRef } from "preact"; import { createRef } from "preact";
import { StateUpdater, useEffect, useState } from "preact/hooks"; import { StateUpdater, useContext, useEffect, useState } from "preact/hooks";
import { ChatStore, TemplateAPI, clearTotalCost, getTotalCost } from "./app"; import { ChatStore, TemplateAPI, clearTotalCost, getTotalCost } from "./app";
import models from "./models"; import models from "./models";
import { TemplateChatStore } from "./chatbox"; import { TemplateChatStore } from "./chatbox";
import { tr, Tr, langCodeContext, LANG_OPTIONS } from "./translate";
const Help = (props: { children: any; help: string }) => { const Help = (props: { children: any; help: string }) => {
return ( return (
@@ -95,6 +96,43 @@ const Input = (props: {
</Help> </Help>
); );
}; };
const Slicer = (props: {
chatStore: ChatStore;
setChatStore: (cs: ChatStore) => void;
field: "temperature";
help: string;
}) => {
return (
<Help help={props.help}>
<label className="m-2 p-2">{props.field}</label>
<span>
<input
type="range"
min="0"
max="1"
step="0.01"
value={props.chatStore[props.field]}
onChange={(event: any) => {
const value = parseFloat(event.target.value);
props.chatStore[props.field] = value;
props.setChatStore({ ...props.chatStore });
}}
/>
<input
type="number"
value={props.chatStore[props.field]}
onChange={(event: any) => {
const value = parseFloat(event.target.value);
props.chatStore[props.field] = value;
props.setChatStore({ ...props.chatStore });
}}
/>
</span>
</Help>
);
};
const Number = (props: { const Number = (props: {
chatStore: ChatStore; chatStore: ChatStore;
setChatStore: (cs: ChatStore) => void; setChatStore: (cs: ChatStore) => void;
@@ -103,7 +141,6 @@ const Number = (props: {
| "maxTokens" | "maxTokens"
| "tokenMargin" | "tokenMargin"
| "postBeginIndex" | "postBeginIndex"
| "temperature"
| "top_p" | "top_p"
| "presence_penalty" | "presence_penalty"
| "frequency_penalty"; | "frequency_penalty";
@@ -179,6 +216,8 @@ export default (props: {
const importFileRef = createRef(); const importFileRef = createRef();
const [totalCost, setTotalCost] = useState(getTotalCost()); const [totalCost, setTotalCost] = useState(getTotalCost());
// @ts-ignore
const { langCode, setLangCode } = useContext(langCodeContext);
useEffect(() => { useEffect(() => {
const handleKeyPress = (event: any) => { const handleKeyPress = (event: any) => {
@@ -206,26 +245,38 @@ export default (props: {
}} }}
className="m-2 p-2 bg-white rounded-lg h-fit lg:w-2/3 z-20" className="m-2 p-2 bg-white rounded-lg h-fit lg:w-2/3 z-20"
> >
<h3 className="text-xl text-center">Settings</h3> <h3 className="text-xl text-center">
<span>{Tr("Settings")}</span>
<select>
{Object.keys(LANG_OPTIONS).map((opt) => (
<option
value={opt}
selected={opt === (langCodeContext as any).langCode}
onClick={(event: any) => {
console.log("set lang code", event.target.value);
setLangCode(event.target.value);
}}
>
{LANG_OPTIONS[opt].name}
</option>
))}
</select>
</h3>
<hr /> <hr />
<div className="flex justify-between"> <div className="flex justify-between">
<button <button
className="p-2 m-2 rounded bg-purple-600 text-white" className="p-2 m-2 rounded bg-purple-600 text-white"
onClick={() => { onClick={() => {
navigator.clipboard.writeText(link); navigator.clipboard.writeText(link);
alert(`Copied link: ${link}`); alert(tr(`Copied link:`, langCode) + `${link}`);
}} }}
> >
Copy Link {Tr("Copy Setting Link")}
</button> </button>
<button <button
className="p-2 m-2 rounded bg-rose-600 text-white" className="p-2 m-2 rounded bg-rose-600 text-white"
onClick={() => { onClick={() => {
if ( if (!confirm(tr("Are you sure to clear all history?", langCode)))
!confirm(
`Are you sure to clear all ${props.chatStore.history.length} messages?`
)
)
return; return;
props.chatStore.history = props.chatStore.history.filter( props.chatStore.history = props.chatStore.history.filter(
(msg) => msg.example && !msg.hide (msg) => msg.example && !msg.hide
@@ -234,7 +285,7 @@ export default (props: {
props.setChatStore({ ...props.chatStore }); props.setChatStore({ ...props.chatStore });
}} }}
> >
Clear History {Tr("Clear History")}
</button> </button>
<button <button
className="p-2 m-2 rounded bg-cyan-600 text-white" className="p-2 m-2 rounded bg-cyan-600 text-white"
@@ -242,11 +293,11 @@ export default (props: {
props.setShow(false); props.setShow(false);
}} }}
> >
Close {Tr("Close")}
</button> </button>
</div> </div>
<p className="m-2 p-2"> <p className="m-2 p-2">
Total cost in this session ${props.chatStore.cost.toFixed(4)} {Tr("Total cost in this session")} ${props.chatStore.cost.toFixed(4)}
</p> </p>
<hr /> <hr />
<div className="box"> <div className="box">
@@ -303,7 +354,7 @@ export default (props: {
readOnly={true} readOnly={true}
{...props} {...props}
/> />
<Number field="temperature" help="温度" readOnly={false} {...props} /> <Slicer field="temperature" help="温度" {...props} />
<Number field="top_p" help="top_p" readOnly={false} {...props} /> <Number field="top_p" help="top_p" readOnly={false} {...props} />
<Number <Number
field="presence_penalty" field="presence_penalty"
@@ -329,7 +380,7 @@ export default (props: {
/> />
<div className="flex justify-between"> <div className="flex justify-between">
<p className="m-2 p-2"> <p className="m-2 p-2">
Accumulated cost in all sessions ${totalCost.toFixed(4)} {Tr("Accumulated cost in all sessions")} ${totalCost.toFixed(4)}
</p> </p>
<button <button
className="p-2 m-2 rounded bg-emerald-500" className="p-2 m-2 rounded bg-emerald-500"
@@ -338,7 +389,7 @@ export default (props: {
setTotalCost(getTotalCost()); setTotalCost(getTotalCost());
}} }}
> >
Reset {Tr("Reset")}
</button> </button>
</div> </div>
<p className="flex justify-evenly"> <p className="flex justify-evenly">
@@ -361,14 +412,14 @@ export default (props: {
downloadAnchorNode.remove(); downloadAnchorNode.remove();
}} }}
> >
Export {Tr("Export")}
</button> </button>
<button <button
className="p-2 m-2 rounded bg-amber-500" className="p-2 m-2 rounded bg-amber-500"
onClick={() => { onClick={() => {
const name = prompt("Give this template a name:"); const name = prompt(tr("Give this template a name:", langCode));
if (!name) { if (!name) {
alert("No template name specified"); alert(tr("No template name specified", langCode));
return; return;
} }
const tmp: ChatStore = structuredClone(props.chatStore); const tmp: ChatStore = structuredClone(props.chatStore);
@@ -382,7 +433,7 @@ export default (props: {
props.setTemplates([...props.templates]); props.setTemplates([...props.templates]);
}} }}
> >
As template {Tr("As template")}
</button> </button>
<button <button
className="p-2 m-2 rounded bg-amber-500" className="p-2 m-2 rounded bg-amber-500"
@@ -401,14 +452,17 @@ export default (props: {
props.setTemplateAPIs([...props.templateAPIs]); props.setTemplateAPIs([...props.templateAPIs]);
}} }}
> >
As API Template {Tr("As API Template")}
</button> </button>
<button <button
className="p-2 m-2 rounded bg-amber-500" className="p-2 m-2 rounded bg-amber-500"
onClick={() => { onClick={() => {
if ( if (
!confirm( !confirm(
"This will OVERWRITE the current chat history! Continue?" tr(
"This will OVERWRITE the current chat history! Continue?",
langCode
)
) )
) )
return; return;
@@ -426,14 +480,14 @@ export default (props: {
const file = importFileRef.current.files[0]; const file = importFileRef.current.files[0];
console.log("file to import", file); console.log("file to import", file);
if (!file || file.type !== "application/json") { if (!file || file.type !== "application/json") {
alert("Please select a json file"); alert(tr("Please select a json file", langCode));
return; return;
} }
const reader = new FileReader(); const reader = new FileReader();
reader.onload = () => { reader.onload = () => {
console.log("import content", reader.result); console.log("import content", reader.result);
if (!reader) { if (!reader) {
alert("Empty file"); alert(tr("Empty file", langCode));
return; return;
} }
try { try {
@@ -441,11 +495,16 @@ export default (props: {
reader.result as string reader.result as string
); );
if (!newChatStore.chatgpt_api_web_version) { if (!newChatStore.chatgpt_api_web_version) {
throw "This is not an exported chatgpt-api-web chatstore file. The key 'chatgpt_api_web_version' is missing!"; throw tr(
"This is not an exported chatgpt-api-web chatstore file. The key 'chatgpt_api_web_version' is missing!",
langCode
);
} }
props.setChatStore({ ...newChatStore }); props.setChatStore({ ...newChatStore });
} catch (e) { } catch (e) {
alert(`Import error on parsing json: ${e}`); alert(
tr(`Import error on parsing json:`, langCode) + `${e}`
);
} }
}; };
reader.readAsText(file); reader.readAsText(file);
@@ -453,7 +512,7 @@ export default (props: {
/> />
</p> </p>
<p className="text-center m-2 p-2"> <p className="text-center m-2 p-2">
chatgpt-api-web ChatStore Version{" "} chatgpt-api-web ChatStore {Tr("Version")}{" "}
{props.chatStore.chatgpt_api_web_version} {props.chatStore.chatgpt_api_web_version}
</p> </p>
</div> </div>

51
src/translate/index.tsx Normal file
View File

@@ -0,0 +1,51 @@
import { createContext } from "preact";
import MAP_zh_CN from "./zh_CN";
interface LangOption {
name: string;
langMap: Record<string, string>;
matches: string[];
}
const LANG_OPTIONS: Record<string, LangOption> = {
"en-US": {
name: "English",
langMap: {},
matches: ["en-US", "en"],
},
"zh-CN": {
name: "中文(简体)",
langMap: MAP_zh_CN,
matches: ["zh-CN", "zh"],
},
};
const langCodeContext = createContext("en-US");
function tr(text: string, langCode: "en-US" | "zh-CN") {
const option = LANG_OPTIONS[langCode];
if (option === undefined) {
return text;
}
const langMap = LANG_OPTIONS[langCode].langMap;
const translatedText = langMap[text.toLowerCase()];
if (translatedText === undefined) {
return text;
}
return translatedText;
}
function Tr(text: string) {
return (
<langCodeContext.Consumer>
{/* @ts-ignore */}
{({ langCode }) => {
return tr(text, langCode);
}}
</langCodeContext.Consumer>
);
}
export { tr, Tr, LANG_OPTIONS, langCodeContext };

58
src/translate/zh_CN.ts Normal file
View File

@@ -0,0 +1,58 @@
const LANG_MAP: Record<string, string> = {
settings: "设置",
model: "模型",
"copy setting link": "复制设置链接",
"are you sure to clear all history?": "确定要清除所有历史记录吗?",
"clear history": "清除历史记录",
new: "新",
del: "删",
cut: "遗忘",
"please click above to set": "请点击上方进行设置",
cost: "消费",
stream: "流式返回",
fetch: "一次获取",
"saved api templates": "已保存的 API 模板",
"saved prompt templates": "已保存的提示模板",
"no chat history here": "暂无历史对话记录",
"click above to change the settings of this chat":
"点击上方更改此对话的参数(请勿泄漏)",
"click the NEW to create a new chat": "点击左上角 NEW 新建对话",
"all chat history and settings are stored in the local browser":
"所有历史对话与参数储存在浏览器本地",
"documents and source code are avaliable here":
"详细文档与源代码可在此处获取",
"generating...": "生成中,请保持网络稳定...",
"re-generate": "重新生成",
completion: "补全",
"generated by": "生成模型: ",
"info: chat history is too long, forget messages":
"提示:对话历史过长,遗忘消息数量",
"warning: current chatstore version": "警告:当前会话版本",
retry: "重试",
send: "发送",
assistant: "AI消息",
user: "用户消息",
close: "关闭",
"message copied to clipboard": "消息已复制到剪贴板",
"total cost in this session": "本次会话总消费",
"accumulated cost in all sessions": "所有会话总消费",
export: "导出",
"give this template a name:": "给此模板命名:",
"no template name specified": "未指定模板名称",
"as template": "保存为会话模板",
"as api template": "保存为 API 模板",
"this will overwrite the current chat history! continue?":
"此操作将覆盖当前会话历史!继续?",
"please select a json file": "请选择一个 JSON 文件",
"empty file": "警告: 空文件",
"this is not an exported chatgpt-api-web chatstore file. the key 'chatgpt_api_web_version' is missing!":
"此文件不是 chatgpt-api-web 导出的会话文件,缺少 chatgpt_api_web_version 键值!",
"import error on parsing json": "JSON 解析错误",
version: "版本",
"copied link:": "已复制链接:",
reset: "重置",
example: "示例",
render: "渲染",
};
export default LANG_MAP;