From f606a61e1c9127f7f1c4128d0361a90ced9cde69 Mon Sep 17 00:00:00 2001 From: ilarioscandurra Date: Sun, 2 Apr 2023 19:23:50 +0200 Subject: [PATCH 01/13] Update: locales in Italian --- app/locales/cn.ts | 1 + app/locales/en.ts | 1 + app/locales/es.ts | 1 + app/locales/index.ts | 7 +- app/locales/it.ts | 159 +++++++++++++++++++++++++++++++++++++++++++ app/locales/tw.ts | 1 + 6 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 app/locales/it.ts diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 66436e12f..59a33a40f 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -58,6 +58,7 @@ const cn = { en: "English", tw: "繁體中文", es: "Español", + it: "Italiano", }, }, Avatar: "头像", diff --git a/app/locales/en.ts b/app/locales/en.ts index 55884308c..1a9acc32a 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -60,6 +60,7 @@ const en: LocaleType = { en: "English", tw: "繁體中文", es: "Español", + it: "Italiano", }, }, Avatar: "Avatar", diff --git a/app/locales/es.ts b/app/locales/es.ts index a78bf1aa3..e26a5e101 100644 --- a/app/locales/es.ts +++ b/app/locales/es.ts @@ -60,6 +60,7 @@ const es: LocaleType = { en: "Inglés", tw: "繁體中文", es: "Español", + it: "Italiano", }, }, Avatar: "Avatar", diff --git a/app/locales/index.ts b/app/locales/index.ts index bcd06c9c1..5c41eeb77 100644 --- a/app/locales/index.ts +++ b/app/locales/index.ts @@ -2,10 +2,11 @@ import CN from "./cn"; import EN from "./en"; import TW from "./tw"; import ES from "./es"; +import IT from "./it"; export type { LocaleType } from "./cn"; -export const AllLangs = ["en", "cn", "tw", "es"] as const; +export const AllLangs = ["en", "cn", "tw", "es", "it"] as const; type Lang = (typeof AllLangs)[number]; const LANG_KEY = "lang"; @@ -47,6 +48,8 @@ export function getLang(): Lang { return "tw"; } else if (lang.includes("es")) { return "es"; + } else if (lang.includes("it")) { + return "it"; } else { return "en"; } @@ -57,4 +60,4 @@ export function changeLang(lang: Lang) { location.reload(); } -export default { en: EN, cn: CN, tw: TW, es: ES }[getLang()]; +export default { en: EN, cn: CN, tw: TW, es: ES, it: IT }[getLang()]; diff --git a/app/locales/it.ts b/app/locales/it.ts new file mode 100644 index 000000000..6bfff42d9 --- /dev/null +++ b/app/locales/it.ts @@ -0,0 +1,159 @@ +import { SubmitKey } from "../store/app"; +import type { LocaleType } from "./index"; + +const it: LocaleType = { + WIP: "Work in progress...", + Error: { + Unauthorized: + "Accesso non autorizzato, inserire il codice di accesso nella pagina delle impostazioni.", + }, + ChatItem: { + ChatItemCount: (count: number) => `${count} messaggi`, + }, + Chat: { + SubTitle: (count: number) => `${count} messaggi con ChatGPT`, + Actions: { + ChatList: "Vai alla Chat List", + CompressedHistory: "Prompt di memoria della cronologia compressa", + Export: "Esportazione di tutti i messaggi come Markdown", + Copy: "Copia", + Stop: "Stop", + Retry: "Riprova", + }, + Rename: "Rinomina Chat", + Typing: "Typing…", + Input: (submitKey: string) => { + var inputHints = `Scrivi qualcosa e premi ${submitKey} per inviare`; + if (submitKey === String(SubmitKey.Enter)) { + inputHints += ", premi Shift + Enter per andare a capo"; + } + return inputHints; + }, + Send: "Invia", + }, + Export: { + Title: "Tutti i messaggi", + Copy: "Copia tutto", + Download: "Scarica", + }, + Memory: { + Title: "Prompt di memoria", + EmptyContent: "Vuoto.", + Copy: "Copia tutto", + }, + Home: { + NewChat: "Nuova Chat", + DeleteChat: "Confermare la cancellazione della conversazione selezionata?", + }, + Settings: { + Title: "Impostazioni", + SubTitle: "Tutte le impostazioni", + Actions: { + ClearAll: "Cancella tutti i dati", + ResetAll: "Resetta tutte le impostazioni", + Close: "Chiudi", + }, + Lang: { + Name: "Lingue", + Options: { + cn: "简体中文", + en: "English", + tw: "繁體中文", + es: "Español", + it: "Italiano", + }, + }, + Avatar: "Avatar", + FontSize: { + Title: "Dimensione carattere", + SubTitle: "Regolare la dimensione dei caratteri del contenuto della chat", + }, + Update: { + Version: (x: string) => `Versione: ${x}`, + IsLatest: "Ultima versione", + CheckUpdate: "Controlla aggiornamenti", + IsChecking: "Sto controllando gli aggiornamenti...", + FoundUpdate: (x: string) => `Trovata nuova versione: ${x}`, + GoToUpdate: "Aggiorna", + }, + SendKey: "Tasto invia", + Theme: "tema", + TightBorder: "Bordi stretti", + SendPreviewBubble: "Invia l'anteprima della bolla", + Prompt: { + Disable: { + Title: "Disabilita l'auto completamento", + SubTitle: "Input / per attivare il completamento automatico", + }, + List: "Elenco dei suggerimenti", + ListCount: (builtin: number, custom: number) => + `${builtin} built-in, ${custom} user-defined`, + Edit: "Modifica", + }, + HistoryCount: { + Title: "Conteggio dei messaggi allegati", + SubTitle: "Numero di messaggi inviati allegati per richiesta", + }, + CompressThreshold: { + Title: "Soglia di compressione della cronologia", + SubTitle: + "Comprimerà se la lunghezza dei messaggi non compressi supera il valore", + }, + Token: { + Title: "Chiave API", + SubTitle: + "Utilizzare la chiave per ignorare il limite del codice di accesso", + Placeholder: "OpenAI API Key", + }, + Usage: { + Title: "Bilancio Account", + SubTitle(granted: any, used: any) { + return `Totale $${granted}, Usato $${used}`; + }, + IsChecking: "Controllando...", + Check: "Controlla ancora", + }, + AccessCode: { + Title: "Codice d'accesso", + SubTitle: "Controllo d'accesso abilitato", + Placeholder: "Inserisci il codice d'accesso", + }, + Model: "Modello GPT", + Temperature: { + Title: "Temperature", + SubTitle: "Un valore maggiore rende l'output più casuale", + }, + MaxTokens: { + Title: "Token massimi", + SubTitle: "Lunghezza massima dei token in ingresso e dei token generati", + }, + PresencePenlty: { + Title: "Penalità di presenza", + SubTitle: + "Un valore maggiore aumenta la probabilità di parlare di nuovi argomenti", + }, + }, + Store: { + DefaultTopic: "Nuova conversazione", + BotHello: "Ciao, come posso aiutarti oggi?", + Error: "Qualcosa è andato storto, riprova più tardi.", + Prompt: { + History: (content: string) => + "Questo è un riassunto della cronologia delle chat tra l'IA e l'utente:" + + content, + Topic: + "Si prega di generare un titolo di quattro o cinque parole che riassuma la nostra conversazione senza alcuna traccia, punteggiatura, virgolette, punti, simboli o testo aggiuntivo. Rimuovere le virgolette", + Summarize: + "Riassumi brevemente la nostra discussione in 50 caratteri o meno per usarla come spunto per una futura conversazione.", + }, + ConfirmClearAll: + "Confermi la cancellazione di tutti i dati della chat e delle impostazioni?", + }, + Copy: { + Success: "Copiato sugli appunti", + Failed: + "Copia fallita, concedere l'autorizzazione all'accesso agli appunti", + }, +}; + +export default it; diff --git a/app/locales/tw.ts b/app/locales/tw.ts index 7137e8846..e136032db 100644 --- a/app/locales/tw.ts +++ b/app/locales/tw.ts @@ -59,6 +59,7 @@ const tw: LocaleType = { en: "English", tw: "繁體中文", es: "Español", + it: "Italiano", }, }, Avatar: "大頭貼", From f9f29afba91dc79e16ce86ede39cca254c78ef0c Mon Sep 17 00:00:00 2001 From: ilarioscandurra Date: Sun, 2 Apr 2023 20:32:43 +0200 Subject: [PATCH 02/13] Update: locales in Italian --- app/locales/it.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/locales/it.ts b/app/locales/it.ts index 6bfff42d9..8c4e01233 100644 --- a/app/locales/it.ts +++ b/app/locales/it.ts @@ -107,8 +107,8 @@ const it: LocaleType = { }, Usage: { Title: "Bilancio Account", - SubTitle(granted: any, used: any) { - return `Totale $${granted}, Usato $${used}`; + SubTitle(used: any) { + return `Usato in questo mese $${used}`; }, IsChecking: "Controllando...", Check: "Controlla ancora", @@ -144,7 +144,7 @@ const it: LocaleType = { Topic: "Si prega di generare un titolo di quattro o cinque parole che riassuma la nostra conversazione senza alcuna traccia, punteggiatura, virgolette, punti, simboli o testo aggiuntivo. Rimuovere le virgolette", Summarize: - "Riassumi brevemente la nostra discussione in 50 caratteri o meno per usarla come spunto per una futura conversazione.", + "Riassumi brevemente la nostra discussione in 200 caratteri o meno per usarla come spunto per una futura conversazione.", }, ConfirmClearAll: "Confermi la cancellazione di tutti i dati della chat e delle impostazioni?", @@ -154,6 +154,11 @@ const it: LocaleType = { Failed: "Copia fallita, concedere l'autorizzazione all'accesso agli appunti", }, + Context: { + Toast: (x: any) => `Con ${x} prompts contestuali`, + Edit: "Prompt contestuali e di memoria", + Add: "Aggiungi altro", + }, }; export default it; From 5c75b6c784c3b99ec849288e83f4345ad40621d1 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Mon, 3 Apr 2023 13:29:37 +0800 Subject: [PATCH 03/13] fix: #397 #373 Array.prototype.at polyfill errors --- app/components/chat.tsx | 9 +--- app/components/error.tsx | 47 +++++++++++++++++ app/components/home.tsx | 30 +++++------ app/constant.ts | 1 + app/page.tsx | 2 - app/polyfill.ts | 27 ++++++++++ app/styles/globals.scss | 15 ++++++ package.json | 1 - yarn.lock | 107 +-------------------------------------- 9 files changed, 107 insertions(+), 132 deletions(-) create mode 100644 app/components/error.tsx create mode 100644 app/polyfill.ts diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 8b687c7eb..d7540dea4 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -12,14 +12,7 @@ import BotIcon from "../icons/bot.svg"; import AddIcon from "../icons/add.svg"; import DeleteIcon from "../icons/delete.svg"; -import { - Message, - SubmitKey, - useChatStore, - ChatSession, - BOT_HELLO, - ROLES, -} from "../store"; +import { Message, SubmitKey, useChatStore, BOT_HELLO, ROLES } from "../store"; import { copyToClipboard, diff --git a/app/components/error.tsx b/app/components/error.tsx new file mode 100644 index 000000000..aa80939b6 --- /dev/null +++ b/app/components/error.tsx @@ -0,0 +1,47 @@ +import React from "react"; +import { IconButton } from "./button"; +import GithubIcon from "../icons/github.svg"; +import { ISSUE_URL } from "../constant"; + +interface IErrorBoundaryState { + hasError: boolean; + error: Error | null; + info: React.ErrorInfo | null; +} + +export class ErrorBoundary extends React.Component { + constructor(props: any) { + super(props); + this.state = { hasError: false, error: null, info: null }; + } + + componentDidCatch(error: Error, info: React.ErrorInfo) { + // Update state with error details + this.setState({ hasError: true, error, info }); + } + + render() { + if (this.state.hasError) { + // Render error message + return ( +
+

Oops, something went wrong!

+
+            {this.state.error?.toString()}
+            {this.state.info?.componentStack}
+          
+ + + } + bordered + /> + +
+ ); + } + // if no error occurred, render children + return this.props.children; + } +} diff --git a/app/components/home.tsx b/app/components/home.tsx index 13db93e29..cbb5dbfc6 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -1,6 +1,8 @@ "use client"; -import { useState, useRef, useEffect, useLayoutEffect } from "react"; +require("../polyfill"); + +import { useState, useEffect } from "react"; import { IconButton } from "./button"; import styles from "./home.module.scss"; @@ -14,25 +16,15 @@ import AddIcon from "../icons/add.svg"; import LoadingIcon from "../icons/three-dots.svg"; import CloseIcon from "../icons/close.svg"; -import { - Message, - SubmitKey, - useChatStore, - ChatSession, - BOT_HELLO, -} from "../store"; -import { - copyToClipboard, - downloadAs, - isMobileScreen, - selectOrCopy, -} from "../utils"; +import { useChatStore } from "../store"; +import { isMobileScreen } from "../utils"; import Locale from "../locales"; import { ChatList } from "./chat-list"; import { Chat } from "./chat"; import dynamic from "next/dynamic"; import { REPO_URL } from "../constant"; +import { ErrorBoundary } from "./error"; export function Loading(props: { noLogo?: boolean }) { return ( @@ -78,7 +70,7 @@ const useHasHydrated = () => { return hasHydrated; }; -export function Home() { +function _Home() { const [createNewSession, currentIndex, removeSession] = useChatStore( (state) => [ state.newSession, @@ -191,3 +183,11 @@ export function Home() { ); } + +export function Home() { + return ( + + <_Home> + + ); +} diff --git a/app/constant.ts b/app/constant.ts index fff77607e..169a5eee5 100644 --- a/app/constant.ts +++ b/app/constant.ts @@ -1,6 +1,7 @@ export const OWNER = "Yidadaa"; export const REPO = "ChatGPT-Next-Web"; export const REPO_URL = `https://github.com/${OWNER}/${REPO}`; +export const ISSUE_URL = `https://github.com/${OWNER}/${REPO}/issues`; export const UPDATE_URL = `${REPO_URL}#%E4%BF%9D%E6%8C%81%E6%9B%B4%E6%96%B0-keep-updated`; export const FETCH_COMMIT_URL = `https://api.github.com/repos/${OWNER}/${REPO}/commits?per_page=1`; export const FETCH_TAG_URL = `https://api.github.com/repos/${OWNER}/${REPO}/tags?per_page=1`; diff --git a/app/page.tsx b/app/page.tsx index 2ad763cec..1d1da2227 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,7 +1,5 @@ import { Analytics } from "@vercel/analytics/react"; -import "array.prototype.at"; - import { Home } from "./components/home"; export default function App() { diff --git a/app/polyfill.ts b/app/polyfill.ts new file mode 100644 index 000000000..517f06e7c --- /dev/null +++ b/app/polyfill.ts @@ -0,0 +1,27 @@ +declare global { + interface Array { + at(index: number): T | undefined; + } +} + +if (!Array.prototype.at) { + Array.prototype.at = function (index: number) { + // Get the length of the array + const length = this.length; + + // Convert negative index to a positive index + if (index < 0) { + index = length + index; + } + + // Return undefined if the index is out of range + if (index < 0 || index >= length) { + return undefined; + } + + // Use Array.prototype.slice method to get value at the specified index + return Array.prototype.slice.call(this, index, index + 1)[0]; + }; +} + +export {}; diff --git a/app/styles/globals.scss b/app/styles/globals.scss index 81811819b..73b9b36f3 100644 --- a/app/styles/globals.scss +++ b/app/styles/globals.scss @@ -268,3 +268,18 @@ pre { filter: brightness(0.9); } } + +.error { + width: 80%; + border-radius: 20px; + border: var(--border-in-light); + box-shadow: var(--card-shadow); + padding: 20px; + overflow: auto; + background-color: var(--white); + color: var(--black); + + pre { + overflow: auto; + } +} diff --git a/package.json b/package.json index 2e018647d..18e227f1a 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,6 @@ "dependencies": { "@svgr/webpack": "^6.5.1", "@vercel/analytics": "^0.1.11", - "array.prototype.at": "^1.1.1", "emoji-picker-react": "^4.4.7", "eventsource-parser": "^0.1.0", "fuse.js": "^6.6.2", diff --git a/yarn.lock b/yarn.lock index fd26bb004..9a937276c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1365,11 +1365,6 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== -"@types/prismjs@^1.0.0": - version "1.26.0" - resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.26.0.tgz#a1c3809b0ad61c62cac6d4e0c56d610c910b7654" - integrity sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ== - "@types/prop-types@*", "@types/prop-types@^15.0.0": version "15.7.5" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" @@ -1570,16 +1565,6 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.at@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array.prototype.at/-/array.prototype.at-1.1.1.tgz#6deda3cd3c704afa16361387ea344e0b8d8831b5" - integrity sha512-n/wYNLJy/fVEU9EGPt2ww920hy1XX3XB2yTREFy1QsxctBgQV/tZIwg1G8jVxELna4pLCzg/xvvS/DDXtI4NNg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - array.prototype.flat@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" @@ -1769,21 +1754,11 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -character-entities-legacy@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz#76bc83a90738901d7bc223a9e93759fdd560125b" - integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ== - character-entities@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== -character-reference-invalid@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" - integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== - "chokidar@>=3.0.0 <4.0.0": version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -2879,13 +2854,6 @@ hast-util-parse-selector@^3.0.0: dependencies: "@types/hast" "^2.0.0" -hast-util-to-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hast-util-to-string/-/hast-util-to-string-2.0.0.tgz#b008b0a4ea472bf34dd390b7eea1018726ae152a" - integrity sha512-02AQ3vLhuH3FisaMM+i/9sm4OXGSq1UhOOCpTLLQtHdL3tZt7qil69r8M8iDkZYyC0HCFylcYoP+8IO7ddta1A== - dependencies: - "@types/hast" "^2.0.0" - hast-util-to-text@^3.0.0, hast-util-to-text@^3.1.0: version "3.1.2" resolved "https://registry.yarnpkg.com/hast-util-to-text/-/hast-util-to-text-3.1.2.tgz#ecf30c47141f41e91a5d32d0b1e1859fd2ac04f2" @@ -2982,19 +2950,6 @@ internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5: has "^1.0.3" side-channel "^1.0.4" -is-alphabetical@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" - integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== - -is-alphanumerical@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" - integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== - dependencies: - is-alphabetical "^2.0.0" - is-decimal "^2.0.0" - is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -3063,11 +3018,6 @@ is-date-object@^1.0.1, is-date-object@^1.0.5: dependencies: has-tostringtag "^1.0.0" -is-decimal@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" - integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== - is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" @@ -3095,11 +3045,6 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-hexadecimal@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz#86b5bf668fca307498d319dfc03289d781a90027" - integrity sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg== - is-map@^2.0.1, is-map@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" @@ -4156,20 +4101,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-entities@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.1.tgz#4e2a01111fb1c986549b944af39eeda258fc9e4e" - integrity sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w== - dependencies: - "@types/unist" "^2.0.0" - character-entities "^2.0.0" - character-entities-legacy "^3.0.0" - character-reference-invalid "^2.0.0" - decode-named-character-reference "^1.0.0" - is-alphanumerical "^2.0.0" - is-decimal "^2.0.0" - is-hexadecimal "^2.0.0" - parse-json@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -4180,11 +4111,6 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse-numeric-range@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz#7c63b61190d61e4d53a1197f0c83c47bb670ffa3" - integrity sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ== - parse5@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" @@ -4338,16 +4264,6 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -refractor@^4.7.0: - version "4.8.1" - resolved "https://registry.yarnpkg.com/refractor/-/refractor-4.8.1.tgz#fbdd889333a3d86c9c864479622855c9b38e9d42" - integrity sha512-/fk5sI0iTgFYlmVGYVew90AoYnNMP6pooClx/XKqyeeCQXrL0Kvgn8V0VEht5ccdljbzzF1i3Q213gcntkRExg== - dependencies: - "@types/hast" "^2.0.0" - "@types/prismjs" "^1.0.0" - hastscript "^7.0.0" - parse-entities "^4.0.0" - regenerate-unicode-properties@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" @@ -4425,7 +4341,7 @@ rehype-katex@^6.0.2: unist-util-remove-position "^4.0.0" unist-util-visit "^4.0.0" -rehype-parse@^8.0.0, rehype-parse@^8.0.2: +rehype-parse@^8.0.0: version "8.0.4" resolved "https://registry.yarnpkg.com/rehype-parse/-/rehype-parse-8.0.4.tgz#3d17c9ff16ddfef6bbcc8e6a25a99467b482d688" integrity sha512-MJJKONunHjoTh4kc3dsM1v3C9kGrrxvA3U8PxZlP2SjH8RNUSrb+lF7Y0KVaUDnGH2QZ5vAn7ulkiajM9ifuqg== @@ -4435,18 +4351,6 @@ rehype-parse@^8.0.0, rehype-parse@^8.0.2: parse5 "^6.0.0" unified "^10.0.0" -rehype-prism-plus@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/rehype-prism-plus/-/rehype-prism-plus-1.5.1.tgz#b5f4eb3c789a13ffe874c81039665e144bcb1cae" - integrity sha512-mowYefSfrIkMMxkb0fwuEXlvc5nA9b1vQ6mzujM81Qx28RI0mo7jCHsBZ2tJ4eIJKXdFn+EdPkZZBGB10K02vg== - dependencies: - hast-util-to-string "^2.0.0" - parse-numeric-range "^1.3.0" - refractor "^4.7.0" - rehype-parse "^8.0.2" - unist-util-filter "^4.0.0" - unist-util-visit "^4.0.0" - remark-breaks@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/remark-breaks/-/remark-breaks-3.0.2.tgz#f466b9d3474d7323146c0149fc1496dabadd908e" @@ -4996,15 +4900,6 @@ unified@^10.0.0: trough "^2.0.0" vfile "^5.0.0" -unist-util-filter@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/unist-util-filter/-/unist-util-filter-4.0.1.tgz#fd885dd48adaad345de5f5dc706ec4ff44a8d074" - integrity sha512-RynicUM/vbOSTSiUK+BnaK9XMfmQUh6gyi7L6taNgc7FIf84GukXVV3ucGzEN/PhUUkdP5hb1MmXc+3cvPUm5Q== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - unist-util-visit-parents "^5.0.0" - unist-util-find-after@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/unist-util-find-after/-/unist-util-find-after-4.0.1.tgz#80c69c92b0504033638ce11973f4135f2c822e2d" From 6f82140ba5ffaa91152276821d750f5af9a17681 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Mon, 3 Apr 2023 13:37:55 +0800 Subject: [PATCH 04/13] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 815aba1af..ca71c996b 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,9 @@ One-Click to deploy your own ChatGPT web UI. - 前往 vercel 控制台,删除掉原先的 project,然后新建 project,选择你刚刚 fork 出来的项目重新进行部署即可; - 在重新部署的过程中,请手动添加名为 `OPENAI_API_KEY` 的环境变量,并填入你的 api key 作为值。 -本项目会持续更新,如果你想让代码库总是保持更新,可以查看 [Github 的文档](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork) 了解如何让 fork 的项目与上游代码同步,建议定期进行同步操作以获得新功能。 +本项目会持续更新,当你 Fork 项目之后,默认会每天自动同步上游代码,无需额外操作。 + +如果你想让手动立即更新,可以查看 [Github 的文档](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork) 了解如何让 fork 的项目与上游代码同步。 你可以 star/watch 本项目或者 follow 作者来及时获得新功能更新通知。 @@ -87,7 +89,9 @@ We recommend that you follow the steps below to re-deploy: - Go to the Vercel dashboard, delete the original project, then create a new project and select the project you just forked to redeploy; - Please manually add an environment variable named `OPENAI_API_KEY` and enter your API key as the value during the redeploy process. -This project will be continuously maintained. If you want to keep the code repository up to date, 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. It is recommended to perform synchronization operations regularly. +This project will be continuously updated, and after forking the project, the upstream code will be automatically synchronized every day without additional operations. + +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. From 82c025a34a9bec5186e0bff6c3691522efc85f32 Mon Sep 17 00:00:00 2001 From: Yorun <547747006@qq.com> Date: Mon, 3 Apr 2023 06:03:36 +0000 Subject: [PATCH 05/13] ci(sync): add push permission --- .github/workflows/sync.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml index 9c7b7e6f1..38c272e85 100644 --- a/.github/workflows/sync.yml +++ b/.github/workflows/sync.yml @@ -1,5 +1,8 @@ name: Upstream Sync +permissions: + contents: write + on: schedule: - cron: "0 */6 * * *" # every 6 hours @@ -12,7 +15,7 @@ jobs: if: ${{ github.event.repository.fork }} steps: - # Step 1: run a standard checkout action, provided by github + # Step 1: run a standard checkout action - name: Checkout target repo uses: actions/checkout@v3 From 73f4ea38c6c899f3ef1ce7169523f4b28a45c646 Mon Sep 17 00:00:00 2001 From: cyhhao Date: Mon, 3 Apr 2023 14:13:57 +0800 Subject: [PATCH 06/13] session message should exclude all error tips --- app/components/chat.tsx | 5 ++++- app/requests.ts | 7 +++---- app/store/app.ts | 16 ++++++++++++---- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 3864a3292..70afa319a 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -513,7 +513,10 @@ export function Chat(props: { bordered title={Locale.Chat.Actions.Export} onClick={() => { - exportMessages(session.messages, session.topic); + exportMessages( + session.messages.filter((msg) => !msg.isError), + session.topic, + ); }} /> diff --git a/app/requests.ts b/app/requests.ts index 281f8ff1b..ee3103b77 100644 --- a/app/requests.ts +++ b/app/requests.ts @@ -114,7 +114,7 @@ export async function requestChatStream( filterBot?: boolean; modelConfig?: ModelConfig; onMessage: (message: string, done: boolean) => void; - onError: (error: Error) => void; + onError: (error: Error, statusCode?: number) => void; onController?: (controller: AbortController) => void; }, ) { @@ -178,11 +178,10 @@ export async function requestChatStream( finish(); } else if (res.status === 401) { console.error("Anauthorized"); - responseText = Locale.Error.Unauthorized; - finish(); + options?.onError(new Error("Anauthorized"), res.status); } else { console.error("Stream Error", res.body); - options?.onError(new Error("Stream Error")); + options?.onError(new Error("Stream Error"), res.status); } } catch (err) { console.error("NetWork Error", err); diff --git a/app/store/app.ts b/app/store/app.ts index 3e98757cb..f83c1e082 100644 --- a/app/store/app.ts +++ b/app/store/app.ts @@ -14,6 +14,7 @@ import Locale from "../locales"; export type Message = ChatCompletionResponseMessage & { date: string; streaming?: boolean; + isError?: boolean; }; export enum SubmitKey { @@ -351,9 +352,15 @@ export const useChatStore = create()( set(() => ({})); } }, - onError(error) { - botMessage.content += "\n\n" + Locale.Store.Error; + onError(error, statusCode) { + if (statusCode === 401) { + botMessage.content = Locale.Error.Unauthorized; + } else { + botMessage.content += "\n\n" + Locale.Store.Error; + } botMessage.streaming = false; + userMessage.isError = true; + botMessage.isError = true; set(() => ({})); ControllerPool.remove(sessionIndex, messageIndex); }, @@ -383,7 +390,8 @@ export const useChatStore = create()( getMessagesWithMemory() { const session = get().currentSession(); const config = get().config; - const n = session.messages.length; + const messages = session.messages.filter((msg) => !msg.isError); + const n = messages.length; const context = session.context.slice(); @@ -393,7 +401,7 @@ export const useChatStore = create()( } const recentMessages = context.concat( - session.messages.slice(Math.max(0, n - config.historyMessageCount)), + messages.slice(Math.max(0, n - config.historyMessageCount)), ); return recentMessages; From a6890c0f58c5f9895fdcfa74763f5f205071e43e Mon Sep 17 00:00:00 2001 From: cyhhao Date: Mon, 3 Apr 2023 14:56:13 +0800 Subject: [PATCH 07/13] optimize: scrolling experience --- app/components/chat.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 70afa319a..34cef0b6f 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -377,7 +377,8 @@ export function Chat(props: { chatStore.onUserInput(userInput).then(() => setIsLoading(false)); setUserInput(""); setPromptHints([]); - inputRef.current?.focus(); + if (!isMobileScreen()) inputRef.current?.focus(); + setAutoScroll(true); }; // stop response @@ -533,8 +534,11 @@ export function Chat(props: { className={styles["chat-body"]} ref={scrollRef} onScroll={(e) => onChatBodyScroll(e.currentTarget)} - onMouseOver={() => inputRef.current?.blur()} - onTouchStart={() => inputRef.current?.blur()} + onWheel={() => setAutoScroll(false)} + onTouchStart={() => { + inputRef.current?.blur(); + setAutoScroll(false); + }} > {messages.map((message, i) => { const isUser = message.role === "user"; From 8db26bbd5ff843ee183f1493a23fdeb66c743a0d Mon Sep 17 00:00:00 2001 From: cyhhao Date: Mon, 3 Apr 2023 15:20:16 +0800 Subject: [PATCH 08/13] rm msg body mouseover --- app/components/chat.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 1499e8161..4cc60fa53 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -593,7 +593,6 @@ export function Chat(props: { if (!isMobileScreen()) return; setUserInput(message.content); }} - onMouseOver={() => inputRef.current?.blur()} > From ae8ceb8dca5fad06b3fb27dc8132526981ad3ecf Mon Sep 17 00:00:00 2001 From: cyhhao Date: Mon, 3 Apr 2023 15:21:03 +0800 Subject: [PATCH 09/13] rm input mouseover --- app/components/chat.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 4cc60fa53..2bd80aa8b 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -627,9 +627,6 @@ export function Chat(props: { setAutoScroll(false); setTimeout(() => setPromptHints([]), 500); }} - onMouseOver={() => { - inputRef.current?.focus(); - }} autoFocus={!props?.sideBarShowing} /> Date: Mon, 3 Apr 2023 17:48:22 +0800 Subject: [PATCH 10/13] opt: back to auto scroll --- app/components/chat.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 2bd80aa8b..7aa8bfec6 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -528,7 +528,7 @@ export function Chat(props: { className={styles["chat-body"]} ref={scrollRef} onScroll={(e) => onChatBodyScroll(e.currentTarget)} - onWheel={() => setAutoScroll(false)} + onWheel={(e) => setAutoScroll(hitBottom && e.deltaY > 0)} onTouchStart={() => { inputRef.current?.blur(); setAutoScroll(false); From bb30fdfa1735835b5d51b317d9e3ae0f0d52de30 Mon Sep 17 00:00:00 2001 From: Feifan Zheng <1450849885z@gmail.com> Date: Mon, 3 Apr 2023 12:18:04 +0000 Subject: [PATCH 11/13] feat: optimize usage display --- app/components/settings.tsx | 51 ++++++++++++++++++++++++++++++------- app/icons/eye-off.svg | 4 +++ app/icons/eye.svg | 4 +++ app/locales/cn.ts | 1 + app/locales/en.ts | 1 + app/locales/es.ts | 1 + app/locales/it.ts | 1 + app/locales/tw.ts | 1 + app/styles/globals.scss | 3 ++- 9 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 app/icons/eye-off.svg create mode 100644 app/icons/eye.svg diff --git a/app/components/settings.tsx b/app/components/settings.tsx index 4c5adb86b..936588b79 100644 --- a/app/components/settings.tsx +++ b/app/components/settings.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useRef, useMemo } from "react"; +import { useState, useEffect, useMemo, HTMLProps } from "react"; import EmojiPicker, { Theme as EmojiTheme } from "emoji-picker-react"; @@ -8,6 +8,8 @@ import ResetIcon from "../icons/reload.svg"; import CloseIcon from "../icons/close.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"; @@ -47,6 +49,28 @@ function SettingItem(props: { ); } +function PasswordInput(props: HTMLProps) { + const [visible, setVisible] = useState(false); + + function changeVisibility() { + setVisible(!visible); + } + + return ( + + + : } + onClick={changeVisibility} + /> + + ); +} + export function Settings(props: { closeSettings: () => void }) { const [showEmojiPicker, setShowEmojiPicker] = useState(false); const [config, updateConfig, resetConfig, clearAllData, clearSessions] = @@ -103,6 +127,13 @@ export function Settings(props: { closeSettings: () => void }) { const builtinCount = SearchService.count.builtin; const customCount = promptStore.prompts.size ?? 0; + const showUsage = accessStore.token !== ""; + useEffect(() => { + if (showUsage) { + checkUsage(); + } + }, [showUsage]); + return ( <>
@@ -327,14 +358,14 @@ export function Settings(props: { closeSettings: () => void }) { title={Locale.Settings.AccessCode.Title} subTitle={Locale.Settings.AccessCode.SubTitle} > - { accessStore.updateCode(e.currentTarget.value); }} - > + /> ) : ( <> @@ -344,25 +375,27 @@ export function Settings(props: { closeSettings: () => void }) { title={Locale.Settings.Token.Title} subTitle={Locale.Settings.Token.SubTitle} > - { accessStore.updateToken(e.currentTarget.value); }} - > + /> - {loadingUsage ? ( + {!showUsage || loadingUsage ? (
) : ( + + + \ No newline at end of file diff --git a/app/icons/eye.svg b/app/icons/eye.svg new file mode 100644 index 000000000..b5df29d5b --- /dev/null +++ b/app/icons/eye.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 8f2193b3d..49bcce235 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -109,6 +109,7 @@ const cn = { }, IsChecking: "正在检查…", Check: "重新检查", + NoAccess: "输入API Key查看余额", }, AccessCode: { Title: "访问码", diff --git a/app/locales/en.ts b/app/locales/en.ts index d8e9c615e..ae8e88c2d 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -111,6 +111,7 @@ const en: LocaleType = { }, IsChecking: "Checking...", Check: "Check Again", + NoAccess: "Enter API Key to check balance", }, AccessCode: { Title: "Access Code", diff --git a/app/locales/es.ts b/app/locales/es.ts index 34fcec76c..f3714ef3b 100644 --- a/app/locales/es.ts +++ b/app/locales/es.ts @@ -111,6 +111,7 @@ const es: LocaleType = { }, IsChecking: "Comprobando...", Check: "Comprobar de nuevo", + NoAccess: "Introduzca la clave API para comprobar el saldo", }, AccessCode: { Title: "Código de acceso", diff --git a/app/locales/it.ts b/app/locales/it.ts index 8c4e01233..c4736c1e0 100644 --- a/app/locales/it.ts +++ b/app/locales/it.ts @@ -112,6 +112,7 @@ const it: LocaleType = { }, IsChecking: "Controllando...", Check: "Controlla ancora", + NoAccess: "Inserire la chiave API per controllare il saldo", }, AccessCode: { Title: "Codice d'accesso", diff --git a/app/locales/tw.ts b/app/locales/tw.ts index 3779a5672..fff2f15dc 100644 --- a/app/locales/tw.ts +++ b/app/locales/tw.ts @@ -109,6 +109,7 @@ const tw: LocaleType = { }, IsChecking: "正在檢查…", Check: "重新檢查", + NoAccess: "輸入API Key查看餘額", }, AccessCode: { Title: "訪問碼", diff --git a/app/styles/globals.scss b/app/styles/globals.scss index 73b9b36f3..48f56995b 100644 --- a/app/styles/globals.scss +++ b/app/styles/globals.scss @@ -184,7 +184,8 @@ input[type="range"]::-webkit-slider-thumb:hover { } input[type="number"], -input[type="text"] { +input[type="text"], +input[type="password"] { appearance: none; border-radius: 10px; border: var(--border-in-light); From 4e644cfca70914371586e8761fe63791c7a6b04e Mon Sep 17 00:00:00 2001 From: yidadaa Date: Tue, 4 Apr 2023 01:05:33 +0800 Subject: [PATCH 12/13] fix: #418 valid model config --- app/components/settings.module.scss | 9 +++++ app/components/settings.tsx | 41 +++++++++++-------- app/requests.ts | 7 +--- app/store/app.ts | 62 ++++++++++++++--------------- 4 files changed, 64 insertions(+), 55 deletions(-) diff --git a/app/components/settings.module.scss b/app/components/settings.module.scss index ad994f68d..7d40d83b8 100644 --- a/app/components/settings.module.scss +++ b/app/components/settings.module.scss @@ -18,3 +18,12 @@ .avatar { cursor: pointer; } + +.password-input { + display: flex; + justify-content: flex-end; + + .password-eye { + margin-right: 4px; + } +} diff --git a/app/components/settings.tsx b/app/components/settings.tsx index 936588b79..4645f3191 100644 --- a/app/components/settings.tsx +++ b/app/components/settings.tsx @@ -21,6 +21,7 @@ import { ALL_MODELS, useUpdateStore, useAccessStore, + ModalConfigValidator, } from "../store"; import { Avatar } from "./chat"; @@ -30,6 +31,7 @@ import Link from "next/link"; import { UPDATE_URL } from "../constant"; import { SearchService, usePromptStore } from "../store/prompt"; import { requestUsage } from "../requests"; +import { ErrorBoundary } from "./error"; function SettingItem(props: { title: string; @@ -57,17 +59,14 @@ function PasswordInput(props: HTMLProps) { } return ( - - +
: } onClick={changeVisibility} + className={styles["password-eye"]} /> - + +
); } @@ -115,11 +114,13 @@ export function Settings(props: { closeSettings: () => void }) { useEffect(() => { checkUpdate(); checkUsage(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const accessStore = useAccessStore(); const enabledAccessControl = useMemo( () => accessStore.enabledAccessControl(), + // eslint-disable-next-line react-hooks/exhaustive-deps [], ); @@ -135,7 +136,7 @@ export function Settings(props: { closeSettings: () => void }) { }, [showUsage]); return ( - <> +
@@ -453,7 +454,9 @@ export function Settings(props: { closeSettings: () => void }) { onChange={(e) => { updateConfig( (config) => - (config.modelConfig.model = e.currentTarget.value), + (config.modelConfig.model = ModalConfigValidator.model( + e.currentTarget.value, + )), ); }} > @@ -470,7 +473,7 @@ export function Settings(props: { closeSettings: () => void }) { > void }) { updateConfig( (config) => (config.modelConfig.temperature = - e.currentTarget.valueAsNumber), + ModalConfigValidator.temperature( + e.currentTarget.valueAsNumber, + )), ); }} > @@ -490,13 +495,15 @@ export function Settings(props: { closeSettings: () => void }) { updateConfig( (config) => (config.modelConfig.max_tokens = - e.currentTarget.valueAsNumber), + ModalConfigValidator.max_tokens( + e.currentTarget.valueAsNumber, + )), ) } > @@ -507,7 +514,7 @@ export function Settings(props: { closeSettings: () => void }) { > void }) { updateConfig( (config) => (config.modelConfig.presence_penalty = - e.currentTarget.valueAsNumber), + ModalConfigValidator.presence_penalty( + e.currentTarget.valueAsNumber, + )), ); }} >
- + ); } diff --git a/app/requests.ts b/app/requests.ts index ee3103b77..da9b5c97f 100644 --- a/app/requests.ts +++ b/app/requests.ts @@ -1,5 +1,5 @@ import type { ChatRequest, ChatReponse } from "./api/openai/typing"; -import { filterConfig, Message, ModelConfig, useAccessStore } from "./store"; +import { Message, ModelConfig, useAccessStore } from "./store"; import Locale from "./locales"; import { showToast } from "./components/ui-lib"; @@ -123,11 +123,6 @@ export async function requestChatStream( filterBot: options?.filterBot, }); - // valid and assign model config - if (options?.modelConfig) { - Object.assign(req, filterConfig(options.modelConfig)); - } - console.log("[Request] ", req); const controller = new AbortController(); diff --git a/app/store/app.ts b/app/store/app.ts index b943c0d97..d01e3cdd5 100644 --- a/app/store/app.ts +++ b/app/store/app.ts @@ -85,43 +85,39 @@ export const ALL_MODELS = [ }, ]; -export function isValidModel(name: string) { - return ALL_MODELS.some((m) => m.name === name && m.available); +export function limitNumber( + x: number, + min: number, + max: number, + defaultValue: number, +) { + if (typeof x !== "number" || isNaN(x)) { + return defaultValue; + } + + return Math.min(max, Math.max(min, x)); } -export function isValidNumber(x: number, min: number, max: number) { - return typeof x === "number" && x <= max && x >= min; +export function limitModel(name: string) { + return ALL_MODELS.some((m) => m.name === name && m.available) + ? name + : ALL_MODELS[4].name; } -export function filterConfig(oldConfig: ModelConfig): Partial { - const config = Object.assign({}, oldConfig); - - const validator: { - [k in keyof ModelConfig]: (x: ModelConfig[keyof ModelConfig]) => boolean; - } = { - model(x) { - return isValidModel(x as string); - }, - max_tokens(x) { - return isValidNumber(x as number, 100, 32000); - }, - presence_penalty(x) { - return isValidNumber(x as number, -2, 2); - }, - temperature(x) { - return isValidNumber(x as number, 0, 2); - }, - }; - - Object.keys(validator).forEach((k) => { - const key = k as keyof ModelConfig; - if (!validator[key](config[key])) { - delete config[key]; - } - }); - - return config; -} +export const ModalConfigValidator = { + model(x: string) { + return limitModel(x); + }, + max_tokens(x: number) { + return limitNumber(x, 0, 32000, 2000); + }, + presence_penalty(x: number) { + return limitNumber(x, -2, 2, 0); + }, + temperature(x: number) { + return limitNumber(x, 0, 2, 1); + }, +}; const DEFAULT_CONFIG: ChatConfig = { historyMessageCount: 4, From 7d7f3716beb10d341fbb1bdc28371eb02a1b86ae Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Tue, 4 Apr 2023 01:06:00 +0800 Subject: [PATCH 13/13] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ca71c996b..40386a005 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ One-Click to deploy your own ChatGPT web UI. - 在 1 分钟内使用 Vercel **免费一键部署** - 精心设计的 UI,响应式设计,支持深色模式 -- 极快的首屏加载速度(~85kb) +- 极快的首屏加载速度(~100kb) - 海量的内置 prompt 列表,来自[中文](https://github.com/PlexPt/awesome-chatgpt-prompts-zh)和[英文](https://github.com/f/awesome-chatgpt-prompts) - 自动压缩上下文聊天记录,在节省 Token 的同时支持超长对话 - 一键导出聊天记录,完整的 Markdown 支持 @@ -31,7 +31,7 @@ One-Click to deploy your own ChatGPT web UI. - **Deploy for free with one-click** on Vercel in under 1 minute - Responsive design, and dark mode -- Fast first screen loading speed (~85kb) +- Fast first screen loading speed (~100kb) - Awesome prompts powered by [awesome-chatgpt-prompts-zh](https://github.com/PlexPt/awesome-chatgpt-prompts-zh) and [awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt-prompts) - Automatically compresses chat history to support long conversations while also saving your tokens - One-click export all chat history with full Markdown support