diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
index 52feae50e..15d324074 100644
--- a/.github/workflows/sync.yml
+++ b/.github/workflows/sync.yml
@@ -31,3 +31,10 @@ jobs:
# Set test_mode true to run tests instead of the true action!!
test_mode: false
+
+ - name: Sync check
+ if: failure()
+ run: |
+ echo "::error::由于权限不足,导致同步失败(这是预期的行为),请前往仓库首页手动执行[Sync fork]。"
+ echo "::error::Due to insufficient permissions, synchronization failed (as expected). Please go to the repository homepage and manually perform [Sync fork]."
+ exit 1
diff --git a/README.md b/README.md
index b2d1e48ce..a6288798a 100644
--- a/README.md
+++ b/README.md
@@ -3,11 +3,15 @@
(null);
const [autoScroll, setAutoScroll] = useState(true);
+ const scrollToBottom = () => {
+ const dom = scrollRef.current;
+ if (dom) {
+ setTimeout(() => (dom.scrollTop = dom.scrollHeight), 1);
+ }
+ };
// auto scroll
useLayoutEffect(() => {
- const dom = scrollRef.current;
- if (dom && autoScroll) {
- setTimeout(() => (dom.scrollTop = dom.scrollHeight), 1);
- }
+ autoScroll && scrollToBottom();
});
return {
scrollRef,
autoScroll,
setAutoScroll,
+ scrollToBottom,
};
}
+export function ChatActions(props: {
+ showPromptModal: () => void;
+ scrollToBottom: () => void;
+ hitBottom: boolean;
+}) {
+ 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);
+ const nextIndex = (themeIndex + 1) % themes.length;
+ const nextTheme = themes[nextIndex];
+ chatStore.updateConfig((config) => (config.theme = nextTheme));
+ }
+
+ // stop all responses
+ const couldStop = ControllerPool.hasPending();
+ const stopAll = () => ControllerPool.stopAll();
+
+ return (
+
+ {couldStop && (
+
+
+
+ )}
+ {!props.hitBottom && (
+
+
+
+ )}
+ {props.hitBottom && (
+
+
+
+ )}
+
+
+ {theme === Theme.Auto ? (
+
+ ) : theme === Theme.Light ? (
+
+ ) : theme === Theme.Dark ? (
+
+ ) : null}
+
+
+ );
+}
+
export function Chat(props: {
showSideBar?: () => void;
sideBarShowing?: boolean;
@@ -350,7 +430,7 @@ export function Chat(props: {
const [beforeInput, setBeforeInput] = useState("");
const [isLoading, setIsLoading] = useState(false);
const { submitKey, shouldSubmit } = useSubmitHandler();
- const { scrollRef, setAutoScroll } = useScrollToBottom();
+ const { scrollRef, setAutoScroll, scrollToBottom } = useScrollToBottom();
const [hitBottom, setHitBottom] = useState(false);
const onChatBodyScroll = (e: HTMLElement) => {
@@ -375,16 +455,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(
@@ -409,7 +479,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;
@@ -467,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);
@@ -533,6 +626,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;
@@ -546,14 +646,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}
@@ -572,12 +665,9 @@ export function Chat(props: {
}
+ icon={}
bordered
- title={Locale.Chat.Actions.CompressedHistory}
- onClick={() => {
- setShowPromptModal(true);
- }}
+ onClick={renameSession}
/>
@@ -656,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}
+
+ >
)}
)}
- {(message.preview || message.content.length === 0) &&
- !isUser ? (
-
- ) : (
- onRightClick(e, message)}
- onDoubleClickCapture={() => {
- if (!isMobileScreen()) return;
- setUserInput(message.content);
- }}
- >
-
-
- )}
+ onRightClick(e, message)}
+ onDoubleClickCapture={() => {
+ if (!isMobileScreen()) return;
+ setUserInput(message.content);
+ }}
+ fontSize={fontSize}
+ parentRef={scrollRef}
+ />
{!isUser && !message.preview && (
@@ -704,6 +800,12 @@ export function Chat(props: {
+
+
setShowPromptModal(true)}
+ scrollToBottom={scrollToBottom}
+ hitBottom={hitBottom}
+ />
);
}
diff --git a/app/global.d.ts b/app/global.d.ts
new file mode 100644
index 000000000..bd1c062de
--- /dev/null
+++ b/app/global.d.ts
@@ -0,0 +1,11 @@
+declare module "*.jpg";
+declare module "*.png";
+declare module "*.woff2";
+declare module "*.woff";
+declare module "*.ttf";
+declare module "*.scss" {
+ const content: Record;
+ export default content;
+}
+
+declare module "*.svg";
diff --git a/app/icons/auto.svg b/app/icons/auto.svg
new file mode 100644
index 000000000..6745dfbd0
--- /dev/null
+++ b/app/icons/auto.svg
@@ -0,0 +1 @@
+
diff --git a/app/icons/bottom.svg b/app/icons/bottom.svg
new file mode 100644
index 000000000..e2cfba2c7
--- /dev/null
+++ b/app/icons/bottom.svg
@@ -0,0 +1 @@
+
diff --git a/app/icons/dark.svg b/app/icons/dark.svg
new file mode 100644
index 000000000..3eebc373e
--- /dev/null
+++ b/app/icons/dark.svg
@@ -0,0 +1 @@
+
diff --git a/app/icons/light.svg b/app/icons/light.svg
new file mode 100644
index 000000000..22cfa1fff
--- /dev/null
+++ b/app/icons/light.svg
@@ -0,0 +1 @@
+
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/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 @@
+
diff --git a/app/locales/cn.ts b/app/locales/cn.ts
index 9973a3c68..391ade2ab 100644
--- a/app/locales/cn.ts
+++ b/app/locales/cn.ts
@@ -17,6 +17,7 @@ const cn = {
Copy: "复制",
Stop: "停止",
Retry: "重试",
+ Delete: "删除",
},
Rename: "重命名对话",
Typing: "正在输入…",
@@ -74,6 +75,7 @@ const cn = {
it: "Italiano",
tr: "Türkçe",
jp: "日本語",
+ de: "Deutsch",
},
},
Avatar: "头像",
diff --git a/app/locales/de.ts b/app/locales/de.ts
new file mode 100644
index 000000000..d373cba50
--- /dev/null
+++ b/app/locales/de.ts
@@ -0,0 +1,184 @@
+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 Gedächtnis-Prompt",
+ Export: "Alle Nachrichten als Markdown exportieren",
+ Copy: "Kopieren",
+ Stop: "Stop",
+ Retry: "Wiederholen",
+ Delete: "Delete",
+ },
+ Rename: "Chat umbenennen",
+ Typing: "Tippen...",
+ Input: (submitKey: string) => {
+ var inputHints = `${submitKey} um zu Senden`;
+ if (submitKey === String(SubmitKey.Enter)) {
+ inputHints += ", Umschalt + Eingabe für 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: "Senden-Taste",
+ Theme: "Erscheinungsbild",
+ TightBorder: "Enger Rahmen",
+ 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:
+ "Komprimierung, wenn die Länge der unkomprimierten Nachrichten den Wert überschreitet",
+ },
+ Token: {
+ Title: "API-Schlüssel",
+ SubTitle:
+ "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 ausgegeben $${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} Kontext-Prompts`,
+ Edit: "Kontext- und Gedächtnis-Prompts",
+ Add: "Hinzufügen",
+ },
+};
+
+export default de;
diff --git a/app/locales/en.ts b/app/locales/en.ts
index bd417aa84..213b02d3e 100644
--- a/app/locales/en.ts
+++ b/app/locales/en.ts
@@ -19,6 +19,7 @@ const en: LocaleType = {
Copy: "Copy",
Stop: "Stop",
Retry: "Retry",
+ Delete: "Delete",
},
Rename: "Rename Chat",
Typing: "Typing…",
@@ -77,6 +78,7 @@ const en: LocaleType = {
it: "Italiano",
tr: "Türkçe",
jp: "日本語",
+ de: "Deutsch",
},
},
Avatar: "Avatar",
diff --git a/app/locales/es.ts b/app/locales/es.ts
index 88bcd2012..5d6eca17a 100644
--- a/app/locales/es.ts
+++ b/app/locales/es.ts
@@ -19,6 +19,7 @@ const es: LocaleType = {
Copy: "Copiar",
Stop: "Detener",
Retry: "Reintentar",
+ Delete: "Delete",
},
Rename: "Renombrar chat",
Typing: "Escribiendo...",
@@ -77,6 +78,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..389304f85 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";
@@ -44,21 +54,13 @@ export function getLang(): Lang {
const lang = getLanguage();
- if (lang.includes("zh") || lang.includes("cn")) {
- return "cn";
- } else if (lang.includes("tw")) {
- return "tw";
- } else if (lang.includes("es")) {
- return "es";
- } else if (lang.includes("it")) {
- return "it";
- } else if (lang.includes("tr")) {
- return "tr";
- } else if (lang.includes("jp")) {
- return "jp";
- } else {
- return "en";
+ for (const option of AllLangs) {
+ if (lang.includes(option)) {
+ return option;
+ }
}
+
+ return "en";
}
export function changeLang(lang: Lang) {
@@ -66,6 +68,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()] as typeof CN;
diff --git a/app/locales/it.ts b/app/locales/it.ts
index 3cd768fed..225238888 100644
--- a/app/locales/it.ts
+++ b/app/locales/it.ts
@@ -19,6 +19,7 @@ const it: LocaleType = {
Copy: "Copia",
Stop: "Stop",
Retry: "Riprova",
+ Delete: "Delete",
},
Rename: "Rinomina Chat",
Typing: "Typing…",
@@ -45,12 +46,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: {
@@ -77,6 +78,7 @@ const it: LocaleType = {
it: "Italiano",
tr: "Türkçe",
jp: "日本語",
+ de: "Deutsch",
},
},
Avatar: "Avatar",
@@ -93,9 +95,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 +118,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 +126,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",
diff --git a/app/locales/jp.ts b/app/locales/jp.ts
index 50ac21609..f4ad741c9 100644
--- a/app/locales/jp.ts
+++ b/app/locales/jp.ts
@@ -18,6 +18,7 @@ const jp = {
Copy: "コピー",
Stop: "停止",
Retry: "リトライ",
+ Delete: "Delete",
},
Rename: "チャットの名前を変更",
Typing: "入力中…",
@@ -76,6 +77,7 @@ const jp = {
it: "Italiano",
tr: "Türkçe",
jp: "日本語",
+ de: "Deutsch",
},
},
Avatar: "アバター",
@@ -177,6 +179,4 @@ const jp = {
},
};
-export type LocaleType = typeof jp;
-
export default jp;
diff --git a/app/locales/tr.ts b/app/locales/tr.ts
index 708d2d7d5..a7ede1926 100644
--- a/app/locales/tr.ts
+++ b/app/locales/tr.ts
@@ -19,6 +19,7 @@ const tr: LocaleType = {
Copy: "Kopyala",
Stop: "Durdur",
Retry: "Tekrar Dene",
+ Delete: "Delete",
},
Rename: "Sohbeti Yeniden Adlandır",
Typing: "Yazıyor…",
@@ -77,6 +78,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 77975b896..1397bb098 100644
--- a/app/locales/tw.ts
+++ b/app/locales/tw.ts
@@ -18,6 +18,7 @@ const tw: LocaleType = {
Copy: "複製",
Stop: "停止",
Retry: "重試",
+ Delete: "刪除",
},
Rename: "重命名對話",
Typing: "正在輸入…",
@@ -75,6 +76,7 @@ const tw: LocaleType = {
it: "Italiano",
tr: "Türkçe",
jp: "日本語",
+ de: "Deutsch",
},
},
Avatar: "大頭貼",
@@ -152,9 +154,10 @@ 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: "確認清除所有對話、設定數據?",
},
diff --git a/app/requests.ts b/app/requests.ts
index 86d180f71..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;
@@ -189,8 +188,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);
@@ -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 56037a5db..4990b6be3 100644
--- a/app/store/app.ts
+++ b/app/store/app.ts
@@ -386,6 +386,7 @@ export const useChatStore = create()(
const botMessage: Message = createMessage({
role: "assistant",
streaming: true,
+ id: userMessage.id! + 1,
});
// get recent messages
@@ -421,7 +422,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/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);
});
diff --git a/app/styles/globals.scss b/app/styles/globals.scss
index 53902d935..cf36ee92b 100644
--- a/app/styles/globals.scss
+++ b/app/styles/globals.scss
@@ -1,4 +1,6 @@
@mixin light {
+ --theme: light;
+
/* color */
--white: white;
--black: rgb(48, 48, 48);
@@ -18,6 +20,8 @@
}
@mixin dark {
+ --theme: dark;
+
/* color */
--white: rgb(30, 30, 30);
--black: rgb(187, 187, 187);
@@ -31,6 +35,10 @@
--border-in-light: 1px solid rgba(255, 255, 255, 0.192);
--theme-color: var(--gray);
+
+ div:not(.no-dark) > svg {
+ filter: invert(0.5);
+ }
}
.light {
@@ -282,10 +290,6 @@ pre {
.clickable {
cursor: pointer;
- div:not(.no-dark) > svg {
- filter: invert(0.5);
- }
-
&:hover {
filter: brightness(0.9);
}
diff --git a/app/utils.ts b/app/utils.ts
index 5c2b06975..0e4a8eaea 100644
--- a/app/utils.ts
+++ b/app/utils.ts
@@ -120,3 +120,7 @@ export function autoGrowTextArea(dom: HTMLTextAreaElement) {
return rows;
}
+
+export function getCSSVar(varName: string) {
+ return getComputedStyle(document.body).getPropertyValue(varName).trim();
+}
diff --git a/docs/faq.en.md b/docs/faq-en.md
similarity index 100%
rename from docs/faq.en.md
rename to docs/faq-en.md
diff --git a/docs/images/enable-actions-sync.jpg b/docs/images/enable-actions-sync.jpg
new file mode 100644
index 000000000..4a69da928
Binary files /dev/null and b/docs/images/enable-actions-sync.jpg differ
diff --git a/docs/images/enable-actions.jpg b/docs/images/enable-actions.jpg
new file mode 100644
index 000000000..a4f4f0f1f
Binary files /dev/null and b/docs/images/enable-actions.jpg differ
diff --git a/docs/images/vercel/vercel-create-1.jpg b/docs/images/vercel/vercel-create-1.jpg
new file mode 100644
index 000000000..f0bbd0028
Binary files /dev/null and b/docs/images/vercel/vercel-create-1.jpg differ
diff --git a/docs/images/vercel/vercel-create-2.jpg b/docs/images/vercel/vercel-create-2.jpg
new file mode 100644
index 000000000..157768a88
Binary files /dev/null and b/docs/images/vercel/vercel-create-2.jpg differ
diff --git a/docs/images/vercel/vercel-create-3.jpg b/docs/images/vercel/vercel-create-3.jpg
new file mode 100644
index 000000000..2eaae1f9f
Binary files /dev/null and b/docs/images/vercel/vercel-create-3.jpg differ
diff --git a/docs/images/vercel/vercel-env-edit.jpg b/docs/images/vercel/vercel-env-edit.jpg
new file mode 100644
index 000000000..5b115935e
Binary files /dev/null and b/docs/images/vercel/vercel-env-edit.jpg differ
diff --git a/docs/images/vercel/vercel-redeploy.jpg b/docs/images/vercel/vercel-redeploy.jpg
new file mode 100644
index 000000000..ee3483fa7
Binary files /dev/null and b/docs/images/vercel/vercel-redeploy.jpg differ
diff --git a/docs/vercel-cn.md b/docs/vercel-cn.md
new file mode 100644
index 000000000..c49229694
--- /dev/null
+++ b/docs/vercel-cn.md
@@ -0,0 +1,39 @@
+# Vercel 的使用说明
+
+## 如何新建项目
+当你从 Github fork 本项目之后,需要重新在 Vercel 创建一个全新的 Vercel 项目来重新部署,你需要按照下列步骤进行。
+
+
+1. 进入 Vercel 控制台首页;
+2. 点击 Add New;
+3. 选择 Project。
+
+
+1. 在 Import Git Repository 处,搜索 chatgpt-next-web;
+2. 选中新 fork 的项目,点击 Import。
+
+
+1. 在项目配置页,点开 Environmane Variables 开始配置环境变量;
+2. 依次新增名为 OPENAI_API_KEY 和 CODE 的环境变量;
+3. 填入环境变量对应的值;
+4. 点击 Add 确认增加环境变量;
+5. 请确保你添加了 OPENAI_API_KEY,否则无法使用;
+6. 点击 Deploy,创建完成,耐心等待 5 分钟左右部署完成。
+
+## 如何增加自定义域名
+[TODO]
+
+## 如何更改环境变量
+
+1. 进去 Vercel 项目内部控制台,点击顶部的 Settings 按钮;
+2. 点击左侧的 Environment Variables;
+3. 点击已有条目的右侧按钮;
+4. 选择 Edit 进行编辑,然后保存即可。
+
+⚠️️ 注意:每次修改完环境变量,你都需要[重新部署项目](#如何重新部署)来让改动生效!
+
+## 如何重新部署
+
+1. 进入 Vercel 项目内部控制台,点击顶部的 Deployments 按钮;
+2. 选择列表最顶部一条的右侧按钮;
+3. 点击 Redeploy 即可重新部署。
\ No newline at end of file
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(
diff --git a/package.json b/package.json
index 9fcb74e77..acca33ce2 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",
@@ -18,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/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
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"