From 7fc43b474512c95fdd39b40586c8221124a86fab Mon Sep 17 00:00:00 2001 From: Peanuts <849421294godw@gmail.com> Date: Thu, 13 Apr 2023 11:07:42 +0800 Subject: [PATCH 01/35] Fix wrong spelling --- app/requests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/requests.ts b/app/requests.ts index 86d180f71..c48ef2817 100644 --- a/app/requests.ts +++ b/app/requests.ts @@ -189,8 +189,8 @@ export async function requestChatStream( finish(); } else if (res.status === 401) { - console.error("Anauthorized"); - options?.onError(new Error("Anauthorized"), res.status); + console.error("Unauthorized"); + options?.onError(new Error("Unauthorized"), res.status); } else { console.error("Stream Error", res.body); options?.onError(new Error("Stream Error"), res.status); From 4baadefa1d4aedff841475c5f1504e4347ce0ab1 Mon Sep 17 00:00:00 2001 From: JessySnow Date: Thu, 13 Apr 2023 18:31:38 +0800 Subject: [PATCH 02/35] fix docker proxy config --- README_CN.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README_CN.md b/README_CN.md index b8a46f20a..7d1a835c4 100644 --- a/README_CN.md +++ b/README_CN.md @@ -137,7 +137,8 @@ docker run -d -p 3000:3000 \ docker run -d -p 3000:3000 \ -e OPENAI_API_KEY="sk-xxxx" \ -e CODE="页面访问密码" \ - -e PROXY_URL="http://localhost:7890" \ + --net=host \ + -e PROXY_URL="http://127.0.0.1:7890" \ yidadaa/chatgpt-next-web ``` From 563eb96282a70e50efa97c1d8af775b3282d0e45 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Thu, 13 Apr 2023 22:47:40 +0800 Subject: [PATCH 03/35] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 010cc38c1..8a09a0657 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ One-Click to deploy well-designed ChatGPT web UI on Vercel. [Demo](https://chat-gpt-next-web.vercel.app/) / [Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [Join Discord](https://discord.gg/zrhvHCr79N) / [Buy Me a Coffee](https://www.buymeacoffee.com/yidadaa) -[演示](https://chat-gpt-next-web.vercel.app/) / [反馈](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [QQ 群](https://user-images.githubusercontent.com/16968934/231095592-330adc52-0337-4c13-8452-938ec169e367.jpeg) / [打赏开发者](https://user-images.githubusercontent.com/16968934/227772541-5bcd52d8-61b7-488c-a203-0330d8006e2b.jpg) +[演示](https://chat-gpt-next-web.vercel.app/) / [反馈](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [QQ 群](https://user-images.githubusercontent.com/16968934/231789746-41f34d05-6ef9-43f3-a1d1-ff109d4c3c14.jpg) / [打赏开发者](https://user-images.githubusercontent.com/16968934/227772541-5bcd52d8-61b7-488c-a203-0330d8006e2b.jpg) [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FYidadaa%2FChatGPT-Next-Web&env=OPENAI_API_KEY&env=CODE&project-name=chatgpt-next-web&repository-name=ChatGPT-Next-Web) From 73216513dd9a0000430658122e5d589d81b658fb Mon Sep 17 00:00:00 2001 From: jtung4 Date: Fri, 14 Apr 2023 19:49:48 +0800 Subject: [PATCH 04/35] Update tw.ts --- app/locales/tw.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/locales/tw.ts b/app/locales/tw.ts index 77975b896..b239ed65d 100644 --- a/app/locales/tw.ts +++ b/app/locales/tw.ts @@ -152,9 +152,9 @@ const tw: LocaleType = { Prompt: { History: (content: string) => "這是 AI 與用戶的歷史聊天總結,作為前情提要:" + content, - Topic: "直接返回這句話的簡要主題,無須解釋,若無主題,請直接返回「閒聊」", + Topic: "Summarise the conversation in a short and concise eye-catching title that instantly conveys the main topic. Use as few words as possible. Use the language used in the enquiry, e.g. use English for English enquiry, use zh-hant for traditional chinese enquiry. Don't use quotation marks at the beginning and the end.", Summarize: - "簡要總結一下你和用戶的對話,作為後續的上下文提示 prompt,且字數控制在 200 字以內", + "Summarise the conversation in at most 250 tokens for continuing the conversation in future. Use the language used in the conversation, e.g. use English for English conversation, use zh-hant for traditional chinese conversation.", }, ConfirmClearAll: "確認清除所有對話、設定數據?", }, From fb14785cadf2055818bd4ff9c6064b59e53c2700 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sat, 15 Apr 2023 02:28:30 +0800 Subject: [PATCH 05/35] fix: #804 disable auto scroll in textarea --- app/components/chat.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index b9ae13926..b0deb5a51 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -442,16 +442,6 @@ export function Chat(props: { inputRef.current?.focus(); }; - const scrollInput = () => { - const dom = inputRef.current; - if (!dom) return; - const paddingBottomNum: number = parseInt( - window.getComputedStyle(dom).paddingBottom, - 10, - ); - dom.scrollTop = dom.scrollHeight - dom.offsetHeight + paddingBottomNum; - }; - // auto grow input const [inputRows, setInputRows] = useState(2); const measure = useDebouncedCallback( @@ -476,7 +466,6 @@ export function Chat(props: { // only search prompts when user input is short const SEARCH_TEXT_LIMIT = 30; const onInput = (text: string) => { - scrollInput(); setUserInput(text); const n = text.trim().length; From 47a2911ee2cd229feb14967a10d02148d2ae2913 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sat, 15 Apr 2023 02:37:24 +0800 Subject: [PATCH 06/35] feat: edit session title button --- app/components/chat.tsx | 24 +++++++++++------------- app/icons/rename.svg | 1 + 2 files changed, 12 insertions(+), 13 deletions(-) create mode 100644 app/icons/rename.svg diff --git a/app/components/chat.tsx b/app/components/chat.tsx index b0deb5a51..f7b67b293 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -3,6 +3,7 @@ import { memo, useState, useRef, useEffect, useLayoutEffect } from "react"; import SendWhiteIcon from "../icons/send-white.svg"; import BrainIcon from "../icons/brain.svg"; +import RenameIcon from "../icons/rename.svg"; import ExportIcon from "../icons/share.svg"; import ReturnIcon from "../icons/return.svg"; import CopyIcon from "../icons/copy.svg"; @@ -589,6 +590,13 @@ export function Chat(props: { const [showPromptModal, setShowPromptModal] = useState(false); + const renameSession = () => { + const newTopic = prompt(Locale.Chat.Rename, session.topic); + if (newTopic && newTopic !== session.topic) { + chatStore.updateCurrentSession((session) => (session.topic = newTopic!)); + } + }; + // Auto focus useEffect(() => { if (props.sideBarShowing && isMobileScreen()) return; @@ -602,14 +610,7 @@ export function Chat(props: {
{ - const newTopic = prompt(Locale.Chat.Rename, session.topic); - if (newTopic && newTopic !== session.topic) { - chatStore.updateCurrentSession( - (session) => (session.topic = newTopic!), - ); - } - }} + onClickCapture={renameSession} > {session.topic}
@@ -628,12 +629,9 @@ export function Chat(props: {
} + icon={} bordered - title={Locale.Chat.Actions.CompressedHistory} - onClick={() => { - setShowPromptModal(true); - }} + onClick={renameSession} />
diff --git a/app/icons/rename.svg b/app/icons/rename.svg new file mode 100644 index 000000000..cee69eb8d --- /dev/null +++ b/app/icons/rename.svg @@ -0,0 +1 @@ + From 0a79df3670e9aed5b62d1331012cbffdce74255a Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sat, 15 Apr 2023 02:50:04 +0800 Subject: [PATCH 07/35] refactor: remove protocol env vars --- README.md | 13 ++++--------- README_CN.md | 12 ++++-------- app/api/common.ts | 11 +++++++++-- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 8a09a0657..42642ec98 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ We recommend that you follow the steps below to re-deploy: - Choose and deploy in Vercel again, [please see the detailed tutorial](./docs/vercel-cn.md). ### Enable Automatic Updates + After forking the project, due to the limitations imposed by Github, you need to manually enable Workflows and Upstream Sync Action on the Actions page of the forked project. Once enabled, automatic updates will be scheduled every hour: ![Automatic Updates](./docs/images/enable-actions.jpg) @@ -104,6 +105,7 @@ After forking the project, due to the limitations imposed by Github, you need to ![Enable Automatic Updates](./docs/images/enable-actions-sync.jpg) ### Manually Updating Code + If you want to update instantly, you can check out the [Github documentation](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork) to learn how to synchronize a forked project with upstream code. You can star or watch this project or follow author to get release notifictions in time. @@ -134,18 +136,11 @@ Access passsword, separated by comma. ### `BASE_URL` (optional) -> Default: `api.openai.com` +> Default: `https://api.openai.com` +> Examples: `http://your-openai-proxy.com` Override openai api request base url. -### `PROTOCOL` (optional) - -> Default: `https` - -> Values: `http` | `https` - -Override openai api request protocol. - ## Development > [简体中文 > 如何进行二次开发](./README_CN.md#开发) diff --git a/README_CN.md b/README_CN.md index 7d1a835c4..9c80d865f 100644 --- a/README_CN.md +++ b/README_CN.md @@ -43,6 +43,7 @@ - 在 Vercel 重新选择并部署,[请查看详细教程](./docs/vercel-cn.md#如何新建项目)。 ### 打开自动更新 + 当你 fork 项目之后,由于 Github 的限制,需要手动去你 fork 后的项目的 Actions 页面启用 Workflows,并启用 Upstream Sync Action,启用之后即可开启每小时定时自动更新: ![自动更新](./docs/images/enable-actions.jpg) @@ -85,17 +86,12 @@ OpanAI 密钥,你在 openai 账户页面申请的 api key。 ### `BASE_URL` (可选) -> Default: `api.openai.com` +> Default: `https://api.openai.com` +> Examples: `http://your-openai-proxy.com` OpenAI 接口代理 URL,如果你手动配置了 openai 接口代理,请填写此选项。 -### `PROTOCOL` (可选) - -> Default: `https` - -> Values: `http` | `https` - -OpenAI 代理接口协议,如果遇到 ssl 证书问题,请尝试通过此选项设置为 http。 +> 如果遇到 ssl 证书问题,请将 `BASE_URL` 的协议设置为 http。 ## 开发 diff --git a/app/api/common.ts b/app/api/common.ts index 842eeacaf..53ab18ed6 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -9,9 +9,16 @@ export async function requestOpenai(req: NextRequest) { const apiKey = req.headers.get("token"); const openaiPath = req.headers.get("path"); - console.log("[Proxy] ", openaiPath); + let baseUrl = BASE_URL; - return fetch(`${PROTOCOL}://${BASE_URL}/${openaiPath}`, { + if (!baseUrl.startsWith("http")) { + baseUrl = `${PROTOCOL}://${baseUrl}`; + } + + console.log("[Proxy] ", openaiPath); + console.log("[Base Url]", baseUrl); + + return fetch(`${baseUrl}/${openaiPath}`, { headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}`, From ad274b7cadea0c66a6bce2a8a188dc87e98371fe Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sat, 15 Apr 2023 02:51:15 +0800 Subject: [PATCH 08/35] fixup --- README.md | 1 + README_CN.md | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 42642ec98..a6288798a 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,7 @@ Access passsword, separated by comma. ### `BASE_URL` (optional) > Default: `https://api.openai.com` + > Examples: `http://your-openai-proxy.com` Override openai api request base url. diff --git a/README_CN.md b/README_CN.md index 9c80d865f..d2d64aa00 100644 --- a/README_CN.md +++ b/README_CN.md @@ -87,6 +87,7 @@ OpanAI 密钥,你在 openai 账户页面申请的 api key。 ### `BASE_URL` (可选) > Default: `https://api.openai.com` + > Examples: `http://your-openai-proxy.com` OpenAI 接口代理 URL,如果你手动配置了 openai 接口代理,请填写此选项。 From 98fd08d9e5e300e8b2d0389d5c55ab17c6f66470 Mon Sep 17 00:00:00 2001 From: ilarioscandurra Date: Sat, 15 Apr 2023 16:33:04 +0200 Subject: [PATCH 09/35] fix IT translation --- app/locales/it.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/locales/it.ts b/app/locales/it.ts index 3cd768fed..c785d616e 100644 --- a/app/locales/it.ts +++ b/app/locales/it.ts @@ -45,12 +45,12 @@ const it: LocaleType = { Send: "Send Memory", Reset: "Reset Session", ResetConfirm: - "Resetting will clear the current conversation history and historical memory. Are you sure you want to reset?", + "Ripristinare cancellerà la conversazione corrente e la cronologia di memoria. Sei sicuro che vuoi riavviare?", }, Home: { NewChat: "Nuova Chat", DeleteChat: "Confermare la cancellazione della conversazione selezionata?", - DeleteToast: "Chat Deleted", + DeleteToast: "Chat Cancellata", Revert: "Revert", }, Settings: { @@ -93,9 +93,9 @@ const it: LocaleType = { GoToUpdate: "Aggiorna", }, SendKey: "Tasto invia", - Theme: "tema", - TightBorder: "Bordi stretti", - SendPreviewBubble: "Invia l'anteprima della bolla", + Theme: "Tema", + TightBorder: "Schermo intero", + SendPreviewBubble: "Anteprima di digitazione", Prompt: { Disable: { Title: "Disabilita l'auto completamento", @@ -116,7 +116,7 @@ const it: LocaleType = { "Comprimerà se la lunghezza dei messaggi non compressi supera il valore", }, Token: { - Title: "Chiave API", + Title: "API Key", SubTitle: "Utilizzare la chiave per ignorare il limite del codice di accesso", Placeholder: "OpenAI API Key", @@ -124,7 +124,7 @@ const it: LocaleType = { Usage: { Title: "Bilancio Account", SubTitle(used: any, total: any) { - return `Usato in questo mese $${used}, subscription $${total}`; + return `Attualmente usato in questo mese $${used}, soglia massima $${total}`; }, IsChecking: "Controllando...", Check: "Controlla ancora", From e0fa0d19366a6f998f0cfb024a4bf0a18cff5b2f Mon Sep 17 00:00:00 2001 From: tscherrie tscherru Date: Sun, 16 Apr 2023 04:00:31 +0000 Subject: [PATCH 10/35] Add german language translation de.tss --- app/locales/de.ts | 183 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 app/locales/de.ts diff --git a/app/locales/de.ts b/app/locales/de.ts new file mode 100644 index 000000000..193d5443b --- /dev/null +++ b/app/locales/de.ts @@ -0,0 +1,183 @@ +import { SubmitKey } from "../store/app"; +import type { LocaleType } from "./index"; + +const de: LocaleType = { + WIP: "In Bearbeitung...", + Error: { + Unauthorized: + "Unbefugter Zugriff, bitte geben Sie den Zugangscode auf der Einstellungsseite ein.", + }, + ChatItem: { + ChatItemCount: (count: number) => `${count} Nachrichten`, + }, + Chat: { + SubTitle: (count: number) => `${count} Nachrichten mit ChatGPT`, + Actions: { + ChatList: "Zur Chat-Liste gehen", + CompressedHistory: "Komprimierter VerlaufsGedächtnis-Prompt", + Export: "Alle Nachrichten als Markdown exportieren", + Copy: "Kopieren", + Stop: "Stop", + Retry: "Wiederholen", + }, + Rename: "Chat umbenennen", + Typing: "Tippen...", + Input: (submitKey: string) => { + var inputHints = `${submitKey} zum Senden`; + if (submitKey === String(SubmitKey.Enter)) { + inputHints += ", Umschalt + Eingabe zum Zeilenumbruch"; + } + return inputHints + ", / zum Durchsuchen von Prompts"; + }, + Send: "Senden", + }, + Export: { + Title: "Alle Nachrichten", + Copy: "Alles kopieren", + Download: "Herunterladen", + MessageFromYou: "Deine Nachricht", + MessageFromChatGPT: "Nachricht von ChatGPT", + }, + Memory: { + Title: "Gedächtnis-Prompt", + EmptyContent: "Noch nichts.", + Send: "Gedächtnis senden", + Copy: "Gedächtnis kopieren", + Reset: "Sitzung zurücksetzen", + ResetConfirm: + "Das Zurücksetzen löscht den aktuellen Gesprächsverlauf und das Langzeit-Gedächtnis. Möchten Sie wirklich zurücksetzen?", + }, + Home: { + NewChat: "Neuer Chat", + DeleteChat: "Bestätigen Sie, um das ausgewählte Gespräch zu löschen?", + DeleteToast: "Chat gelöscht", + Revert: "Zurücksetzen", + }, + Settings: { + Title: "Einstellungen", + SubTitle: "Alle Einstellungen", + Actions: { + ClearAll: "Alle Daten löschen", + ResetAll: "Alle Einstellungen zurücksetzen", + Close: "Schließen", + ConfirmResetAll: { + Confirm: "Möchten Sie wirklich alle Konfigurationen zurücksetzen?", + }, + ConfirmClearAll: { + Confirm: "Möchten Sie wirklich alle Chats zurücksetzen?", + }, + }, + Lang: { + Name: "Language", // ATTENTION: if you wanna add a new translation, please do not translate this value, leave it as `Language` + Options: { + cn: "简体中文", + en: "English", + tw: "繁體中文", + es: "Español", + it: "Italiano", + tr: "Türkçe", + jp: "日本語", + de: "Deutsch", + }, + }, + Avatar: "Avatar", + FontSize: { + Title: "Schriftgröße", + SubTitle: "Schriftgröße des Chat-Inhalts anpassen", + }, + Update: { + Version: (x: string) => `Version: ${x}`, + IsLatest: "Neueste Version", + CheckUpdate: "Update prüfen", + IsChecking: "Update wird geprüft...", + FoundUpdate: (x: string) => `Neue Version gefunden: ${x}`, + GoToUpdate: "Aktualisieren", + }, + SendKey: "Sendetaste", + Theme: "Thema", + TightBorder: "Enge Grenze", + SendPreviewBubble: "Vorschau-Bubble senden", + Prompt: { + Disable: { + Title: "Autovervollständigung deaktivieren", + SubTitle: "Autovervollständigung mit / starten", + }, + List: "Prompt-Liste", + ListCount: (builtin: number, custom: number) => + `${builtin} integriert, ${custom} benutzerdefiniert`, + Edit: "Bearbeiten", + }, + HistoryCount: { + Title: "Anzahl der angehängten Nachrichten", + SubTitle: "Anzahl der pro Anfrage angehängten gesendeten Nachrichten", + }, + CompressThreshold: { + Title: "Schwellenwert für Verlaufskomprimierung", + SubTitle: + "Wird komprimiert, wenn die Länge der unkomprimierten Nachrichten den Wert überschreitet", + }, + Token: { + Title: "API-Schlüssel", + SubTitle: + "Verwenden Sie Ihren Schlüssel, um das Zugangscodelimit zu ignorieren", + Placeholder: "OpenAI API-Schlüssel", + }, + Usage: { + Title: "Kontostand", + SubTitle(used: any, total: any) { + return `Diesen Monat verwendet $${used}, Abonnement $${total}`; + }, + IsChecking: "Wird überprüft...", + Check: "Erneut prüfen", + NoAccess: "API-Schlüssel eingeben, um den Kontostand zu überprüfen", + }, + AccessCode: { + Title: "Zugangscode", + SubTitle: "Zugangskontrolle aktiviert", + Placeholder: "Zugangscode erforderlich", + }, + Model: "Modell", + Temperature: { + Title: "Temperature", //Temperatur + SubTitle: "Ein größerer Wert führt zu zufälligeren Antworten", + }, + MaxTokens: { + Title: "Max Tokens", //Maximale Token + SubTitle: "Maximale Anzahl der Anfrage- plus Antwort-Token", + }, + PresencePenlty: { + Title: "Presence Penalty", //Anwesenheitsstrafe + SubTitle: + "Ein größerer Wert erhöht die Wahrscheinlichkeit, dass über neue Themen gesprochen wird", + }, + }, + Store: { + DefaultTopic: "Neues Gespräch", + BotHello: "Hallo! Wie kann ich Ihnen heute helfen?", + Error: + "Etwas ist schief gelaufen, bitte versuchen Sie es später noch einmal.", + Prompt: { + History: (content: string) => + "Dies ist eine Zusammenfassung des Chatverlaufs zwischen dem KI und dem Benutzer als Rückblick: " + + content, + Topic: + "Bitte erstellen Sie einen vier- bis fünfwörtigen Titel, der unser Gespräch zusammenfasst, ohne Einleitung, Zeichensetzung, Anführungszeichen, Punkte, Symbole oder zusätzlichen Text. Entfernen Sie Anführungszeichen.", + Summarize: + "Fassen Sie unsere Diskussion kurz in 200 Wörtern oder weniger zusammen, um sie als Pronpt für zukünftige Gespräche zu verwenden.", + }, + ConfirmClearAll: + "Bestätigen Sie, um alle Chat- und Einstellungsdaten zu löschen?", + }, + Copy: { + Success: "In die Zwischenablage kopiert", + Failed: + "Kopieren fehlgeschlagen, bitte geben Sie die Berechtigung zum Zugriff auf die Zwischenablage frei", + }, + Context: { + Toast: (x: any) => `Mit ${x} kontextbezogene Prompts`, + Edit: "Kontextbezogene und Gedächtnis-Prompts", + Add: "Hinzufügen", + }, +}; + +export default de; From 4ce5f89c660d4ff67487cecb7bb524d8f677c9ca Mon Sep 17 00:00:00 2001 From: tscherrie tscherru Date: Sun, 16 Apr 2023 04:16:04 +0000 Subject: [PATCH 11/35] fixed german language translations --- app/locales/en.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/locales/en.ts b/app/locales/en.ts index bd417aa84..686d73eee 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -77,6 +77,7 @@ const en: LocaleType = { it: "Italiano", tr: "Türkçe", jp: "日本語", + de: "Deutsch", }, }, Avatar: "Avatar", From f042d07ee7312dc792ef78c497ba68655ccfc4be Mon Sep 17 00:00:00 2001 From: tscherrie tscherru Date: Sun, 16 Apr 2023 05:07:54 +0000 Subject: [PATCH 12/35] added de to index and other files --- app/locales/cn.ts | 1 + app/locales/es.ts | 1 + app/locales/index.ts | 27 +++++++++++++++++++++++---- app/locales/it.ts | 1 + app/locales/jp.ts | 1 + app/locales/tr.ts | 1 + app/locales/tw.ts | 4 +++- app/store/app.ts | 1 + 8 files changed, 32 insertions(+), 5 deletions(-) diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 9973a3c68..aa99227ce 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -74,6 +74,7 @@ const cn = { it: "Italiano", tr: "Türkçe", jp: "日本語", + de: "Deutsch", }, }, Avatar: "头像", diff --git a/app/locales/es.ts b/app/locales/es.ts index 88bcd2012..a895367f0 100644 --- a/app/locales/es.ts +++ b/app/locales/es.ts @@ -77,6 +77,7 @@ const es: LocaleType = { it: "Italiano", tr: "Türkçe", jp: "日本語", + de: "Deutsch", }, }, Avatar: "Avatar", diff --git a/app/locales/index.ts b/app/locales/index.ts index dff1e6614..e4b303b41 100644 --- a/app/locales/index.ts +++ b/app/locales/index.ts @@ -5,10 +5,20 @@ import ES from "./es"; import IT from "./it"; import TR from "./tr"; import JP from "./jp"; +import DE from "./de"; export type { LocaleType } from "./cn"; -export const AllLangs = ["en", "cn", "tw", "es", "it", "tr", "jp"] as const; +export const AllLangs = [ + "en", + "cn", + "tw", + "es", + "it", + "tr", + "jp", + "de", +] as const; type Lang = (typeof AllLangs)[number]; const LANG_KEY = "lang"; @@ -56,6 +66,8 @@ export function getLang(): Lang { return "tr"; } else if (lang.includes("jp")) { return "jp"; + } else if (lang.includes("de")) { + return "de"; } else { return "en"; } @@ -66,6 +78,13 @@ export function changeLang(lang: Lang) { location.reload(); } -export default { en: EN, cn: CN, tw: TW, es: ES, it: IT, tr: TR, jp: JP }[ - getLang() -]; +export default { + en: EN, + cn: CN, + tw: TW, + es: ES, + it: IT, + tr: TR, + jp: JP, + de: DE, +}[getLang()]; diff --git a/app/locales/it.ts b/app/locales/it.ts index c785d616e..928572214 100644 --- a/app/locales/it.ts +++ b/app/locales/it.ts @@ -77,6 +77,7 @@ const it: LocaleType = { it: "Italiano", tr: "Türkçe", jp: "日本語", + de: "Deutsch", }, }, Avatar: "Avatar", diff --git a/app/locales/jp.ts b/app/locales/jp.ts index 50ac21609..09623a570 100644 --- a/app/locales/jp.ts +++ b/app/locales/jp.ts @@ -76,6 +76,7 @@ const jp = { it: "Italiano", tr: "Türkçe", jp: "日本語", + de: "Deutsch", }, }, Avatar: "アバター", diff --git a/app/locales/tr.ts b/app/locales/tr.ts index 708d2d7d5..a77771be1 100644 --- a/app/locales/tr.ts +++ b/app/locales/tr.ts @@ -77,6 +77,7 @@ const tr: LocaleType = { it: "Italiano", tr: "Türkçe", jp: "日本語", + de: "Deutsch", }, }, Avatar: "Avatar", diff --git a/app/locales/tw.ts b/app/locales/tw.ts index b239ed65d..318bdcd29 100644 --- a/app/locales/tw.ts +++ b/app/locales/tw.ts @@ -75,6 +75,7 @@ const tw: LocaleType = { it: "Italiano", tr: "Türkçe", jp: "日本語", + de: "Deutsch", }, }, Avatar: "大頭貼", @@ -152,7 +153,8 @@ const tw: LocaleType = { Prompt: { History: (content: string) => "這是 AI 與用戶的歷史聊天總結,作為前情提要:" + content, - Topic: "Summarise the conversation in a short and concise eye-catching title that instantly conveys the main topic. Use as few words as possible. Use the language used in the enquiry, e.g. use English for English enquiry, use zh-hant for traditional chinese enquiry. Don't use quotation marks at the beginning and the end.", + Topic: + "Summarise the conversation in a short and concise eye-catching title that instantly conveys the main topic. Use as few words as possible. Use the language used in the enquiry, e.g. use English for English enquiry, use zh-hant for traditional chinese enquiry. Don't use quotation marks at the beginning and the end.", Summarize: "Summarise the conversation in at most 250 tokens for continuing the conversation in future. Use the language used in the conversation, e.g. use English for English conversation, use zh-hant for traditional chinese conversation.", }, diff --git a/app/store/app.ts b/app/store/app.ts index 813668905..c767d9999 100644 --- a/app/store/app.ts +++ b/app/store/app.ts @@ -560,6 +560,7 @@ export const useChatStore = create()( onError(error) { console.error("[Summarize] ", error); }, + enen, }, ); } From 2c35c2674945fdb65d35d22981aa864c980a4227 Mon Sep 17 00:00:00 2001 From: tscherrie tscherru Date: Sun, 16 Apr 2023 05:32:55 +0000 Subject: [PATCH 13/35] fixed typo --- app/store/app.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/store/app.ts b/app/store/app.ts index c767d9999..813668905 100644 --- a/app/store/app.ts +++ b/app/store/app.ts @@ -560,7 +560,6 @@ export const useChatStore = create()( onError(error) { console.error("[Summarize] ", error); }, - enen, }, ); } From 410695d8233902a0bb2a61d4b45e8428837124fa Mon Sep 17 00:00:00 2001 From: tscherrie tscherru Date: Sun, 16 Apr 2023 07:11:36 +0000 Subject: [PATCH 14/35] some final language quality improvements --- app/locales/de.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/locales/de.ts b/app/locales/de.ts index 193d5443b..0f4bf8996 100644 --- a/app/locales/de.ts +++ b/app/locales/de.ts @@ -23,9 +23,9 @@ const de: LocaleType = { Rename: "Chat umbenennen", Typing: "Tippen...", Input: (submitKey: string) => { - var inputHints = `${submitKey} zum Senden`; + var inputHints = `${submitKey} um zu Senden`; if (submitKey === String(SubmitKey.Enter)) { - inputHints += ", Umschalt + Eingabe zum Zeilenumbruch"; + inputHints += ", Umschalt + Eingabe für Zeilenumbruch"; } return inputHints + ", / zum Durchsuchen von Prompts"; }, @@ -93,9 +93,9 @@ const de: LocaleType = { FoundUpdate: (x: string) => `Neue Version gefunden: ${x}`, GoToUpdate: "Aktualisieren", }, - SendKey: "Sendetaste", - Theme: "Thema", - TightBorder: "Enge Grenze", + SendKey: "Senden-Taste", + Theme: "Erscheinungsbild", + TightBorder: "Enger Rahmen", SendPreviewBubble: "Vorschau-Bubble senden", Prompt: { Disable: { @@ -114,18 +114,18 @@ const de: LocaleType = { CompressThreshold: { Title: "Schwellenwert für Verlaufskomprimierung", SubTitle: - "Wird komprimiert, wenn die Länge der unkomprimierten Nachrichten den Wert überschreitet", + "Komprimierung, wenn die Länge der unkomprimierten Nachrichten den Wert überschreitet", }, Token: { Title: "API-Schlüssel", SubTitle: - "Verwenden Sie Ihren Schlüssel, um das Zugangscodelimit zu ignorieren", + "Verwenden Sie Ihren Schlüssel, um das Zugangscode-Limit zu ignorieren", Placeholder: "OpenAI API-Schlüssel", }, Usage: { Title: "Kontostand", SubTitle(used: any, total: any) { - return `Diesen Monat verwendet $${used}, Abonnement $${total}`; + return `Diesen Monat ausgegeben $${used}, Abonnement $${total}`; }, IsChecking: "Wird überprüft...", Check: "Erneut prüfen", @@ -174,8 +174,8 @@ const de: LocaleType = { "Kopieren fehlgeschlagen, bitte geben Sie die Berechtigung zum Zugriff auf die Zwischenablage frei", }, Context: { - Toast: (x: any) => `Mit ${x} kontextbezogene Prompts`, - Edit: "Kontextbezogene und Gedächtnis-Prompts", + Toast: (x: any) => `Mit ${x} Kontext-Prompts`, + Edit: "Kontext- und Gedächtnis-Prompts", Add: "Hinzufügen", }, }; From f9906aba7f2ed54bab518907d25682b5e16632ae Mon Sep 17 00:00:00 2001 From: tscherrie tscherru Date: Sun, 16 Apr 2023 07:43:38 +0000 Subject: [PATCH 15/35] found typo --- app/locales/de.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/locales/de.ts b/app/locales/de.ts index 0f4bf8996..60698c626 100644 --- a/app/locales/de.ts +++ b/app/locales/de.ts @@ -14,7 +14,7 @@ const de: LocaleType = { SubTitle: (count: number) => `${count} Nachrichten mit ChatGPT`, Actions: { ChatList: "Zur Chat-Liste gehen", - CompressedHistory: "Komprimierter VerlaufsGedächtnis-Prompt", + CompressedHistory: "Komprimierter Gedächtnis-Prompt", Export: "Alle Nachrichten als Markdown exportieren", Copy: "Kopieren", Stop: "Stop", From bd69c8f5dd90bef9290c20a321a638a949b929b5 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sun, 16 Apr 2023 17:20:33 +0800 Subject: [PATCH 16/35] feat: close #813 log user ip time --- middleware.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/middleware.ts b/middleware.ts index c2e077706..d16a812d9 100644 --- a/middleware.ts +++ b/middleware.ts @@ -8,6 +8,17 @@ export const config = { const serverConfig = getServerSideConfig(); +function getIP(req: NextRequest) { + let ip = req.ip ?? req.headers.get("x-real-ip"); + const forwardedFor = req.headers.get("x-forwarded-for"); + + if (!ip && forwardedFor) { + ip = forwardedFor.split(",").at(0) ?? ""; + } + + return ip; +} + export function middleware(req: NextRequest) { const accessCode = req.headers.get("access-code"); const token = req.headers.get("token"); @@ -16,6 +27,8 @@ export function middleware(req: NextRequest) { console.log("[Auth] allowed hashed codes: ", [...serverConfig.codes]); console.log("[Auth] got access code:", accessCode); console.log("[Auth] hashed access code:", hashedCode); + console.log("[User IP] ", getIP(req)); + console.log("[Time] ", new Date().toLocaleString()); if (serverConfig.needCode && !serverConfig.codes.has(hashedCode) && !token) { return NextResponse.json( From dc3883ed1aa8bc4c7b25216f52774a4a860623e4 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sun, 16 Apr 2023 18:07:43 +0800 Subject: [PATCH 17/35] feat: close #118 add stop all button --- app/components/chat.tsx | 16 ++++++++++++++-- app/icons/bottom.svg | 2 +- app/icons/pause.svg | 1 + app/requests.ts | 15 +++++++++++---- app/store/app.ts | 2 +- package.json | 3 ++- scripts/.gitignore | 1 + scripts/init-proxy.sh | 5 +++++ scripts/proxychains.template.conf | 12 ++++++++++++ 9 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 app/icons/pause.svg create mode 100644 scripts/.gitignore create mode 100644 scripts/init-proxy.sh create mode 100644 scripts/proxychains.template.conf diff --git a/app/components/chat.tsx b/app/components/chat.tsx index f7b67b293..9e4a2bd9a 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -19,6 +19,7 @@ import LightIcon from "../icons/light.svg"; import DarkIcon from "../icons/dark.svg"; import AutoIcon from "../icons/auto.svg"; import BottomIcon from "../icons/bottom.svg"; +import StopIcon from "../icons/pause.svg"; import { Message, @@ -38,7 +39,6 @@ import { isMobileScreen, selectOrCopy, autoGrowTextArea, - getCSSVar, } from "../utils"; import dynamic from "next/dynamic"; @@ -355,8 +355,8 @@ export function ChatActions(props: { }) { const chatStore = useChatStore(); + // switch themes const theme = chatStore.config.theme; - function nextTheme() { const themes = [Theme.Auto, Theme.Light, Theme.Dark]; const themeIndex = themes.indexOf(theme); @@ -365,8 +365,20 @@ export function ChatActions(props: { chatStore.updateConfig((config) => (config.theme = nextTheme)); } + // stop all responses + const couldStop = ControllerPool.hasPending(); + const stopAll = () => ControllerPool.stopAll(); + return (
+ {couldStop && ( +
+ +
+ )} {!props.hitBottom && (
+ diff --git a/app/icons/pause.svg b/app/icons/pause.svg new file mode 100644 index 000000000..382f7a939 --- /dev/null +++ b/app/icons/pause.svg @@ -0,0 +1 @@ + diff --git a/app/requests.ts b/app/requests.ts index c48ef2817..db91f6fc3 100644 --- a/app/requests.ts +++ b/app/requests.ts @@ -2,7 +2,7 @@ import type { ChatRequest, ChatResponse } from "./api/openai/typing"; import { Message, ModelConfig, useAccessStore, useChatStore } from "./store"; import { showToast } from "./components/ui-lib"; -const TIME_OUT_MS = 30000; +const TIME_OUT_MS = 60000; const makeRequestParam = ( messages: Message[], @@ -167,15 +167,14 @@ export async function requestChatStream( options?.onController?.(controller); while (true) { - // handle time out, will stop if no response in 10 secs const resTimeoutId = setTimeout(() => finish(), TIME_OUT_MS); const content = await reader?.read(); clearTimeout(resTimeoutId); - + if (!content || !content.value) { break; } - + const text = decoder.decode(content.value, { stream: true }); responseText += text; @@ -235,6 +234,14 @@ export const ControllerPool = { controller?.abort(); }, + stopAll() { + Object.values(this.controllers).forEach((v) => v.abort()); + }, + + hasPending() { + return Object.values(this.controllers).length > 0; + }, + remove(sessionIndex: number, messageId: number) { const key = this.key(sessionIndex, messageId); delete this.controllers[key]; diff --git a/app/store/app.ts b/app/store/app.ts index 813668905..c4c1c3411 100644 --- a/app/store/app.ts +++ b/app/store/app.ts @@ -421,7 +421,7 @@ export const useChatStore = create()( onError(error, statusCode) { if (statusCode === 401) { botMessage.content = Locale.Error.Unauthorized; - } else { + } else if (!error.message.includes("aborted")) { botMessage.content += "\n\n" + Locale.Store.Error; } botMessage.streaming = false; diff --git a/package.json b/package.json index 9fcb74e77..9a3e6d41c 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "start": "next start", "lint": "next lint", "fetch": "node ./scripts/fetch-prompts.mjs", - "prepare": "husky install" + "prepare": "husky install", + "proxy-dev": "sh ./scripts/init-proxy.sh && proxychains -f ./scripts/proxychains.conf yarn dev" }, "dependencies": { "@hello-pangea/dnd": "^16.2.0", diff --git a/scripts/.gitignore b/scripts/.gitignore new file mode 100644 index 000000000..80fe56c37 --- /dev/null +++ b/scripts/.gitignore @@ -0,0 +1 @@ +proxychains.conf diff --git a/scripts/init-proxy.sh b/scripts/init-proxy.sh new file mode 100644 index 000000000..acba064f4 --- /dev/null +++ b/scripts/init-proxy.sh @@ -0,0 +1,5 @@ +dir="$(dirname "$0")" +config=$dir/proxychains.conf +host_ip=$(grep nameserver /etc/resolv.conf | sed 's/nameserver //') +cp $dir/proxychains.template.conf $config +sed -i "\$s/.*/http $host_ip 7890/" $config diff --git a/scripts/proxychains.template.conf b/scripts/proxychains.template.conf new file mode 100644 index 000000000..e78b96a68 --- /dev/null +++ b/scripts/proxychains.template.conf @@ -0,0 +1,12 @@ +strict_chain +proxy_dns + +remote_dns_subnet 224 + +tcp_read_time_out 15000 +tcp_connect_time_out 8000 + +localnet 127.0.0.0/255.0.0.0 + +[ProxyList] +socks4 127.0.0.1 9050 From ea3e8a7459db28ca201aada341e54137e43cebb4 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sun, 16 Apr 2023 18:11:09 +0800 Subject: [PATCH 18/35] fix: #829 filter empty prompt --- app/store/prompt.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/store/prompt.ts b/app/store/prompt.ts index d0dd454ac..648b38145 100644 --- a/app/store/prompt.ts +++ b/app/store/prompt.ts @@ -116,10 +116,9 @@ export const usePromptStore = create()( }) .concat([...(state?.prompts?.values() ?? [])]); - const allPromptsForSearch = builtinPrompts.reduce( - (pre, cur) => pre.concat(cur), - [], - ); + const allPromptsForSearch = builtinPrompts + .reduce((pre, cur) => pre.concat(cur), []) + .filter((v) => !!v.title && !!v.content); SearchService.count.builtin = res.en.length + res.cn.length; SearchService.init(allPromptsForSearch); }); From 124938ecc9d0e015ed1a0cd3185395fec34de08d Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sun, 16 Apr 2023 18:17:46 +0800 Subject: [PATCH 19/35] fix: #832 update nextjs version to 13.3.0 --- package.json | 2 +- yarn.lock | 145 ++++++++++++++++++++++++--------------------------- 2 files changed, 68 insertions(+), 79 deletions(-) diff --git a/package.json b/package.json index 9a3e6d41c..acca33ce2 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "emoji-picker-react": "^4.4.7", "eventsource-parser": "^0.1.0", "fuse.js": "^6.6.2", - "next": "^13.2.3", + "next": "^13.3.0", "node-fetch": "^3.3.1", "openai": "^3.2.1", "react": "^18.2.0", diff --git a/yarn.lock b/yarn.lock index 88aa59823..f1f5bf2f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1099,10 +1099,10 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@next/env@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/env/-/env-13.2.4.tgz#8b763700262b2445140a44a8c8d088cef676dbae" - integrity sha512-+Mq3TtpkeeKFZanPturjcXt+KHfKYnLlX6jMLyCrmpq6OOs4i1GqBOAauSkii9QeKCMTYzGppar21JU57b/GEA== +"@next/env@13.3.0": + version "13.3.0" + resolved "https://registry.npmmirror.com/@next/env/-/env-13.3.0.tgz#cc2e49f03060a4684ce7ec7fd617a21bc5b9edba" + integrity sha512-AjppRV4uG3No7L1plinoTQETH+j2F10TEnrMfzbTUYwze5sBUPveeeBAPZPm8OkJZ1epq9OyYKhZrvbD6/9HCQ== "@next/eslint-plugin-next@13.2.3": version "13.2.3" @@ -1111,70 +1111,50 @@ dependencies: glob "7.1.7" -"@next/swc-android-arm-eabi@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.2.4.tgz#758d0403771e549f9cee71cbabc0cb16a6c947c0" - integrity sha512-DWlalTSkLjDU11MY11jg17O1gGQzpRccM9Oes2yTqj2DpHndajrXHGxj9HGtJ+idq2k7ImUdJVWS2h2l/EDJOw== +"@next/swc-darwin-arm64@13.3.0": + version "13.3.0" + resolved "https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.3.0.tgz#38f18e0639cd4c7edc6a38d4b83fe00f38eea4f2" + integrity sha512-DmIQCNq6JtccLPPBzf0dgh2vzMWt5wjxbP71pCi5EWpWYE3MsP6FcRXi4MlAmFNDQOfcFXR2r7kBeG1LpZUh1w== -"@next/swc-android-arm64@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-13.2.4.tgz#834d586523045110d5602e0c8aae9028835ac427" - integrity sha512-sRavmUImUCf332Gy+PjIfLkMhiRX1Ez4SI+3vFDRs1N5eXp+uNzjFUK/oLMMOzk6KFSkbiK/3Wt8+dHQR/flNg== +"@next/swc-darwin-x64@13.3.0": + version "13.3.0" + resolved "https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.3.0.tgz#b670ed1fd1d231aa21279173ec52e3ad56dc6aeb" + integrity sha512-oQoqFa88OGgwnYlnAGHVct618FRI/749se0N3S8t9Bzdv5CRbscnO0RcX901+YnNK4Q6yeiizfgO3b7kogtsZg== -"@next/swc-darwin-arm64@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.2.4.tgz#5006fca179a36ef3a24d293abadec7438dbb48c6" - integrity sha512-S6vBl+OrInP47TM3LlYx65betocKUUlTZDDKzTiRDbsRESeyIkBtZ6Qi5uT2zQs4imqllJznVjFd1bXLx3Aa6A== +"@next/swc-linux-arm64-gnu@13.3.0": + version "13.3.0" + resolved "https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.3.0.tgz#b114935f6b4c94c123f6cac55a4823d483209ba5" + integrity sha512-Wzz2p/WqAJUqTVoLo6H18WMeAXo3i+9DkPDae4oQG8LMloJ3if4NEZTnOnTUlro6cq+S/W4pTGa97nWTrOjbGw== -"@next/swc-darwin-x64@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.2.4.tgz#6549c7c04322766acc3264ccdb3e1b43fcaf7946" - integrity sha512-a6LBuoYGcFOPGd4o8TPo7wmv5FnMr+Prz+vYHopEDuhDoMSHOnC+v+Ab4D7F0NMZkvQjEJQdJS3rqgFhlZmKlw== +"@next/swc-linux-arm64-musl@13.3.0": + version "13.3.0" + resolved "https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.3.0.tgz#67a57309f8761c7d00d629d6785d56ed0567a0d2" + integrity sha512-xPVrIQOQo9WXJYgmoTlMnAD/HlR/1e1ZIWGbwIzEirXBVBqMARUulBEIKdC19zuvoJ477qZJgBDCKtKEykCpyQ== -"@next/swc-freebsd-x64@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.2.4.tgz#0bbe28979e3e868debc2cc06e45e186ce195b7f4" - integrity sha512-kkbzKVZGPaXRBPisoAQkh3xh22r+TD+5HwoC5bOkALraJ0dsOQgSMAvzMXKsN3tMzJUPS0tjtRf1cTzrQ0I5vQ== +"@next/swc-linux-x64-gnu@13.3.0": + version "13.3.0" + resolved "https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.3.0.tgz#11bd2bea7c00b40be111c0dd16e71171f3792086" + integrity sha512-jOFlpGuPD7W2tuXVJP4wt9a3cpNxWAPcloq5EfMJRiXsBBOjLVFZA7boXYxEBzSVgUiVVr1V9T0HFM7pULJ1qA== -"@next/swc-linux-arm-gnueabihf@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.2.4.tgz#1d28d2203f5a7427d6e7119d7bcb5fc40959fb3e" - integrity sha512-7qA1++UY0fjprqtjBZaOA6cas/7GekpjVsZn/0uHvquuITFCdKGFCsKNBx3S0Rpxmx6WYo0GcmhNRM9ru08BGg== +"@next/swc-linux-x64-musl@13.3.0": + version "13.3.0" + resolved "https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.3.0.tgz#d57e99f85890799b78719c3ea32a4624de8d701b" + integrity sha512-2OwKlzaBgmuet9XYHc3KwsEilzb04F540rlRXkAcjMHL7eCxB7uZIGtsVvKOnQLvC/elrUegwSw1+5f7WmfyOw== -"@next/swc-linux-arm64-gnu@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.2.4.tgz#eb26448190948cdf4c44b8f34110a3ecea32f1d0" - integrity sha512-xzYZdAeq883MwXgcwc72hqo/F/dwUxCukpDOkx/j1HTq/J0wJthMGjinN9wH5bPR98Mfeh1MZJ91WWPnZOedOg== +"@next/swc-win32-arm64-msvc@13.3.0": + version "13.3.0" + resolved "https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.3.0.tgz#0c209aa35d1c88b01e78259a89cd68f4139b5093" + integrity sha512-OeHiA6YEvndxT46g+rzFK/MQTfftKxJmzslERMu9LDdC6Kez0bdrgEYed5eXFK2Z1viKZJCGRlhd06rBusyztA== -"@next/swc-linux-arm64-musl@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.2.4.tgz#c4227c0acd94a420bb14924820710e6284d234d3" - integrity sha512-8rXr3WfmqSiYkb71qzuDP6I6R2T2tpkmf83elDN8z783N9nvTJf2E7eLx86wu2OJCi4T05nuxCsh4IOU3LQ5xw== +"@next/swc-win32-ia32-msvc@13.3.0": + version "13.3.0" + resolved "https://registry.npmmirror.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.3.0.tgz#52ae74da1dd6d840c3743923367d27ed013803dd" + integrity sha512-4aB7K9mcVK1lYEzpOpqWrXHEZympU3oK65fnNcY1Qc4HLJFLJj8AViuqQd4jjjPNuV4sl8jAwTz3gN5VNGWB7w== -"@next/swc-linux-x64-gnu@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.4.tgz#6bcb540944ee9b0209b33bfc23b240c2044dfc3e" - integrity sha512-Ngxh51zGSlYJ4EfpKG4LI6WfquulNdtmHg1yuOYlaAr33KyPJp4HeN/tivBnAHcZkoNy0hh/SbwDyCnz5PFJQQ== - -"@next/swc-linux-x64-musl@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.4.tgz#ce21e43251eaf09a09df39372b2c3e38028c30ff" - integrity sha512-gOvwIYoSxd+j14LOcvJr+ekd9fwYT1RyMAHOp7znA10+l40wkFiMONPLWiZuHxfRk+Dy7YdNdDh3ImumvL6VwA== - -"@next/swc-win32-arm64-msvc@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.2.4.tgz#68220063d8e5e082f5465498675640dedb670ff1" - integrity sha512-q3NJzcfClgBm4HvdcnoEncmztxrA5GXqKeiZ/hADvC56pwNALt3ngDC6t6qr1YW9V/EPDxCYeaX4zYxHciW4Dw== - -"@next/swc-win32-ia32-msvc@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.2.4.tgz#7c120ab54a081be9566df310bed834f168252990" - integrity sha512-/eZ5ncmHUYtD2fc6EUmAIZlAJnVT2YmxDsKs1Ourx0ttTtvtma/WKlMV5NoUsyOez0f9ExLyOpeCoz5aj+MPXw== - -"@next/swc-win32-x64-msvc@13.2.4": - version "13.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.4.tgz#5abda92fe12b9829bf7951c4a221282c56041144" - integrity sha512-0MffFmyv7tBLlji01qc0IaPP/LVExzvj7/R5x1Jph1bTAIj4Vu81yFQWHHQAP6r4ff9Ukj1mBK6MDNVXm7Tcvw== +"@next/swc-win32-x64-msvc@13.3.0": + version "13.3.0" + resolved "https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.3.0.tgz#db7b55fee834dc8c2c484c696469e65bae2ee770" + integrity sha512-Reer6rkLLcoOvB0dd66+Y7WrWVFH7sEEkF/4bJCIfsSKnTStTYaHtwIJAwbqnt9I392Tqvku0KkoqZOryWV9LQ== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1730,6 +1710,13 @@ browserslist@^4.21.3, browserslist@^4.21.5: node-releases "^2.0.8" update-browserslist-db "^1.0.10" +busboy@1.6.0: + version "1.6.0" + resolved "https://registry.npmmirror.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -3937,30 +3924,27 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -next@^13.2.3: - version "13.2.4" - resolved "https://registry.yarnpkg.com/next/-/next-13.2.4.tgz#2363330392b0f7da02ab41301f60857ffa7f67d6" - integrity sha512-g1I30317cThkEpvzfXujf0O4wtaQHtDCLhlivwlTJ885Ld+eOgcz7r3TGQzeU+cSRoNHtD8tsJgzxVdYojFssw== +next@^13.3.0: + version "13.3.0" + resolved "https://registry.npmmirror.com/next/-/next-13.3.0.tgz#40632d303d74fc8521faa0a5bf4a033a392749b1" + integrity sha512-OVTw8MpIPa12+DCUkPqRGPS3thlJPcwae2ZL4xti3iBff27goH024xy4q2lhlsdoYiKOi8Kz6uJoLW/GXwgfOA== dependencies: - "@next/env" "13.2.4" + "@next/env" "13.3.0" "@swc/helpers" "0.4.14" + busboy "1.6.0" caniuse-lite "^1.0.30001406" postcss "8.4.14" styled-jsx "5.1.1" optionalDependencies: - "@next/swc-android-arm-eabi" "13.2.4" - "@next/swc-android-arm64" "13.2.4" - "@next/swc-darwin-arm64" "13.2.4" - "@next/swc-darwin-x64" "13.2.4" - "@next/swc-freebsd-x64" "13.2.4" - "@next/swc-linux-arm-gnueabihf" "13.2.4" - "@next/swc-linux-arm64-gnu" "13.2.4" - "@next/swc-linux-arm64-musl" "13.2.4" - "@next/swc-linux-x64-gnu" "13.2.4" - "@next/swc-linux-x64-musl" "13.2.4" - "@next/swc-win32-arm64-msvc" "13.2.4" - "@next/swc-win32-ia32-msvc" "13.2.4" - "@next/swc-win32-x64-msvc" "13.2.4" + "@next/swc-darwin-arm64" "13.3.0" + "@next/swc-darwin-x64" "13.3.0" + "@next/swc-linux-arm64-gnu" "13.3.0" + "@next/swc-linux-arm64-musl" "13.3.0" + "@next/swc-linux-x64-gnu" "13.3.0" + "@next/swc-linux-x64-musl" "13.3.0" + "@next/swc-win32-arm64-msvc" "13.3.0" + "@next/swc-win32-ia32-msvc" "13.3.0" + "@next/swc-win32-x64-msvc" "13.3.0" node-domexception@^1.0.0: version "1.0.0" @@ -4668,6 +4652,11 @@ stop-iteration-iterator@^1.0.0: dependencies: internal-slot "^1.0.4" +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + string-argv@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" From 12d4081311f22ee2b9de30292b1be8aa5c69e6dd Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sun, 16 Apr 2023 18:55:29 +0800 Subject: [PATCH 20/35] feat: close #539 add delete message button --- app/components/chat.tsx | 68 ++++++++++++++++++++++++++++++----------- app/locales/cn.ts | 1 + app/locales/de.ts | 1 + app/locales/en.ts | 1 + app/locales/es.ts | 1 + app/locales/index.ts | 24 +++++---------- app/locales/it.ts | 1 + app/locales/jp.ts | 3 +- app/locales/tr.ts | 1 + app/locales/tw.ts | 1 + app/store/app.ts | 1 + 11 files changed, 66 insertions(+), 37 deletions(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 9e4a2bd9a..991ef312e 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -536,21 +536,45 @@ export function Chat(props: { } }; - const onResend = (botIndex: number) => { + const findLastUesrIndex = (messageId: number) => { // find last user input message and resend - for (let i = botIndex; i >= 0; i -= 1) { - if (messages[i].role === "user") { - setIsLoading(true); - chatStore - .onUserInput(messages[i].content) - .then(() => setIsLoading(false)); - chatStore.updateCurrentSession((session) => - session.messages.splice(i, 2), - ); - inputRef.current?.focus(); - return; + let lastUserMessageIndex: number | null = null; + for (let i = 0; i < session.messages.length; i += 1) { + const message = session.messages[i]; + if (message.id === messageId) { + break; + } + if (message.role === "user") { + lastUserMessageIndex = i; } } + + return lastUserMessageIndex; + }; + + const deleteMessage = (userIndex: number) => { + chatStore.updateCurrentSession((session) => + session.messages.splice(userIndex, 2), + ); + }; + + const onDelete = (botMessageId: number) => { + const userIndex = findLastUesrIndex(botMessageId); + if (userIndex === null) return; + deleteMessage(userIndex); + }; + + const onResend = (botMessageId: number) => { + // find last user input message and resend + const userIndex = findLastUesrIndex(botMessageId); + if (userIndex === null) return; + + setIsLoading(true); + chatStore + .onUserInput(session.messages[userIndex].content) + .then(() => setIsLoading(false)); + deleteMessage(userIndex); + inputRef.current?.focus(); }; const config = useChatStore((state) => state.config); @@ -722,12 +746,20 @@ export function Chat(props: { {Locale.Chat.Actions.Stop}
) : ( -
onResend(i)} - > - {Locale.Chat.Actions.Retry} -
+ <> +
onDelete(message.id ?? i)} + > + {Locale.Chat.Actions.Delete} +
+
onResend(message.id ?? i)} + > + {Locale.Chat.Actions.Retry} +
+ )}
()( const botMessage: Message = createMessage({ role: "assistant", streaming: true, + id: userMessage.id! + 1, }); // get recent messages From 2979df1d82a86046c07283b83b071df3db60d6e0 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Mon, 17 Apr 2023 11:17:05 +0800 Subject: [PATCH 21/35] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index a6288798a..53706900d 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,9 @@ bash <(curl -s https://raw.githubusercontent.com/Yidadaa/ChatGPT-Next-Web/main/s [@chazzhou](https://github.com/chazzhou) [@hauy](https://github.com/hauy) [@Corwin006](https://github.com/Corwin006) +[@yankunsong](https://github.com/yankunsong) +[@ypwhs](https://github.com/ypwhs) +[@fxxxchao](https://github.com/fxxxchao) ### Contributor From cc053b148d6487c83a2dd647059e0cfa7314fe16 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Mon, 17 Apr 2023 11:27:31 +0800 Subject: [PATCH 22/35] fix: #853 fetch duplex errors --- app/api/common.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/api/common.ts b/app/api/common.ts index 53ab18ed6..089dbf02a 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -25,5 +25,6 @@ export async function requestOpenai(req: NextRequest) { }, method: req.method, body: req.body, + duplex: !!req.body, }); } From 76ef5ef9a9872e1d3f30e9d201d9ac2546010156 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Mon, 17 Apr 2023 11:34:33 +0800 Subject: [PATCH 23/35] fixup --- app/api/common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/common.ts b/app/api/common.ts index 089dbf02a..65870ee91 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -25,6 +25,6 @@ export async function requestOpenai(req: NextRequest) { }, method: req.method, body: req.body, - duplex: !!req.body, + duplex: !!req.body ? "half" : "", }); } From b79845fcaa5fce0da272b88564bf02d8252570c0 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Mon, 17 Apr 2023 11:36:32 +0800 Subject: [PATCH 24/35] fixup --- app/api/common.ts | 1 - app/api/openai/route.ts | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/api/common.ts b/app/api/common.ts index 65870ee91..53ab18ed6 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -25,6 +25,5 @@ export async function requestOpenai(req: NextRequest) { }, method: req.method, body: req.body, - duplex: !!req.body ? "half" : "", }); } diff --git a/app/api/openai/route.ts b/app/api/openai/route.ts index 261c20a85..0ac94bdd5 100644 --- a/app/api/openai/route.ts +++ b/app/api/openai/route.ts @@ -17,7 +17,7 @@ async function makeRequest(req: NextRequest) { }, { status: 500, - }, + } ); } } @@ -29,3 +29,7 @@ export async function POST(req: NextRequest) { export async function GET(req: NextRequest) { return makeRequest(req); } + +export const config = { + runtime: "edge", +}; From 64e78329ec4650300d49d12641880f43a8226e98 Mon Sep 17 00:00:00 2001 From: Ma Yuke Date: Mon, 17 Apr 2023 11:51:51 +0800 Subject: [PATCH 25/35] Update app/requests.ts fix: displaying the number of subscription beyond two decimal places. --- app/requests.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/requests.ts b/app/requests.ts index db91f6fc3..af718f234 100644 --- a/app/requests.ts +++ b/app/requests.ts @@ -113,6 +113,10 @@ export async function requestUsage() { if (response.total_usage) { response.total_usage = Math.round(response.total_usage) / 100; } + + if (total.hard_limit_usd) { + total.hard_limit_usd = Math.round(total.hard_limit_usd * 100) / 100; + } return { used: response.total_usage, From 3038dfdb278c3fa4bdc5e1aa6ce12aa7f1e8eae8 Mon Sep 17 00:00:00 2001 From: jaw <2135326728@qq.com> Date: Mon, 17 Apr 2023 15:37:03 +0800 Subject: [PATCH 26/35] fix: error in windows --- package.json | 2 +- yarn.lock | 108 +++++++++++++++++++++++++-------------------------- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/package.json b/package.json index acca33ce2..19047ad11 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "emoji-picker-react": "^4.4.7", "eventsource-parser": "^0.1.0", "fuse.js": "^6.6.2", - "next": "^13.3.0", + "next": "^13.3.1-canary.8", "node-fetch": "^3.3.1", "openai": "^3.2.1", "react": "^18.2.0", diff --git a/yarn.lock b/yarn.lock index f1f5bf2f7..342ea4a44 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1099,10 +1099,10 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@next/env@13.3.0": - version "13.3.0" - resolved "https://registry.npmmirror.com/@next/env/-/env-13.3.0.tgz#cc2e49f03060a4684ce7ec7fd617a21bc5b9edba" - integrity sha512-AjppRV4uG3No7L1plinoTQETH+j2F10TEnrMfzbTUYwze5sBUPveeeBAPZPm8OkJZ1epq9OyYKhZrvbD6/9HCQ== +"@next/env@13.3.1-canary.8": + version "13.3.1-canary.8" + resolved "https://registry.yarnpkg.com/@next/env/-/env-13.3.1-canary.8.tgz#9f5cf57999e4f4b59ef6407924803a247cc4e451" + integrity sha512-xZfNu7yq3OfiC4rkGuGMcqb25se+ZHRqajSdny8dp+nZzkNSK1SHuNT3W8faI+KGk6dqzO/zAdHR9YrqnQlCAg== "@next/eslint-plugin-next@13.2.3": version "13.2.3" @@ -1111,50 +1111,50 @@ dependencies: glob "7.1.7" -"@next/swc-darwin-arm64@13.3.0": - version "13.3.0" - resolved "https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.3.0.tgz#38f18e0639cd4c7edc6a38d4b83fe00f38eea4f2" - integrity sha512-DmIQCNq6JtccLPPBzf0dgh2vzMWt5wjxbP71pCi5EWpWYE3MsP6FcRXi4MlAmFNDQOfcFXR2r7kBeG1LpZUh1w== +"@next/swc-darwin-arm64@13.3.1-canary.8": + version "13.3.1-canary.8" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.3.1-canary.8.tgz#66786ba76d37c210c184739624c6f84eaf2dc52b" + integrity sha512-BLbvhcaSzwuXbREOmJiqAdXVD7Jl9830hDY5ZTTNg7hXqEZgoMg2LxAEmtaaBMVZRfDQjd5bH3QPBV8fbG4UKg== -"@next/swc-darwin-x64@13.3.0": - version "13.3.0" - resolved "https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.3.0.tgz#b670ed1fd1d231aa21279173ec52e3ad56dc6aeb" - integrity sha512-oQoqFa88OGgwnYlnAGHVct618FRI/749se0N3S8t9Bzdv5CRbscnO0RcX901+YnNK4Q6yeiizfgO3b7kogtsZg== +"@next/swc-darwin-x64@13.3.1-canary.8": + version "13.3.1-canary.8" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.3.1-canary.8.tgz#289296bd3cc55db7fef42037eb89ce4a6260ba31" + integrity sha512-n4tJKPIvFTZshS1TVWrsqaW7h9VW+BmguO/AlZ3Q3NJ9hWxC5L4lxn2T6CTQ4M30Gf+t5u+dPzYLQ5IDtJFnFQ== -"@next/swc-linux-arm64-gnu@13.3.0": - version "13.3.0" - resolved "https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.3.0.tgz#b114935f6b4c94c123f6cac55a4823d483209ba5" - integrity sha512-Wzz2p/WqAJUqTVoLo6H18WMeAXo3i+9DkPDae4oQG8LMloJ3if4NEZTnOnTUlro6cq+S/W4pTGa97nWTrOjbGw== +"@next/swc-linux-arm64-gnu@13.3.1-canary.8": + version "13.3.1-canary.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.3.1-canary.8.tgz#dc79e8005849b6482241b460abdce9334665c766" + integrity sha512-AxnsgZ56whwVAeejyEZMk8xc8Vapwzb3Zn0YdZzPCR42WKfkcSkM+AWfq33zUOZnjvCmQBDyfHIo4CURVweR6g== -"@next/swc-linux-arm64-musl@13.3.0": - version "13.3.0" - resolved "https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.3.0.tgz#67a57309f8761c7d00d629d6785d56ed0567a0d2" - integrity sha512-xPVrIQOQo9WXJYgmoTlMnAD/HlR/1e1ZIWGbwIzEirXBVBqMARUulBEIKdC19zuvoJ477qZJgBDCKtKEykCpyQ== +"@next/swc-linux-arm64-musl@13.3.1-canary.8": + version "13.3.1-canary.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.3.1-canary.8.tgz#f70873add4aad7ced36f760d1640adc008b7dc03" + integrity sha512-zc7rzhtrHMWZ/phvjCNplHGo+ZLembjtluI5J8Xl4iwQQCyZwAtnmQhs37/zkdi6dHZou+wcFBZWRz14awRDBw== -"@next/swc-linux-x64-gnu@13.3.0": - version "13.3.0" - resolved "https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.3.0.tgz#11bd2bea7c00b40be111c0dd16e71171f3792086" - integrity sha512-jOFlpGuPD7W2tuXVJP4wt9a3cpNxWAPcloq5EfMJRiXsBBOjLVFZA7boXYxEBzSVgUiVVr1V9T0HFM7pULJ1qA== +"@next/swc-linux-x64-gnu@13.3.1-canary.8": + version "13.3.1-canary.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.3.1-canary.8.tgz#fe81b8033628c6cf74e154f2db8c8c7f1593008f" + integrity sha512-vNbFDiuZ9fWmcznlilDbflZLb04evWPUQlyDT7Tqjd964PlSIaaX3tr64pdYjJOljDaqTr2Kbx0YW74mWF/PEw== -"@next/swc-linux-x64-musl@13.3.0": - version "13.3.0" - resolved "https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.3.0.tgz#d57e99f85890799b78719c3ea32a4624de8d701b" - integrity sha512-2OwKlzaBgmuet9XYHc3KwsEilzb04F540rlRXkAcjMHL7eCxB7uZIGtsVvKOnQLvC/elrUegwSw1+5f7WmfyOw== +"@next/swc-linux-x64-musl@13.3.1-canary.8": + version "13.3.1-canary.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.3.1-canary.8.tgz#ada4585046a7937f96f2d39fc4aaca12826dde5f" + integrity sha512-/FVBPJEBDZYCNraocRWtd5ObAgNi9VFnzJYGYDYIj4jKkFRWWm/CaWu9A7toQACC/JDy262uPyDPathXT9BAqQ== -"@next/swc-win32-arm64-msvc@13.3.0": - version "13.3.0" - resolved "https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.3.0.tgz#0c209aa35d1c88b01e78259a89cd68f4139b5093" - integrity sha512-OeHiA6YEvndxT46g+rzFK/MQTfftKxJmzslERMu9LDdC6Kez0bdrgEYed5eXFK2Z1viKZJCGRlhd06rBusyztA== +"@next/swc-win32-arm64-msvc@13.3.1-canary.8": + version "13.3.1-canary.8" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.3.1-canary.8.tgz#21b4f6c4be61845759753df9313bd9bcbb241969" + integrity sha512-8jMwRCeI26yVZLPwG0AjOi4b1yqSeqYmbHA7r+dqiV0OgFdYjnbyHU1FmiKDaC5SnnJN6LWV2Qjer9GDD0Kcuw== -"@next/swc-win32-ia32-msvc@13.3.0": - version "13.3.0" - resolved "https://registry.npmmirror.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.3.0.tgz#52ae74da1dd6d840c3743923367d27ed013803dd" - integrity sha512-4aB7K9mcVK1lYEzpOpqWrXHEZympU3oK65fnNcY1Qc4HLJFLJj8AViuqQd4jjjPNuV4sl8jAwTz3gN5VNGWB7w== +"@next/swc-win32-ia32-msvc@13.3.1-canary.8": + version "13.3.1-canary.8" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.3.1-canary.8.tgz#e23192e1d1b1a32b0eb805363b02360c5b523a77" + integrity sha512-kcYB9iSEikFhv0I9uQDdgQ2lm8i3O8LA+GhnED9e5VtURBwOSwED7c6ZpaRQBYSPgnEA9/xiJVChICE/I7Ig1g== -"@next/swc-win32-x64-msvc@13.3.0": - version "13.3.0" - resolved "https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.3.0.tgz#db7b55fee834dc8c2c484c696469e65bae2ee770" - integrity sha512-Reer6rkLLcoOvB0dd66+Y7WrWVFH7sEEkF/4bJCIfsSKnTStTYaHtwIJAwbqnt9I392Tqvku0KkoqZOryWV9LQ== +"@next/swc-win32-x64-msvc@13.3.1-canary.8": + version "13.3.1-canary.8" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.3.1-canary.8.tgz#a3f29404955cba2193de5e74fd5d9fcfdcb0ab51" + integrity sha512-UKrGHonKVWBNg+HI4J8pXE6Jjjl8GwjhygFau71s8M0+jSy99y5Y+nGH9EmMNWKNvrObukyYvrs6OsAusKdCqw== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -3924,27 +3924,27 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -next@^13.3.0: - version "13.3.0" - resolved "https://registry.npmmirror.com/next/-/next-13.3.0.tgz#40632d303d74fc8521faa0a5bf4a033a392749b1" - integrity sha512-OVTw8MpIPa12+DCUkPqRGPS3thlJPcwae2ZL4xti3iBff27goH024xy4q2lhlsdoYiKOi8Kz6uJoLW/GXwgfOA== +next@^13.3.1-canary.8: + version "13.3.1-canary.8" + resolved "https://registry.yarnpkg.com/next/-/next-13.3.1-canary.8.tgz#f0846e5eada1491884326786a0749d5adc04c24d" + integrity sha512-z4QUgyAN+hSWSEqb4pvGvC3iRktE6NH2DVLU4AvfqNYpzP+prePiJC8HN/cJpFhGW9YbhyRLi5FliDC631OOag== dependencies: - "@next/env" "13.3.0" + "@next/env" "13.3.1-canary.8" "@swc/helpers" "0.4.14" busboy "1.6.0" caniuse-lite "^1.0.30001406" postcss "8.4.14" styled-jsx "5.1.1" optionalDependencies: - "@next/swc-darwin-arm64" "13.3.0" - "@next/swc-darwin-x64" "13.3.0" - "@next/swc-linux-arm64-gnu" "13.3.0" - "@next/swc-linux-arm64-musl" "13.3.0" - "@next/swc-linux-x64-gnu" "13.3.0" - "@next/swc-linux-x64-musl" "13.3.0" - "@next/swc-win32-arm64-msvc" "13.3.0" - "@next/swc-win32-ia32-msvc" "13.3.0" - "@next/swc-win32-x64-msvc" "13.3.0" + "@next/swc-darwin-arm64" "13.3.1-canary.8" + "@next/swc-darwin-x64" "13.3.1-canary.8" + "@next/swc-linux-arm64-gnu" "13.3.1-canary.8" + "@next/swc-linux-arm64-musl" "13.3.1-canary.8" + "@next/swc-linux-x64-gnu" "13.3.1-canary.8" + "@next/swc-linux-x64-musl" "13.3.1-canary.8" + "@next/swc-win32-arm64-msvc" "13.3.1-canary.8" + "@next/swc-win32-ia32-msvc" "13.3.1-canary.8" + "@next/swc-win32-x64-msvc" "13.3.1-canary.8" node-domexception@^1.0.0: version "1.0.0" From 525a2ff9a7e9b1be79a15972f138d092b71bf4de Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Mon, 17 Apr 2023 22:51:14 +0800 Subject: [PATCH 27/35] fix: #866 remove unused retry messages --- app/components/chat.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 991ef312e..3c66627f6 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -570,10 +570,9 @@ export function Chat(props: { if (userIndex === null) return; setIsLoading(true); - chatStore - .onUserInput(session.messages[userIndex].content) - .then(() => setIsLoading(false)); + const content = session.messages[userIndex].content; deleteMessage(userIndex); + chatStore.onUserInput(content).then(() => setIsLoading(false)); inputRef.current?.focus(); }; From fdc8278b90cdcacc8859df4740752a58d8829d8b Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Mon, 17 Apr 2023 23:12:27 +0800 Subject: [PATCH 28/35] feat: check usage throttle --- app/components/settings.module.scss | 11 ++++++++++ app/components/settings.tsx | 28 +++++++++++++++--------- app/requests.ts | 2 +- app/store/update.ts | 34 +++++++++++++++++++++-------- 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/app/components/settings.module.scss b/app/components/settings.module.scss index 830e1baeb..0628c6e3f 100644 --- a/app/components/settings.module.scss +++ b/app/components/settings.module.scss @@ -32,3 +32,14 @@ min-width: 80%; } } + +.user-prompt-modal { + .user-prompt-search { + } + + .user-prompt-list { + } + + .user-prompt-actions { + } +} diff --git a/app/components/settings.tsx b/app/components/settings.tsx index e418d4843..d5f26c3e6 100644 --- a/app/components/settings.tsx +++ b/app/components/settings.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useMemo, HTMLProps } from "react"; +import { useState, useEffect, useMemo, HTMLProps, useRef } from "react"; import EmojiPicker, { Theme as EmojiTheme } from "emoji-picker-react"; @@ -34,6 +34,15 @@ import { requestUsage } from "../requests"; import { ErrorBoundary } from "./error"; import { InputRange } from "./input-range"; +function UserPromptModal() { + const promptStore = usePromptStore(); + const prompts = Array.from(promptStore.prompts.values()).sort( + (a, b) => a.id ?? 0 - (b.id ?? 0), + ); + + return <>; +} + function SettingItem(props: { title: string; subTitle?: string; @@ -99,18 +108,16 @@ export function Settings(props: { closeSettings: () => void }) { }); } - const [usage, setUsage] = useState<{ - used?: number; - subscription?: number; - }>(); + const usage = { + used: updateStore.used, + subscription: updateStore.subscription, + }; const [loadingUsage, setLoadingUsage] = useState(false); function checkUsage() { setLoadingUsage(true); - requestUsage() - .then((res) => setUsage(res)) - .finally(() => { - setLoadingUsage(false); - }); + updateStore.updateUsage().finally(() => { + setLoadingUsage(false); + }); } const accessStore = useAccessStore(); @@ -126,6 +133,7 @@ export function Settings(props: { closeSettings: () => void }) { const showUsage = accessStore.isAuthorized(); useEffect(() => { + // checks per minutes checkUpdate(); showUsage && checkUsage(); // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/app/requests.ts b/app/requests.ts index af718f234..3cb838e63 100644 --- a/app/requests.ts +++ b/app/requests.ts @@ -113,7 +113,7 @@ export async function requestUsage() { if (response.total_usage) { response.total_usage = Math.round(response.total_usage) / 100; } - + if (total.hard_limit_usd) { total.hard_limit_usd = Math.round(total.hard_limit_usd * 100) / 100; } diff --git a/app/store/update.ts b/app/store/update.ts index efcdc8a7b..d49c246d1 100644 --- a/app/store/update.ts +++ b/app/store/update.ts @@ -1,13 +1,19 @@ import { create } from "zustand"; import { persist } from "zustand/middleware"; import { FETCH_COMMIT_URL, FETCH_TAG_URL } from "../constant"; +import { requestUsage } from "../requests"; export interface UpdateStore { lastUpdate: number; remoteVersion: string; + used?: number; + subscription?: number; + lastUpdateUsage: number; + version: string; - getLatestVersion: (force: boolean) => Promise; + getLatestVersion: (force?: boolean) => Promise; + updateUsage: (force?: boolean) => Promise; } export const UPDATE_KEY = "chat-update"; @@ -26,22 +32,23 @@ function queryMeta(key: string, defaultValue?: string): string { return ret; } +const ONE_MINUTE = 60 * 1000; + export const useUpdateStore = create()( persist( (set, get) => ({ lastUpdate: 0, remoteVersion: "", + lastUpdateUsage: 0, + version: "unknown", async getLatestVersion(force = false) { - set(() => ({ version: queryMeta("version") })); + set(() => ({ version: queryMeta("version") ?? "unknown" })); - const overTenMins = Date.now() - get().lastUpdate > 10 * 60 * 1000; - const shouldFetch = force || overTenMins; - if (!shouldFetch) { - return get().version ?? "unknown"; - } + const overTenMins = Date.now() - get().lastUpdate > 10 * ONE_MINUTE; + if (!force && !overTenMins) return; try { // const data = await (await fetch(FETCH_TAG_URL)).json(); @@ -53,10 +60,19 @@ export const useUpdateStore = create()( remoteVersion: remoteId, })); console.log("[Got Upstream] ", remoteId); - return remoteId; } catch (error) { console.error("[Fetch Upstream Commit Id]", error); - return get().version ?? ""; + } + }, + + async updateUsage(force = false) { + const overOneMinute = Date.now() - get().lastUpdateUsage >= ONE_MINUTE; + if (!overOneMinute && !force) return; + + const usage = await requestUsage(); + + if (usage) { + set(() => usage); } }, }), From 789a77977525eb06be52c329a7a65ad47e6babfc Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 18 Apr 2023 01:34:12 +0800 Subject: [PATCH 29/35] feat: user prompts --- app/components/settings.module.scss | 49 ++++++++++++ app/components/settings.tsx | 119 +++++++++++++++++++++++++--- app/components/ui-lib.module.scss | 2 +- app/locales/cn.ts | 9 ++- app/locales/de.ts | 5 ++ app/locales/en.ts | 7 +- app/locales/es.ts | 5 ++ app/locales/it.ts | 5 ++ app/locales/jp.ts | 5 ++ app/locales/tr.ts | 5 ++ app/locales/tw.ts | 5 ++ app/store/prompt.ts | 79 +++++++++++++----- app/store/update.ts | 9 ++- app/styles/globals.scss | 2 + 14 files changed, 269 insertions(+), 37 deletions(-) diff --git a/app/components/settings.module.scss b/app/components/settings.module.scss index 0628c6e3f..b7f095580 100644 --- a/app/components/settings.module.scss +++ b/app/components/settings.module.scss @@ -34,10 +34,59 @@ } .user-prompt-modal { + min-height: 40vh; + .user-prompt-search { + width: 100%; + max-width: 100%; + margin-bottom: 10px; + background-color: var(--gray); } .user-prompt-list { + padding: 10px 0; + + .user-prompt-item { + margin-bottom: 10px; + widows: 100%; + + .user-prompt-header { + display: flex; + widows: 100%; + margin-bottom: 5px; + + .user-prompt-title { + flex-grow: 1; + max-width: 100%; + margin-right: 5px; + padding: 5px; + font-size: 12px; + text-align: left; + } + + .user-prompt-buttons { + display: flex; + align-items: center; + + .user-prompt-button { + height: 100%; + + &:not(:last-child) { + margin-right: 5px; + } + } + } + } + + .user-prompt-content { + width: 100%; + box-sizing: border-box; + padding: 5px; + margin-right: 10px; + font-size: 12px; + flex-grow: 1; + } + } } .user-prompt-actions { diff --git a/app/components/settings.tsx b/app/components/settings.tsx index d5f26c3e6..d81b5b358 100644 --- a/app/components/settings.tsx +++ b/app/components/settings.tsx @@ -6,12 +6,13 @@ import styles from "./settings.module.scss"; import ResetIcon from "../icons/reload.svg"; import CloseIcon from "../icons/close.svg"; +import CopyIcon from "../icons/copy.svg"; import ClearIcon from "../icons/clear.svg"; import EditIcon from "../icons/edit.svg"; import EyeIcon from "../icons/eye.svg"; import EyeOffIcon from "../icons/eye-off.svg"; -import { List, ListItem, Popover, showToast } from "./ui-lib"; +import { Input, List, ListItem, Modal, Popover } from "./ui-lib"; import { IconButton } from "./button"; import { @@ -26,21 +27,112 @@ import { import { Avatar } from "./chat"; import Locale, { AllLangs, changeLang, getLang } from "../locales"; -import { getEmojiUrl } from "../utils"; +import { copyToClipboard, getEmojiUrl } from "../utils"; import Link from "next/link"; import { UPDATE_URL } from "../constant"; -import { SearchService, usePromptStore } from "../store/prompt"; -import { requestUsage } from "../requests"; +import { Prompt, SearchService, usePromptStore } from "../store/prompt"; import { ErrorBoundary } from "./error"; import { InputRange } from "./input-range"; -function UserPromptModal() { +function UserPromptModal(props: { onClose?: () => void }) { const promptStore = usePromptStore(); - const prompts = Array.from(promptStore.prompts.values()).sort( - (a, b) => a.id ?? 0 - (b.id ?? 0), - ); + const userPrompts = promptStore.getUserPrompts(); + const builtinPrompts = SearchService.builtinPrompts; + const allPrompts = userPrompts.concat(builtinPrompts); + const [searchInput, setSearchInput] = useState(""); + const [searchPrompts, setSearchPrompts] = useState([]); + const prompts = searchInput.length > 0 ? searchPrompts : allPrompts; - return <>; + useEffect(() => { + if (searchInput.length > 0) { + const searchResult = SearchService.search(searchInput); + setSearchPrompts(searchResult); + } else { + setSearchPrompts([]); + } + }, [searchInput]); + + return ( +
+ props.onClose?.()} + actions={[ + promptStore.add({ title: "", content: "" })} + icon={} + bordered + text={Locale.Settings.Prompt.Modal.Add} + />, + ]} + > +
+ setSearchInput(e.currentTarget.value)} + > + +
+ {prompts.map((v, _) => ( +
+
+ { + if (v.isUser) { + promptStore.updateUserPrompts( + v.id!, + (prompt) => (prompt.title = e.currentTarget.value), + ); + } + }} + > + +
+ {v.isUser && ( + } + bordered + className={styles["user-prompt-button"]} + onClick={() => promptStore.remove(v.id!)} + /> + )} + } + bordered + className={styles["user-prompt-button"]} + onClick={() => copyToClipboard(v.content)} + /> +
+
+ { + if (v.isUser) { + promptStore.updateUserPrompts( + v.id!, + (prompt) => (prompt.content = e.currentTarget.value), + ); + } + }} + /> +
+ ))} +
+
+
+
+ ); } function SettingItem(props: { @@ -129,7 +221,8 @@ export function Settings(props: { closeSettings: () => void }) { const promptStore = usePromptStore(); const builtinCount = SearchService.count.builtin; - const customCount = promptStore.prompts.size ?? 0; + const customCount = promptStore.getUserPrompts().length ?? 0; + const [shouldShowPromptModal, setShowPromptModal] = useState(false); const showUsage = accessStore.isAuthorized(); useEffect(() => { @@ -477,7 +570,7 @@ export function Settings(props: { closeSettings: () => void }) { } text={Locale.Settings.Prompt.Edit} - onClick={() => showToast(Locale.WIP)} + onClick={() => setShowPromptModal(true)} /> @@ -563,6 +656,10 @@ export function Settings(props: { closeSettings: () => void }) { > + + {shouldShowPromptModal && ( + setShowPromptModal(false)} /> + )}
); diff --git a/app/components/ui-lib.module.scss b/app/components/ui-lib.module.scss index 457c55049..8965c06a0 100644 --- a/app/components/ui-lib.module.scss +++ b/app/components/ui-lib.module.scss @@ -53,7 +53,7 @@ box-shadow: var(--card-shadow); background-color: var(--white); border-radius: 12px; - width: 50vw; + width: 60vw; animation: slide-in ease 0.3s; --modal-padding: 20px; diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 391ade2ab..d0ab27ca2 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -59,10 +59,10 @@ const cn = { ResetAll: "重置所有选项", Close: "关闭", ConfirmResetAll: { - Confirm: "Are you sure you want to reset all configurations?", + Confirm: "确认清除所有配置?", }, ConfirmClearAll: { - Confirm: "Are you sure you want to reset all chat?", + Confirm: "确认清除所有聊天记录?", }, }, Lang: { @@ -105,6 +105,11 @@ const cn = { ListCount: (builtin: number, custom: number) => `内置 ${builtin} 条,用户定义 ${custom} 条`, Edit: "编辑", + Modal: { + Title: "提示词列表", + Add: "增加一条", + Search: "搜尋提示詞", + }, }, HistoryCount: { Title: "附带历史消息数", diff --git a/app/locales/de.ts b/app/locales/de.ts index d373cba50..e71abfaf7 100644 --- a/app/locales/de.ts +++ b/app/locales/de.ts @@ -107,6 +107,11 @@ const de: LocaleType = { ListCount: (builtin: number, custom: number) => `${builtin} integriert, ${custom} benutzerdefiniert`, Edit: "Bearbeiten", + Modal: { + Title: "Prompt List", + Add: "Add One", + Search: "Search Prompts", + }, }, HistoryCount: { Title: "Anzahl der angehängten Nachrichten", diff --git a/app/locales/en.ts b/app/locales/en.ts index 213b02d3e..20e569606 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -107,6 +107,11 @@ const en: LocaleType = { ListCount: (builtin: number, custom: number) => `${builtin} built-in, ${custom} user-defined`, Edit: "Edit", + Modal: { + Title: "Prompt List", + Add: "Add One", + Search: "Search Prompts", + }, }, HistoryCount: { Title: "Attached Messages Count", @@ -128,7 +133,7 @@ const en: LocaleType = { return `Used this month $${used}, subscription $${total}`; }, IsChecking: "Checking...", - Check: "Check Again", + Check: "Check", NoAccess: "Enter API Key to check balance", }, AccessCode: { diff --git a/app/locales/es.ts b/app/locales/es.ts index 5d6eca17a..e2a9eb211 100644 --- a/app/locales/es.ts +++ b/app/locales/es.ts @@ -107,6 +107,11 @@ const es: LocaleType = { ListCount: (builtin: number, custom: number) => `${builtin} incorporado, ${custom} definido por el usuario`, Edit: "Editar", + Modal: { + Title: "Prompt List", + Add: "Add One", + Search: "Search Prompts", + }, }, HistoryCount: { Title: "Cantidad de mensajes adjuntos", diff --git a/app/locales/it.ts b/app/locales/it.ts index 225238888..f0453b5c3 100644 --- a/app/locales/it.ts +++ b/app/locales/it.ts @@ -107,6 +107,11 @@ const it: LocaleType = { ListCount: (builtin: number, custom: number) => `${builtin} built-in, ${custom} user-defined`, Edit: "Modifica", + Modal: { + Title: "Prompt List", + Add: "Add One", + Search: "Search Prompts", + }, }, HistoryCount: { Title: "Conteggio dei messaggi allegati", diff --git a/app/locales/jp.ts b/app/locales/jp.ts index f4ad741c9..a793b5fe0 100644 --- a/app/locales/jp.ts +++ b/app/locales/jp.ts @@ -108,6 +108,11 @@ const jp = { ListCount: (builtin: number, custom: number) => `組み込み ${builtin} 件、ユーザー定義 ${custom} 件`, Edit: "編集", + Modal: { + Title: "提示词列表", + Add: "增加一条", + Search: "搜尋提示詞", + }, }, HistoryCount: { Title: "履歴メッセージ数を添付", diff --git a/app/locales/tr.ts b/app/locales/tr.ts index a7ede1926..04a846245 100644 --- a/app/locales/tr.ts +++ b/app/locales/tr.ts @@ -107,6 +107,11 @@ const tr: LocaleType = { ListCount: (builtin: number, custom: number) => `${builtin} yerleşik, ${custom} kullanıcı tanımlı`, Edit: "Düzenle", + Modal: { + Title: "Prompt List", + Add: "Add One", + Search: "Search Prompts", + }, }, HistoryCount: { Title: "Ekli Mesaj Sayısı", diff --git a/app/locales/tw.ts b/app/locales/tw.ts index 1397bb098..2fbb2e477 100644 --- a/app/locales/tw.ts +++ b/app/locales/tw.ts @@ -105,6 +105,11 @@ const tw: LocaleType = { ListCount: (builtin: number, custom: number) => `內置 ${builtin} 條,用戶定義 ${custom} 條`, Edit: "編輯", + Modal: { + Title: "提示詞列表", + Add: "增加一條", + Search: "搜索提示词", + }, }, HistoryCount: { Title: "附帶歷史訊息數", diff --git a/app/store/prompt.ts b/app/store/prompt.ts index 648b38145..8d754ff5d 100644 --- a/app/store/prompt.ts +++ b/app/store/prompt.ts @@ -5,62 +5,74 @@ import { getLang } from "../locales"; export interface Prompt { id?: number; + isUser?: boolean; title: string; content: string; } export interface PromptStore { + counter: number; latestId: number; - prompts: Map; + prompts: Record; add: (prompt: Prompt) => number; remove: (id: number) => void; search: (text: string) => Prompt[]; + + getUserPrompts: () => Prompt[]; + updateUserPrompts: (id: number, updater: (prompt: Prompt) => void) => void; } export const PROMPT_KEY = "prompt-store"; export const SearchService = { ready: false, - engine: new Fuse([], { keys: ["title"] }), + builtinEngine: new Fuse([], { keys: ["title"] }), + userEngine: new Fuse([], { keys: ["title"] }), count: { builtin: 0, }, - allBuiltInPrompts: [] as Prompt[], + allPrompts: [] as Prompt[], + builtinPrompts: [] as Prompt[], - init(prompts: Prompt[]) { + init(builtinPrompts: Prompt[], userPrompts: Prompt[]) { if (this.ready) { return; } - this.allBuiltInPrompts = prompts; - this.engine.setCollection(prompts); + this.allPrompts = userPrompts.concat(builtinPrompts); + this.builtinPrompts = builtinPrompts.slice(); + this.builtinEngine.setCollection(builtinPrompts); + this.userEngine.setCollection(userPrompts); this.ready = true; }, remove(id: number) { - this.engine.remove((doc) => doc.id === id); + this.userEngine.remove((doc) => doc.id === id); }, add(prompt: Prompt) { - this.engine.add(prompt); + this.userEngine.add(prompt); }, search(text: string) { - const results = this.engine.search(text); - return results.map((v) => v.item); + const userResults = this.userEngine.search(text); + const builtinResults = this.builtinEngine.search(text); + return userResults.concat(builtinResults).map((v) => v.item); }, }; export const usePromptStore = create()( persist( (set, get) => ({ + counter: 0, latestId: 0, - prompts: new Map(), + prompts: {}, add(prompt) { const prompts = get().prompts; prompt.id = get().latestId + 1; - prompts.set(prompt.id, prompt); + prompt.isUser = true; + prompts[prompt.id] = prompt; set(() => ({ latestId: prompt.id!, @@ -72,19 +84,40 @@ export const usePromptStore = create()( remove(id) { const prompts = get().prompts; - prompts.delete(id); + delete prompts[id]; SearchService.remove(id); set(() => ({ prompts, + counter: get().counter + 1, })); }, + getUserPrompts() { + const userPrompts = Object.values(get().prompts ?? {}); + userPrompts.sort((a, b) => (b.id && a.id ? b.id - a.id : 0)); + return userPrompts; + }, + + updateUserPrompts(id: number, updater) { + const prompt = get().prompts[id] ?? { + title: "", + content: "", + id, + }; + + SearchService.remove(id); + updater(prompt); + const prompts = get().prompts; + prompts[id] = prompt; + set(() => ({ prompts })); + SearchService.add(prompt); + }, + search(text) { if (text.length === 0) { - // return all prompts - const userPrompts = get().prompts?.values?.() ?? []; - return SearchService.allBuiltInPrompts.concat([...userPrompts]); + // return all rompts + return SearchService.allPrompts.concat([...get().getUserPrompts()]); } return SearchService.search(text) as Prompt[]; }, @@ -104,23 +137,27 @@ export const usePromptStore = create()( if (getLang() === "cn") { fetchPrompts = fetchPrompts.reverse(); } - const builtinPrompts = fetchPrompts - .map((promptList: PromptList) => { + const builtinPrompts = fetchPrompts.map( + (promptList: PromptList) => { return promptList.map( ([title, content]) => ({ + id: Math.random(), title, content, } as Prompt), ); - }) - .concat([...(state?.prompts?.values() ?? [])]); + }, + ); + + const userPrompts = + usePromptStore.getState().getUserPrompts() ?? []; const allPromptsForSearch = builtinPrompts .reduce((pre, cur) => pre.concat(cur), []) .filter((v) => !!v.title && !!v.content); SearchService.count.builtin = res.en.length + res.cn.length; - SearchService.init(allPromptsForSearch); + SearchService.init(allPromptsForSearch, userPrompts); }); }, }, diff --git a/app/store/update.ts b/app/store/update.ts index d49c246d1..47b190b88 100644 --- a/app/store/update.ts +++ b/app/store/update.ts @@ -50,13 +50,16 @@ export const useUpdateStore = create()( const overTenMins = Date.now() - get().lastUpdate > 10 * ONE_MINUTE; if (!force && !overTenMins) return; + set(() => ({ + lastUpdate: Date.now(), + })); + try { // const data = await (await fetch(FETCH_TAG_URL)).json(); // const remoteId = data[0].name as string; const data = await (await fetch(FETCH_COMMIT_URL)).json(); const remoteId = (data[0].sha as string).substring(0, 7); set(() => ({ - lastUpdate: Date.now(), remoteVersion: remoteId, })); console.log("[Got Upstream] ", remoteId); @@ -69,6 +72,10 @@ export const useUpdateStore = create()( const overOneMinute = Date.now() - get().lastUpdateUsage >= ONE_MINUTE; if (!overOneMinute && !force) return; + set(() => ({ + lastUpdateUsage: Date.now(), + })); + const usage = await requestUsage(); if (usage) { diff --git a/app/styles/globals.scss b/app/styles/globals.scss index cf36ee92b..37c662288 100644 --- a/app/styles/globals.scss +++ b/app/styles/globals.scss @@ -140,6 +140,7 @@ label { input { text-align: center; + font-family: inherit; } input[type="checkbox"] { @@ -224,6 +225,7 @@ input[type="password"] { color: var(--black); padding: 0 10px; max-width: 50%; + font-family: inherit; } div.math { From c03b4adec0c0178dbcb7de85c0b6a3488171e93d Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Tue, 18 Apr 2023 01:48:07 +0800 Subject: [PATCH 30/35] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 53706900d..3b6308be9 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,9 @@ One-Click to deploy well-designed ChatGPT web UI on Vercel. ## Roadmap - [x] System Prompt: pin a user defined prompt as system prompt [#138](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/138) -- [ ] User Prompt: user can edit and save custom prompts to prompt list +- [x] User Prompt: user can edit and save custom prompts to prompt list +- [ ] Prompt Template: create a new chat with pre-defined in-context prompts +- [ ] Share as image, share to ShareGPT - [ ] Desktop App with tauri - [ ] Self-host Model: support llama, alpaca, ChatGLM, BELLE etc. - [ ] Plugins: support network search, caculator, any other apis etc. [#165](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/165) @@ -59,7 +61,9 @@ One-Click to deploy well-designed ChatGPT web UI on Vercel. ## 开发计划 - [x] 为每个对话设置系统 Prompt [#138](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/138) -- [ ] 允许用户自行编辑内置 Prompt 列表 +- [x] 允许用户自行编辑内置 Prompt 列表 +- [ ] 提示词模板:使用预制上下文快速定制新对话 +- [ ] 分享为图片,分享到 ShareGPT - [ ] 使用 tauri 打包桌面应用 - [ ] 支持自部署的大语言模型 - [ ] 插件机制,支持联网搜索、计算器、调用其他平台 api [#165](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/165) From bd85d9a36a4ce22ea708d393b634997edaec558a Mon Sep 17 00:00:00 2001 From: yesRabbit Date: Tue, 18 Apr 2023 08:55:24 +0800 Subject: [PATCH 31/35] fix: typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b6308be9..ab902dd39 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ One-Click to deploy well-designed ChatGPT web UI on Vercel. - [ ] Share as image, share to ShareGPT - [ ] Desktop App with tauri - [ ] Self-host Model: support llama, alpaca, ChatGLM, BELLE etc. -- [ ] Plugins: support network search, caculator, any other apis etc. [#165](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/165) +- [ ] Plugins: support network search, calculator, any other apis etc. [#165](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/165) ### Not in Plan From e68207be2cd9faa72ead10cf1f512dc357ac6f05 Mon Sep 17 00:00:00 2001 From: L1468999760 <1468999760@qq.com> Date: Tue, 18 Apr 2023 11:34:33 +0800 Subject: [PATCH 32/35] fix:delete user.svg --- app/icons/user.svg | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 app/icons/user.svg diff --git a/app/icons/user.svg b/app/icons/user.svg deleted file mode 100644 index 7f91de4dc..000000000 --- a/app/icons/user.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 🤣 - - - - - \ No newline at end of file From 53173d90534616ea30aacd163033b12b8586b816 Mon Sep 17 00:00:00 2001 From: jtung4 <126780548+jtung4@users.noreply.github.com> Date: Tue, 18 Apr 2023 11:38:26 +0800 Subject: [PATCH 33/35] Optimize topic and summary prompts in tw.ts --- app/locales/tw.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/locales/tw.ts b/app/locales/tw.ts index 2fbb2e477..8d79e74fa 100644 --- a/app/locales/tw.ts +++ b/app/locales/tw.ts @@ -160,9 +160,9 @@ const tw: LocaleType = { History: (content: string) => "這是 AI 與用戶的歷史聊天總結,作為前情提要:" + content, Topic: - "Summarise the conversation in a short and concise eye-catching title that instantly conveys the main topic. Use as few words as possible. Use the language used in the enquiry, e.g. use English for English enquiry, use zh-hant for traditional chinese enquiry. Don't use quotation marks at the beginning and the end.", + "Use the language used by the user (e.g. en for english conversation, zh-hant for chinese conversation, etc.) to generate a title (at most 6 words) summarizing our conversation without any lead-in, quotation marks, preamble like 'Title:', direct text copies, single-word replies, quotation marks, translations, or brackets. Remove enclosing quotation marks. The title should make third-party grasp the essence of the conversation in first sight.", Summarize: - "Summarise the conversation in at most 250 tokens for continuing the conversation in future. Use the language used in the conversation, e.g. use English for English conversation, use zh-hant for traditional chinese conversation.", + "Use the language used by the user (e.g. en-us for english conversation, zh-hant for chinese conversation, etc.) to summarise the conversation in at most 200 words. The summary will be used as prompt for you to continue the conversation in the future.", }, ConfirmClearAll: "確認清除所有對話、設定數據?", }, From d75b7d49b83362583a09884654bbbcd81f0f08ce Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Tue, 18 Apr 2023 11:42:08 +0800 Subject: [PATCH 34/35] feat: close #864 improve long term history --- app/locales/cn.ts | 10 ++++---- app/store/app.ts | 64 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/app/locales/cn.ts b/app/locales/cn.ts index d0ab27ca2..7d011c7f1 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -38,12 +38,12 @@ const cn = { MessageFromChatGPT: "来自 ChatGPT 的消息", }, Memory: { - Title: "历史记忆", - EmptyContent: "尚未记忆", - Send: "发送记忆", - Copy: "复制记忆", + Title: "历史摘要", + EmptyContent: "尚未总结", + Send: "启用总结并发送摘要", + Copy: "复制摘要", Reset: "重置对话", - ResetConfirm: "重置后将清空当前对话记录以及历史记忆,确认重置?", + ResetConfirm: "重置后将清空当前对话记录以及历史摘要,确认重置?", }, Home: { NewChat: "新的聊天", diff --git a/app/store/app.ts b/app/store/app.ts index 39df9ef79..b3dfbd687 100644 --- a/app/store/app.ts +++ b/app/store/app.ts @@ -102,7 +102,7 @@ export function limitNumber( x: number, min: number, max: number, - defaultValue: number, + defaultValue: number ) { if (typeof x !== "number" || isNaN(x)) { return defaultValue; @@ -217,7 +217,7 @@ interface ChatStore { updateMessage: ( sessionIndex: number, messageIndex: number, - updater: (message?: Message) => void, + updater: (message?: Message) => void ) => void; resetSession: () => void; getMessagesWithMemory: () => Message[]; @@ -345,12 +345,12 @@ export const useChatStore = create()( .slice(0, index) .concat([deletedSession]) .concat( - state.sessions.slice(index + Number(isLastSession)), + state.sessions.slice(index + Number(isLastSession)) ), })); }, }, - 5000, + 5000 ); } }, @@ -412,7 +412,7 @@ export const useChatStore = create()( get().onNewMessage(botMessage); ControllerPool.remove( sessionIndex, - botMessage.id ?? messageIndex, + botMessage.id ?? messageIndex ); } else { botMessage.content = content; @@ -436,7 +436,7 @@ export const useChatStore = create()( ControllerPool.addController( sessionIndex, botMessage.id ?? messageIndex, - controller, + controller ); }, filterBot: !get().config.sendBotMessages, @@ -462,6 +462,7 @@ export const useChatStore = create()( const context = session.context.slice(); + // long term memory if ( session.sendMemory && session.memoryPrompt && @@ -471,9 +472,33 @@ export const useChatStore = create()( context.push(memoryPrompt); } - const recentMessages = context.concat( - messages.slice(Math.max(0, n - config.historyMessageCount)), + // get short term and unmemoried long term memory + const shortTermMemoryMessageIndex = Math.max( + 0, + n - config.historyMessageCount ); + const longTermMemoryMessageIndex = config.lastSummarizeIndex; + const oldestIndex = Math.min( + shortTermMemoryMessageIndex, + longTermMemoryMessageIndex + ); + const threshold = config.compressMessageLengthThreshold; + + // get recent messages as many as possible + const reversedRecentMessages = []; + for ( + let i = n - 1, count = 0; + i >= oldestIndex && count < threshold; + i -= 1 + ) { + const msg = messages[i]; + if (!msg || msg.isError) continue; + count += msg.content.length; + reversedRecentMessages.push(msg); + } + + // concat + const recentMessages = context.concat(reversedRecentMessages.reverse()); return recentMessages; }, @@ -481,7 +506,7 @@ export const useChatStore = create()( updateMessage( sessionIndex: number, messageIndex: number, - updater: (message?: Message) => void, + updater: (message?: Message) => void ) { const sessions = get().sessions; const session = sessions.at(sessionIndex); @@ -510,15 +535,15 @@ export const useChatStore = create()( (res) => { get().updateCurrentSession( (session) => - (session.topic = res ? trimTopic(res) : DEFAULT_TOPIC), + (session.topic = res ? trimTopic(res) : DEFAULT_TOPIC) ); - }, + } ); } const config = get().config; let toBeSummarizedMsgs = session.messages.slice( - session.lastSummarizeIndex, + session.lastSummarizeIndex ); const historyMsgLength = countMessages(toBeSummarizedMsgs); @@ -526,7 +551,7 @@ export const useChatStore = create()( if (historyMsgLength > get().config?.modelConfig?.max_tokens ?? 4000) { const n = toBeSummarizedMsgs.length; toBeSummarizedMsgs = toBeSummarizedMsgs.slice( - Math.max(0, n - config.historyMessageCount), + Math.max(0, n - config.historyMessageCount) ); } @@ -539,10 +564,13 @@ export const useChatStore = create()( "[Chat History] ", toBeSummarizedMsgs, historyMsgLength, - config.compressMessageLengthThreshold, + config.compressMessageLengthThreshold ); - if (historyMsgLength > config.compressMessageLengthThreshold) { + if ( + historyMsgLength > config.compressMessageLengthThreshold && + session.sendMemory + ) { requestChatStream( toBeSummarizedMsgs.concat({ role: "system", @@ -561,7 +589,7 @@ export const useChatStore = create()( onError(error) { console.error("[Summarize] ", error); }, - }, + } ); } }, @@ -603,6 +631,6 @@ export const useChatStore = create()( return state; }, - }, - ), + } + ) ); From ad1c8ffe21f16d86367101e5ecfaca66860f7254 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 18 Apr 2023 11:44:15 +0800 Subject: [PATCH 35/35] fixup --- app/store/app.ts | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/app/store/app.ts b/app/store/app.ts index b3dfbd687..da0e886ff 100644 --- a/app/store/app.ts +++ b/app/store/app.ts @@ -102,7 +102,7 @@ export function limitNumber( x: number, min: number, max: number, - defaultValue: number + defaultValue: number, ) { if (typeof x !== "number" || isNaN(x)) { return defaultValue; @@ -217,7 +217,7 @@ interface ChatStore { updateMessage: ( sessionIndex: number, messageIndex: number, - updater: (message?: Message) => void + updater: (message?: Message) => void, ) => void; resetSession: () => void; getMessagesWithMemory: () => Message[]; @@ -345,12 +345,12 @@ export const useChatStore = create()( .slice(0, index) .concat([deletedSession]) .concat( - state.sessions.slice(index + Number(isLastSession)) + state.sessions.slice(index + Number(isLastSession)), ), })); }, }, - 5000 + 5000, ); } }, @@ -412,7 +412,7 @@ export const useChatStore = create()( get().onNewMessage(botMessage); ControllerPool.remove( sessionIndex, - botMessage.id ?? messageIndex + botMessage.id ?? messageIndex, ); } else { botMessage.content = content; @@ -436,7 +436,7 @@ export const useChatStore = create()( ControllerPool.addController( sessionIndex, botMessage.id ?? messageIndex, - controller + controller, ); }, filterBot: !get().config.sendBotMessages, @@ -475,12 +475,12 @@ export const useChatStore = create()( // get short term and unmemoried long term memory const shortTermMemoryMessageIndex = Math.max( 0, - n - config.historyMessageCount + n - config.historyMessageCount, ); - const longTermMemoryMessageIndex = config.lastSummarizeIndex; + const longTermMemoryMessageIndex = session.lastSummarizeIndex; const oldestIndex = Math.min( shortTermMemoryMessageIndex, - longTermMemoryMessageIndex + longTermMemoryMessageIndex, ); const threshold = config.compressMessageLengthThreshold; @@ -506,7 +506,7 @@ export const useChatStore = create()( updateMessage( sessionIndex: number, messageIndex: number, - updater: (message?: Message) => void + updater: (message?: Message) => void, ) { const sessions = get().sessions; const session = sessions.at(sessionIndex); @@ -535,15 +535,15 @@ export const useChatStore = create()( (res) => { get().updateCurrentSession( (session) => - (session.topic = res ? trimTopic(res) : DEFAULT_TOPIC) + (session.topic = res ? trimTopic(res) : DEFAULT_TOPIC), ); - } + }, ); } const config = get().config; let toBeSummarizedMsgs = session.messages.slice( - session.lastSummarizeIndex + session.lastSummarizeIndex, ); const historyMsgLength = countMessages(toBeSummarizedMsgs); @@ -551,7 +551,7 @@ export const useChatStore = create()( if (historyMsgLength > get().config?.modelConfig?.max_tokens ?? 4000) { const n = toBeSummarizedMsgs.length; toBeSummarizedMsgs = toBeSummarizedMsgs.slice( - Math.max(0, n - config.historyMessageCount) + Math.max(0, n - config.historyMessageCount), ); } @@ -564,7 +564,7 @@ export const useChatStore = create()( "[Chat History] ", toBeSummarizedMsgs, historyMsgLength, - config.compressMessageLengthThreshold + config.compressMessageLengthThreshold, ); if ( @@ -589,7 +589,7 @@ export const useChatStore = create()( onError(error) { console.error("[Summarize] ", error); }, - } + }, ); } }, @@ -631,6 +631,6 @@ export const useChatStore = create()( return state; }, - } - ) + }, + ), );