This commit is contained in:
GH Action - Upstream Sync 2023-05-14 01:02:07 +00:00
commit d1bdf4a292
17 changed files with 131 additions and 85 deletions

View File

@ -31,7 +31,7 @@ One-Click to deploy well-designed ChatGPT web UI on Vercel.
- New in v2: create, share and debug your chat tools with prompt templates (mask) - New in v2: create, share and debug your chat tools with prompt templates (mask)
- Awesome prompts powered by [awesome-chatgpt-prompts-zh](https://github.com/PlexPt/awesome-chatgpt-prompts-zh) and [awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt-prompts) - Awesome prompts powered by [awesome-chatgpt-prompts-zh](https://github.com/PlexPt/awesome-chatgpt-prompts-zh) and [awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt-prompts)
- Automatically compresses chat history to support long conversations while also saving your tokens - Automatically compresses chat history to support long conversations while also saving your tokens
- I18n: English, 简体中文, 繁体中文, 日本語, Español, Italiano, Türkçe, Deutsch - I18n: English, 简体中文, 繁体中文, 日本語, Español, Italiano, Türkçe, Deutsch, Tiếng Việt, Русский, Čeština
## Roadmap ## Roadmap
@ -62,7 +62,7 @@ One-Click to deploy well-designed ChatGPT web UI on Vercel.
- 预制角色功能(面具),方便地创建、分享和调试你的个性化对话 - 预制角色功能(面具),方便地创建、分享和调试你的个性化对话
- 海量的内置 prompt 列表,来自[中文](https://github.com/PlexPt/awesome-chatgpt-prompts-zh)和[英文](https://github.com/f/awesome-chatgpt-prompts) - 海量的内置 prompt 列表,来自[中文](https://github.com/PlexPt/awesome-chatgpt-prompts-zh)和[英文](https://github.com/f/awesome-chatgpt-prompts)
- 自动压缩上下文聊天记录,在节省 Token 的同时支持超长对话 - 自动压缩上下文聊天记录,在节省 Token 的同时支持超长对话
- 多国语言支持English, 简体中文, 繁体中文, 日本語, Español, Italiano, Türkçe, Deutsch - 多国语言支持English, 简体中文, 繁体中文, 日本語, Español, Italiano, Türkçe, Deutsch, Tiếng Việt, Русский, Čeština
- 拥有自己的域名?好上加好,绑定后即可在任何地方**无障碍**快速访问 - 拥有自己的域名?好上加好,绑定后即可在任何地方**无障碍**快速访问
## 开发计划 ## 开发计划

View File

@ -16,6 +16,7 @@ import { Link, useNavigate } from "react-router-dom";
import { Path } from "../constant"; import { Path } from "../constant";
import { MaskAvatar } from "./mask"; import { MaskAvatar } from "./mask";
import { Mask } from "../store/mask"; import { Mask } from "../store/mask";
import { useRef, useEffect } from "react";
export function ChatItem(props: { export function ChatItem(props: {
onClick?: () => void; onClick?: () => void;
@ -29,6 +30,14 @@ export function ChatItem(props: {
narrow?: boolean; narrow?: boolean;
mask: Mask; mask: Mask;
}) { }) {
const draggableRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
if (props.selected && draggableRef.current) {
draggableRef.current?.scrollIntoView({
block: "center",
});
}
}, [props.selected]);
return ( return (
<Draggable draggableId={`${props.id}`} index={props.index}> <Draggable draggableId={`${props.id}`} index={props.index}>
{(provided) => ( {(provided) => (
@ -37,7 +46,10 @@ export function ChatItem(props: {
props.selected && styles["chat-item-selected"] props.selected && styles["chat-item-selected"]
}`} }`}
onClick={props.onClick} onClick={props.onClick}
ref={provided.innerRef} ref={(ele) => {
draggableRef.current = ele;
provided.innerRef(ele);
}}
{...provided.draggableProps} {...provided.draggableProps}
{...provided.dragHandleProps} {...provided.dragHandleProps}
title={`${props.title}\n${Locale.ChatItem.ChatItemCount( title={`${props.title}\n${Locale.ChatItem.ChatItemCount(

View File

@ -64,17 +64,17 @@ export function useSwitchTheme() {
} }
const metaDescriptionDark = document.querySelector( const metaDescriptionDark = document.querySelector(
'meta[name="theme-color"][media]', 'meta[name="theme-color"][media*="dark"]',
); );
const metaDescriptionLight = document.querySelector( const metaDescriptionLight = document.querySelector(
'meta[name="theme-color"]:not([media])', 'meta[name="theme-color"][media*="light"]',
); );
if (config.theme === "auto") { if (config.theme === "auto") {
metaDescriptionDark?.setAttribute("content", "#151515"); metaDescriptionDark?.setAttribute("content", "#151515");
metaDescriptionLight?.setAttribute("content", "#fafafa"); metaDescriptionLight?.setAttribute("content", "#fafafa");
} else { } else {
const themeColor = getCSSVar("--themeColor"); const themeColor = getCSSVar("--theme-color");
metaDescriptionDark?.setAttribute("content", themeColor); metaDescriptionDark?.setAttribute("content", themeColor);
metaDescriptionLight?.setAttribute("content", themeColor); metaDescriptionLight?.setAttribute("content", themeColor);
} }

View File

@ -573,9 +573,9 @@ export function Settings() {
<List> <List>
<ModelConfigList <ModelConfigList
modelConfig={config.modelConfig} modelConfig={config.modelConfig}
updateConfig={(upater) => { updateConfig={(updater) => {
const modelConfig = { ...config.modelConfig }; const modelConfig = { ...config.modelConfig };
upater(modelConfig); updater(modelConfig);
config.update((config) => (config.modelConfig = modelConfig)); config.update((config) => (config.modelConfig = modelConfig));
}} }}
/> />

View File

@ -9,11 +9,19 @@ const buildConfig = getBuildConfig();
export const metadata = { export const metadata = {
title: "ChatGPT Next Web", title: "ChatGPT Next Web",
description: "Your personal ChatGPT Chat Bot.", description: "Your personal ChatGPT Chat Bot.",
viewport: {
width: "device-width",
initialScale: 1,
maximumScale: 1,
},
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "#fafafa" },
{ media: "(prefers-color-scheme: dark)", color: "#151515" },
],
appleWebApp: { appleWebApp: {
title: "ChatGPT Next Web", title: "ChatGPT Next Web",
statusBarStyle: "default", statusBarStyle: "default",
}, },
viewport: "width=device-width, initial-scale=1, maximum-scale=1",
}; };
export default function RootLayout({ export default function RootLayout({
@ -24,22 +32,12 @@ export default function RootLayout({
return ( return (
<html lang="en"> <html lang="en">
<head> <head>
<meta
name="theme-color"
content="#fafafa"
media="(prefers-color-scheme: light)"
/>
<meta
name="theme-color"
content="#151515"
media="(prefers-color-scheme: dark)"
/>
<meta name="version" content={buildConfig.commitId} /> <meta name="version" content={buildConfig.commitId} />
<link rel="manifest" href="/site.webmanifest"></link> <link rel="manifest" href="/site.webmanifest"></link>
<link rel="preconnect" href="https://fonts.proxy.ustclug.org"></link> <link rel="preconnect" href="https://fonts.proxy.ustclug.org"></link>
<link <link
href="https://fonts.proxy.ustclug.org/css2?family=Noto+Sans+SC:wght@300;400;700;900&display=swap"
rel="stylesheet" rel="stylesheet"
href="https://fonts.proxy.ustclug.org/css2?family=Noto+Sans+SC:wght@300;400;700;900&display=swap"
></link> ></link>
<script src="/serviceWorkerRegister.js" defer></script> <script src="/serviceWorkerRegister.js" defer></script>
</head> </head>

View File

@ -78,7 +78,7 @@ const cn = {
tr: "Türkçe", tr: "Türkçe",
jp: "日本語", jp: "日本語",
de: "Deutsch", de: "Deutsch",
vi: "Vietnamese", vi: "Tiếng Việt",
ru: "Русский", ru: "Русский",
cs: "Čeština", cs: "Čeština",
}, },

View File

@ -70,8 +70,8 @@ const cs: LocaleType = {
}, },
Lang: { Lang: {
Name: "Language", // ATTENTION: if you wanna add a new translation, please do not translate this value, leave it as `Language` Name: "Language", // ATTENTION: if you wanna add a new translation, please do not translate this value, leave it as `Language`
All: "Všechny jazyky", All: "Všechny jazyky",
Options: { Options: {
cn: "简体中文", cn: "简体中文",
en: "English", en: "English",
tw: "繁體中文", tw: "繁體中文",
@ -80,7 +80,7 @@ const cs: LocaleType = {
tr: "Türkçe", tr: "Türkçe",
jp: "日本語", jp: "日本語",
de: "Deutsch", de: "Deutsch",
vi: "Vietnamese", vi: "Tiếng Việt",
ru: "Русский", ru: "Русский",
cs: "Čeština", cs: "Čeština",
}, },
@ -166,8 +166,7 @@ const cs: LocaleType = {
}, },
PresencePenlty: { PresencePenlty: {
Title: "Přítomnostní korekce", Title: "Přítomnostní korekce",
SubTitle: SubTitle: "Větší hodnota zvyšuje pravděpodobnost nových témat.",
"Větší hodnota zvyšuje pravděpodobnost nových témat.",
}, },
}, },
Store: { Store: {
@ -182,7 +181,7 @@ const cs: LocaleType = {
"Vytvořte prosím název o čtyřech až pěti slovech vystihující průběh našeho rozhovoru bez jakýchkoli úvodních slov, interpunkčních znamének, uvozovek, teček, symbolů nebo dalšího textu. Odstraňte uvozovky.", "Vytvořte prosím název o čtyřech až pěti slovech vystihující průběh našeho rozhovoru bez jakýchkoli úvodních slov, interpunkčních znamének, uvozovek, teček, symbolů nebo dalšího textu. Odstraňte uvozovky.",
Summarize: Summarize:
"Krátce shrň naši diskusi v rozsahu do 200 slov a použij ji jako podnět pro budoucí kontext.", "Krátce shrň naši diskusi v rozsahu do 200 slov a použij ji jako podnět pro budoucí kontext.",
}, },
}, },
Copy: { Copy: {
Success: "Zkopírováno do schránky", Success: "Zkopírováno do schránky",
@ -231,7 +230,7 @@ const cs: LocaleType = {
More: "Najít více", More: "Najít více",
NotShow: "Nezobrazovat znovu", NotShow: "Nezobrazovat znovu",
ConfirmNoShow: "Potvrdit zakázáníMůžete jej povolit později v nastavení.", ConfirmNoShow: "Potvrdit zakázáníMůžete jej povolit později v nastavení.",
}, },
UI: { UI: {
Confirm: "Potvrdit", Confirm: "Potvrdit",
@ -239,7 +238,7 @@ const cs: LocaleType = {
Close: "Zavřít", Close: "Zavřít",
Create: "Vytvořit", Create: "Vytvořit",
Edit: "Upravit", Edit: "Upravit",
} },
}; };
export default cs; export default cs;

View File

@ -81,7 +81,7 @@ const de: LocaleType = {
tr: "Türkçe", tr: "Türkçe",
jp: "日本語", jp: "日本語",
de: "Deutsch", de: "Deutsch",
vi: "Vietnamese", vi: "Tiếng Việt",
ru: "Русский", ru: "Русский",
cs: "Čeština", cs: "Čeština",
}, },

View File

@ -80,7 +80,7 @@ const en: LocaleType = {
tr: "Türkçe", tr: "Türkçe",
jp: "日本語", jp: "日本語",
de: "Deutsch", de: "Deutsch",
vi: "Vietnamese", vi: "Tiếng Việt",
ru: "Русский", ru: "Русский",
cs: "Čeština", cs: "Čeština",
}, },

View File

@ -80,7 +80,7 @@ const es: LocaleType = {
tr: "Türkçe", tr: "Türkçe",
jp: "日本語", jp: "日本語",
de: "Deutsch", de: "Deutsch",
vi: "Vietnamese", vi: "Tiếng Việt",
ru: "Русский", ru: "Русский",
cs: "Čeština", cs: "Čeština",
}, },

View File

@ -80,7 +80,7 @@ const it: LocaleType = {
tr: "Türkçe", tr: "Türkçe",
jp: "日本語", jp: "日本語",
de: "Deutsch", de: "Deutsch",
vi: "Vietnamese", vi: "Tiếng Việt",
ru: "Русский", ru: "Русский",
cs: "Čeština", cs: "Čeština",
}, },

View File

@ -80,7 +80,7 @@ const jp: LocaleType = {
tr: "Türkçe", tr: "Türkçe",
jp: "日本語", jp: "日本語",
de: "Deutsch", de: "Deutsch",
vi: "Vietnamese", vi: "Tiếng Việt",
ru: "Русский", ru: "Русский",
cs: "Čeština", cs: "Čeština",
}, },

View File

@ -80,56 +80,57 @@ const ru: LocaleType = {
tr: "Türkçe", tr: "Türkçe",
jp: "日本語", jp: "日本語",
de: "Deutsch", de: "Deutsch",
vi: "Vietnamese", vi: "Tiếng Việt",
ru: "Русский", ru: "Русский",
cs: "Čeština", cs: "Čeština",
}, },
}, },
Avatar: "Аватар", Avatar: "Аватар",
FontSize: { FontSize: {
Title: "Размер шрифта", Title: "Размер шрифта",
SubTitle: "Настроить размер шрифта контента чата", SubTitle: "Настроить размер шрифта контента чата",
},
Update: {
Version: (x: string) => `Версия: ${x}`,
IsLatest: "Последняя версия",
CheckUpdate: "Проверить обновление",
IsChecking: "Проверка обновления...",
FoundUpdate: (x: string) => `Найдена новая версия: ${x}`,
GoToUpdate: "Обновить",
},
SendKey: "Клавиша отправки",
Theme: "Тема",
TightBorder: "Узкая граница",
SendPreviewBubble: {
Title: "Отправить предпросмотр",
SubTitle: "Предварительный просмотр markdown в пузыре",
},
Mask: {
Title: "Экран заставки маски",
SubTitle: "Показывать экран заставки маски перед началом нового чата",
},
Prompt: {
Disable: {
Title: "Отключить автозаполнение",
SubTitle: "Ввод / для запуска автозаполнения",
}, },
Update: { List: "Список подсказок",
Version: (x: string) => `Версия: ${x}`, ListCount: (builtin: number, custom: number) =>
IsLatest: "Последняя версия", `${builtin} встроенных, ${custom} пользовательских`,
CheckUpdate: "Проверить обновление", Edit: "Редактировать",
IsChecking: "Проверка обновления...", Modal: {
FoundUpdate: (x: string) => `Найдена новая версия: ${x}`, Title: "Список подсказок",
GoToUpdate: "Обновить", Add: "Добавить",
Search: "Поиск подсказок",
}, },
SendKey: "Клавиша отправки", EditModal: {
Theme: "Тема", Title: "Редактировать подсказку",
TightBorder: "Узкая граница",
SendPreviewBubble: {
Title: "Отправить предпросмотр",
SubTitle: "Предварительный просмотр markdown в пузыре",
}, },
Mask: { },
Title: "Экран заставки маски", HistoryCount: {
SubTitle: "Показывать экран заставки маски перед началом нового чата", Title: "Количество прикрепляемых сообщений",
}, SubTitle:
Prompt: { "Количество отправляемых сообщений, прикрепляемых к каждому запросу",
Disable: {
Title: "Отключить автозаполнение",
SubTitle: "Ввод / для запуска автозаполнения",
},
List: "Список подсказок",
ListCount: (builtin: number, custom: number) =>
`${builtin} встроенных, ${custom} пользовательских`,
Edit: "Редактировать",
Modal: {
Title: "Список подсказок",
Add: "Добавить",
Search: "Поиск подсказок",
},
EditModal: {
Title: "Редактировать подсказку",
},
},
HistoryCount: {
Title: "Количество прикрепляемых сообщений",
SubTitle: "Количество отправляемых сообщений, прикрепляемых к каждому запросу",
}, },
CompressThreshold: { CompressThreshold: {
Title: "Порог сжатия истории", Title: "Порог сжатия истории",
@ -186,7 +187,8 @@ const ru: LocaleType = {
}, },
Copy: { Copy: {
Success: "Скопировано в буфер обмена", Success: "Скопировано в буфер обмена",
Failed: "Не удалось скопировать, пожалуйста, предоставьте разрешение на доступ к буферу обмена", Failed:
"Не удалось скопировать, пожалуйста, предоставьте разрешение на доступ к буферу обмена",
}, },
Context: { Context: {
Toast: (x: any) => `С ${x} контекстными подсказками`, Toast: (x: any) => `С ${x} контекстными подсказками`,
@ -214,7 +216,9 @@ const ru: LocaleType = {
}, },
EditModal: { EditModal: {
Title: (readonly: boolean) => Title: (readonly: boolean) =>
`Редактирование шаблона подсказки ${readonly ? "(только для чтения)" : ""}`, `Редактирование шаблона подсказки ${
readonly ? "(только для чтения)" : ""
}`,
Download: "Скачать", Download: "Скачать",
Clone: "Клонировать", Clone: "Клонировать",
}, },
@ -230,7 +234,8 @@ const ru: LocaleType = {
SubTitle: "Общайтесь с душой за маской", SubTitle: "Общайтесь с душой за маской",
More: "Найти еще", More: "Найти еще",
NotShow: "Не показывать снова", NotShow: "Не показывать снова",
ConfirmNoShow: "Подтвердите отключение? Вы можете включить это позже в настройках.", ConfirmNoShow:
"Подтвердите отключение? Вы можете включить это позже в настройках.",
}, },
UI: { UI: {

View File

@ -80,7 +80,7 @@ const tr: LocaleType = {
tr: "Türkçe", tr: "Türkçe",
jp: "日本語", jp: "日本語",
de: "Deutsch", de: "Deutsch",
vi: "Vietnamese", vi: "Tiếng Việt",
ru: "Русский", ru: "Русский",
cs: "Čeština", cs: "Čeština",
}, },

View File

@ -78,7 +78,7 @@ const tw: LocaleType = {
tr: "Türkçe", tr: "Türkçe",
jp: "日本語", jp: "日本語",
de: "Deutsch", de: "Deutsch",
vi: "Vietnamese", vi: "Tiếng Việt",
ru: "Русский", ru: "Русский",
cs: "Čeština", cs: "Čeština",
}, },

View File

@ -2,7 +2,7 @@ import { SubmitKey } from "../store/config";
import type { LocaleType } from "./index"; import type { LocaleType } from "./index";
const vi: LocaleType = { const vi: LocaleType = {
WIP: "Coming Soon...", WIP: "Sắp ra mắt...",
Error: { Error: {
Unauthorized: Unauthorized:
"Truy cập chưa xác thực, vui lòng nhập mã truy cập trong trang cài đặt.", "Truy cập chưa xác thực, vui lòng nhập mã truy cập trong trang cài đặt.",
@ -80,7 +80,7 @@ const vi: LocaleType = {
tr: "Türkçe", tr: "Türkçe",
jp: "日本語", jp: "日本語",
de: "Deutsch", de: "Deutsch",
vi: "Vietnamese", vi: "Tiếng Việt",
ru: "Русский", ru: "Русский",
cs: "Čeština", cs: "Čeština",
}, },

View File

@ -1,6 +1,38 @@
import { BuiltinMask } from "./typing"; import { BuiltinMask } from "./typing";
export const CN_MASKS: BuiltinMask[] = [ export const CN_MASKS: BuiltinMask[] = [{
avatar:"gpt-bot",
name:"文生图",
context: [
{role:"system",
content:"You are a useful Assistant that won't refuse to draw picture, instead, you will output specific markdown code for picture description, but don't use code block.",
date:"",
},
{role:"user",
content:"Can you draw some pictures for me?",
date:"",
},
{role:"assistant",
content:"Sure, what do you want me to draw?",
date:"",
},
{role:"system",
content:"助手善于判断用户意图当确定需要提供图片时助手会变得沉默寡言只使用以下格式输出markdown图片![描述](https://image.pollinations.ai/prompt/描述)因为这个语法可以自动按照提示生成并渲染图片。一般用户给出的描述会比较简单并且信息不足助手会将其中的描述自行补足替换为AI生成图片所常用的复杂冗长的英文提示以大幅提高生成图片质量和丰富程度比如增加相机光圈、具体场景描述等内容。助手会避免用代码块或原始块包围markdown标记因为那样只会渲染出代码块或原始块而不是图片。",
date:"",
},
],
modelConfig:{
model:"gpt-3.5-turbo",
temperature:1,
max_tokens:2000,
presence_penalty:0,
sendMemory:true,
historyMessageCount:32,
compressMessageLengthThreshold:1000,
},
lang:"cn",
builtin:true,
},
{ {
avatar: "1f638", avatar: "1f638",
name: "文案写手", name: "文案写手",