mirror of
https://github.com/Yidadaa/ChatGPT-Next-Web.git
synced 2025-09-03 05:46:54 +08:00
Compare commits
30 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b7b16aa33b | ||
|
789a779775 | ||
|
fdc8278b90 | ||
|
525a2ff9a7 | ||
|
78c9e66c1f | ||
|
3038dfdb27 | ||
|
7cd9f644ee | ||
|
64e78329ec | ||
|
e49acda806 | ||
|
b79845fcaa | ||
|
76ef5ef9a9 | ||
|
cc053b148d | ||
|
2979df1d82 | ||
|
c305ba3c92 | ||
|
12d4081311 | ||
|
124938ecc9 | ||
|
ea3e8a7459 | ||
|
dc3883ed1a | ||
|
bd69c8f5dd | ||
|
b751861bfb | ||
|
d035523f30 | ||
|
f9906aba7f | ||
|
410695d823 | ||
|
cd198ee1fa | ||
|
2c35c26749 | ||
|
f042d07ee7 | ||
|
4ce5f89c66 | ||
|
e0fa0d1936 | ||
|
96d65f7d39 | ||
|
98fd08d9e5 |
@@ -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
|
||||
|
||||
|
@@ -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",
|
||||
};
|
||||
|
@@ -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 (
|
||||
<div className={chatStyle["chat-input-actions"]}>
|
||||
{couldStop && (
|
||||
<div
|
||||
className={`${chatStyle["chat-input-action"]} clickable`}
|
||||
onClick={stopAll}
|
||||
>
|
||||
<StopIcon />
|
||||
</div>
|
||||
)}
|
||||
{!props.hitBottom && (
|
||||
<div
|
||||
className={`${chatStyle["chat-input-action"]} clickable`}
|
||||
@@ -524,21 +536,44 @@ 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);
|
||||
const content = session.messages[userIndex].content;
|
||||
deleteMessage(userIndex);
|
||||
chatStore.onUserInput(content).then(() => setIsLoading(false));
|
||||
inputRef.current?.focus();
|
||||
};
|
||||
|
||||
const config = useChatStore((state) => state.config);
|
||||
@@ -710,12 +745,20 @@ export function Chat(props: {
|
||||
{Locale.Chat.Actions.Stop}
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={styles["chat-message-top-action"]}
|
||||
onClick={() => onResend(i)}
|
||||
>
|
||||
{Locale.Chat.Actions.Retry}
|
||||
</div>
|
||||
<>
|
||||
<div
|
||||
className={styles["chat-message-top-action"]}
|
||||
onClick={() => onDelete(message.id ?? i)}
|
||||
>
|
||||
{Locale.Chat.Actions.Delete}
|
||||
</div>
|
||||
<div
|
||||
className={styles["chat-message-top-action"]}
|
||||
onClick={() => onResend(message.id ?? i)}
|
||||
>
|
||||
{Locale.Chat.Actions.Retry}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div
|
||||
|
@@ -32,3 +32,63 @@
|
||||
min-width: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
.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 {
|
||||
}
|
||||
}
|
||||
|
@@ -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";
|
||||
|
||||
@@ -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,14 +27,114 @@ 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(props: { onClose?: () => void }) {
|
||||
const promptStore = usePromptStore();
|
||||
const userPrompts = promptStore.getUserPrompts();
|
||||
const builtinPrompts = SearchService.builtinPrompts;
|
||||
const allPrompts = userPrompts.concat(builtinPrompts);
|
||||
const [searchInput, setSearchInput] = useState("");
|
||||
const [searchPrompts, setSearchPrompts] = useState<Prompt[]>([]);
|
||||
const prompts = searchInput.length > 0 ? searchPrompts : allPrompts;
|
||||
|
||||
useEffect(() => {
|
||||
if (searchInput.length > 0) {
|
||||
const searchResult = SearchService.search(searchInput);
|
||||
setSearchPrompts(searchResult);
|
||||
} else {
|
||||
setSearchPrompts([]);
|
||||
}
|
||||
}, [searchInput]);
|
||||
|
||||
return (
|
||||
<div className="modal-mask">
|
||||
<Modal
|
||||
title={Locale.Settings.Prompt.Modal.Title}
|
||||
onClose={() => props.onClose?.()}
|
||||
actions={[
|
||||
<IconButton
|
||||
key="add"
|
||||
onClick={() => promptStore.add({ title: "", content: "" })}
|
||||
icon={<ClearIcon />}
|
||||
bordered
|
||||
text={Locale.Settings.Prompt.Modal.Add}
|
||||
/>,
|
||||
]}
|
||||
>
|
||||
<div className={styles["user-prompt-modal"]}>
|
||||
<input
|
||||
type="text"
|
||||
className={styles["user-prompt-search"]}
|
||||
placeholder={Locale.Settings.Prompt.Modal.Search}
|
||||
value={searchInput}
|
||||
onInput={(e) => setSearchInput(e.currentTarget.value)}
|
||||
></input>
|
||||
|
||||
<div className={styles["user-prompt-list"]}>
|
||||
{prompts.map((v, _) => (
|
||||
<div className={styles["user-prompt-item"]} key={v.id ?? v.title}>
|
||||
<div className={styles["user-prompt-header"]}>
|
||||
<input
|
||||
type="text"
|
||||
className={styles["user-prompt-title"]}
|
||||
value={v.title}
|
||||
readOnly={!v.isUser}
|
||||
onChange={(e) => {
|
||||
if (v.isUser) {
|
||||
promptStore.updateUserPrompts(
|
||||
v.id!,
|
||||
(prompt) => (prompt.title = e.currentTarget.value),
|
||||
);
|
||||
}
|
||||
}}
|
||||
></input>
|
||||
|
||||
<div className={styles["user-prompt-buttons"]}>
|
||||
{v.isUser && (
|
||||
<IconButton
|
||||
icon={<ClearIcon />}
|
||||
bordered
|
||||
className={styles["user-prompt-button"]}
|
||||
onClick={() => promptStore.remove(v.id!)}
|
||||
/>
|
||||
)}
|
||||
<IconButton
|
||||
icon={<CopyIcon />}
|
||||
bordered
|
||||
className={styles["user-prompt-button"]}
|
||||
onClick={() => copyToClipboard(v.content)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Input
|
||||
rows={2}
|
||||
value={v.content}
|
||||
className={styles["user-prompt-content"]}
|
||||
readOnly={!v.isUser}
|
||||
onChange={(e) => {
|
||||
if (v.isUser) {
|
||||
promptStore.updateUserPrompts(
|
||||
v.id!,
|
||||
(prompt) => (prompt.content = e.currentTarget.value),
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SettingItem(props: {
|
||||
title: string;
|
||||
subTitle?: string;
|
||||
@@ -99,18 +200,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();
|
||||
@@ -122,10 +221,12 @@ 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(() => {
|
||||
// checks per minutes
|
||||
checkUpdate();
|
||||
showUsage && checkUsage();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@@ -469,7 +570,7 @@ export function Settings(props: { closeSettings: () => void }) {
|
||||
<IconButton
|
||||
icon={<EditIcon />}
|
||||
text={Locale.Settings.Prompt.Edit}
|
||||
onClick={() => showToast(Locale.WIP)}
|
||||
onClick={() => setShowPromptModal(true)}
|
||||
/>
|
||||
</SettingItem>
|
||||
</List>
|
||||
@@ -555,6 +656,10 @@ export function Settings(props: { closeSettings: () => void }) {
|
||||
></InputRange>
|
||||
</SettingItem>
|
||||
</List>
|
||||
|
||||
{shouldShowPromptModal && (
|
||||
<UserPromptModal onClose={() => setShowPromptModal(false)} />
|
||||
)}
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
@@ -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;
|
||||
|
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" fill="none"><defs><rect id="path_0" x="0" y="0" width="16" height="16" /></defs><g opacity="1" transform="translate(0 0) rotate(0 8 8)"><mask id="bg-mask-0" fill="white"><use xlink:href="#path_0"></use></mask><g mask="url(#bg-mask-0)" ><path id="路径 1" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(8.002766666666666 2) rotate(0 0 4.649916666666667)" d="M0,9.3L0,0 " /><path id="路径 2" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(4 7.333333333333333) rotate(0 4 2)" d="M8,0L4,4L0,0 " /><path id="路径 3" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(4 14) rotate(0 4 0)" d="M8,0L0,0 " /></g></g></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" fill="none"><defs><rect id="path_0" x="0" y="0" width="16" height="16" /></defs><g opacity="1" transform="translate(0 0) rotate(0 8 8)"><mask id="bg-mask-0" fill="white"><use xlink:href="#path_0"></use></mask><g mask="url(#bg-mask-0)" ><path id="路径 1" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(4 4) rotate(0 4 2)" d="M8,0L4,4L0,0 " /><path id="路径 2" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(4 8) rotate(0 4 2)" d="M8,0L4,4L0,0 " /></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 958 B After Width: | Height: | Size: 736 B |
1
app/icons/pause.svg
Normal file
1
app/icons/pause.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" fill="none"><defs><rect id="path_0" x="0" y="0" width="16" height="16" /></defs><g opacity="1" transform="translate(0 0) rotate(0 8 8)"><mask id="bg-mask-0" fill="white"><use xlink:href="#path_0"></use></mask><g mask="url(#bg-mask-0)" ><path id="路径 1" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(1.3333333333333333 1.3333333333333333) rotate(0 6.666666666666666 6.666666666666666)" d="M13.33,6.67C13.33,2.98 10.35,0 6.67,0C2.98,0 0,2.98 0,6.67C0,10.35 2.98,13.33 6.67,13.33C10.35,13.33 13.33,10.35 13.33,6.67Z " /><path id="路径 2" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(6.333333333333333 6) rotate(0 0 2)" d="M0,0L0,4 " /><path id="路径 3" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(9.666666666666666 6) rotate(0 0 2)" d="M0,0L0,4 " /></g></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
@@ -17,6 +17,7 @@ const cn = {
|
||||
Copy: "复制",
|
||||
Stop: "停止",
|
||||
Retry: "重试",
|
||||
Delete: "删除",
|
||||
},
|
||||
Rename: "重命名对话",
|
||||
Typing: "正在输入…",
|
||||
@@ -58,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: {
|
||||
@@ -74,6 +75,7 @@ const cn = {
|
||||
it: "Italiano",
|
||||
tr: "Türkçe",
|
||||
jp: "日本語",
|
||||
de: "Deutsch",
|
||||
},
|
||||
},
|
||||
Avatar: "头像",
|
||||
@@ -103,6 +105,11 @@ const cn = {
|
||||
ListCount: (builtin: number, custom: number) =>
|
||||
`内置 ${builtin} 条,用户定义 ${custom} 条`,
|
||||
Edit: "编辑",
|
||||
Modal: {
|
||||
Title: "提示词列表",
|
||||
Add: "增加一条",
|
||||
Search: "搜尋提示詞",
|
||||
},
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "附带历史消息数",
|
||||
|
189
app/locales/de.ts
Normal file
189
app/locales/de.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
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",
|
||||
Modal: {
|
||||
Title: "Prompt List",
|
||||
Add: "Add One",
|
||||
Search: "Search Prompts",
|
||||
},
|
||||
},
|
||||
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;
|
@@ -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",
|
||||
@@ -105,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",
|
||||
@@ -126,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: {
|
||||
|
@@ -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",
|
||||
@@ -105,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",
|
||||
|
@@ -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;
|
||||
|
@@ -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",
|
||||
@@ -105,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",
|
||||
@@ -116,7 +123,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 +131,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",
|
||||
|
@@ -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: "アバター",
|
||||
@@ -106,6 +108,11 @@ const jp = {
|
||||
ListCount: (builtin: number, custom: number) =>
|
||||
`組み込み ${builtin} 件、ユーザー定義 ${custom} 件`,
|
||||
Edit: "編集",
|
||||
Modal: {
|
||||
Title: "提示词列表",
|
||||
Add: "增加一条",
|
||||
Search: "搜尋提示詞",
|
||||
},
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "履歴メッセージ数を添付",
|
||||
@@ -177,6 +184,4 @@ const jp = {
|
||||
},
|
||||
};
|
||||
|
||||
export type LocaleType = typeof jp;
|
||||
|
||||
export default jp;
|
||||
|
@@ -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",
|
||||
@@ -105,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ı",
|
||||
|
@@ -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: "大頭貼",
|
||||
@@ -103,6 +105,11 @@ const tw: LocaleType = {
|
||||
ListCount: (builtin: number, custom: number) =>
|
||||
`內置 ${builtin} 條,用戶定義 ${custom} 條`,
|
||||
Edit: "編輯",
|
||||
Modal: {
|
||||
Title: "提示詞列表",
|
||||
Add: "增加一條",
|
||||
Search: "搜索提示词",
|
||||
},
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "附帶歷史訊息數",
|
||||
@@ -152,7 +159,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.",
|
||||
},
|
||||
|
@@ -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[],
|
||||
@@ -114,6 +114,10 @@ export async function requestUsage() {
|
||||
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,
|
||||
subscription: total.hard_limit_usd,
|
||||
@@ -167,15 +171,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 +238,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];
|
||||
|
@@ -386,6 +386,7 @@ export const useChatStore = create<ChatStore>()(
|
||||
const botMessage: Message = createMessage({
|
||||
role: "assistant",
|
||||
streaming: true,
|
||||
id: userMessage.id! + 1,
|
||||
});
|
||||
|
||||
// get recent messages
|
||||
@@ -421,7 +422,7 @@ export const useChatStore = create<ChatStore>()(
|
||||
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;
|
||||
|
@@ -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<number, Prompt>;
|
||||
prompts: Record<number, Prompt>;
|
||||
|
||||
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<Prompt>([], { keys: ["title"] }),
|
||||
builtinEngine: new Fuse<Prompt>([], { keys: ["title"] }),
|
||||
userEngine: new Fuse<Prompt>([], { 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<PromptStore>()(
|
||||
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<PromptStore>()(
|
||||
|
||||
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,24 +137,27 @@ export const usePromptStore = create<PromptStore>()(
|
||||
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 allPromptsForSearch = builtinPrompts.reduce(
|
||||
(pre, cur) => pre.concat(cur),
|
||||
[],
|
||||
},
|
||||
);
|
||||
|
||||
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);
|
||||
});
|
||||
},
|
||||
},
|
||||
|
@@ -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<string>;
|
||||
getLatestVersion: (force?: boolean) => Promise<void>;
|
||||
updateUsage: (force?: boolean) => Promise<void>;
|
||||
}
|
||||
|
||||
export const UPDATE_KEY = "chat-update";
|
||||
@@ -26,22 +32,27 @@ function queryMeta(key: string, defaultValue?: string): string {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const ONE_MINUTE = 60 * 1000;
|
||||
|
||||
export const useUpdateStore = create<UpdateStore>()(
|
||||
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;
|
||||
|
||||
set(() => ({
|
||||
lastUpdate: Date.now(),
|
||||
}));
|
||||
|
||||
try {
|
||||
// const data = await (await fetch(FETCH_TAG_URL)).json();
|
||||
@@ -49,14 +60,26 @@ export const useUpdateStore = create<UpdateStore>()(
|
||||
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);
|
||||
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;
|
||||
|
||||
set(() => ({
|
||||
lastUpdateUsage: Date.now(),
|
||||
}));
|
||||
|
||||
const usage = await requestUsage();
|
||||
|
||||
if (usage) {
|
||||
set(() => usage);
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
@@ -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 {
|
||||
|
@@ -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(
|
||||
|
@@ -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.1-canary.8",
|
||||
"node-fetch": "^3.3.1",
|
||||
"openai": "^3.2.1",
|
||||
"react": "^18.2.0",
|
||||
|
1
scripts/.gitignore
vendored
Normal file
1
scripts/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
proxychains.conf
|
5
scripts/init-proxy.sh
Normal file
5
scripts/init-proxy.sh
Normal file
@@ -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
|
12
scripts/proxychains.template.conf
Normal file
12
scripts/proxychains.template.conf
Normal file
@@ -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
|
145
yarn.lock
145
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.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,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.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-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.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-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.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-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.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-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.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-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.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-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.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-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.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-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.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"
|
||||
@@ -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.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.2.4"
|
||||
"@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-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.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"
|
||||
@@ -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"
|
||||
|
Reference in New Issue
Block a user