Merge branch 'Yidadaa:main' into main
This commit is contained in:
commit
cdb3748ca1
|
@ -28,7 +28,7 @@ jobs:
|
||||||
images: yidadaa/chatgpt-next-web
|
images: yidadaa/chatgpt-next-web
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=latest
|
type=raw,value=latest
|
||||||
type=semver,pattern={{version}}
|
type=ref,event=tag
|
||||||
|
|
||||||
-
|
-
|
||||||
name: Set up QEMU
|
name: Set up QEMU
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# .github/workflows/sync.yml
|
||||||
|
name: Sync Fork
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 8 * * *" # 每天0点触发
|
||||||
|
jobs:
|
||||||
|
repo-sync:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: TG908/fork-sync@v1.1
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }} # 这个 token action 会默认配置, 这里只需这样写就行
|
||||||
|
owner: Yidadaa # fork 上游项目 owner
|
||||||
|
head: main # fork 上游项目需要同步的分支
|
||||||
|
base: main # 需要同步到本项目的目标分支
|
14
README.md
14
README.md
|
@ -36,7 +36,17 @@ One-Click to deploy your own ChatGPT web UI.
|
||||||
- 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
|
||||||
- One-click export all chat history with full Markdown support
|
- One-click export all chat history with full Markdown support
|
||||||
|
|
||||||
## 使用
|
## 开发计划 Roadmap
|
||||||
|
- System Prompt: pin a user defined prompt as system prompt 为每个对话设置系统 Prompt [#138](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/138)
|
||||||
|
- User Prompt: user can edit and save custom prompts to prompt list 允许用户自行编辑内置 Prompt 列表
|
||||||
|
- Self-host Model: support llama, alpaca, ChatGLM, BELLE etc. 支持自部署的大语言模型
|
||||||
|
- Plugins: support network search, caculator, any other apis etc. 插件机制,支持联网搜索、计算器、调用其他平台 api [#165](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/165)
|
||||||
|
|
||||||
|
### 不会开发的功能 Not in Plan
|
||||||
|
- User login, accounts, cloud sync 用户登陆、账号管理、消息云同步
|
||||||
|
- UI text customize 界面文字自定义
|
||||||
|
|
||||||
|
## 开始使用
|
||||||
|
|
||||||
1. 准备好你的 [OpenAI API Key](https://platform.openai.com/account/api-keys);
|
1. 准备好你的 [OpenAI API Key](https://platform.openai.com/account/api-keys);
|
||||||
2. 点击右侧按钮开始部署:
|
2. 点击右侧按钮开始部署:
|
||||||
|
@ -191,4 +201,4 @@ docker run -d -p 3000:3000 -e OPENAI_API_KEY="" -e CODE="" yidadaa/chatgpt-next-
|
||||||
|
|
||||||
## LICENSE
|
## LICENSE
|
||||||
|
|
||||||
- [Anti 996 License](https://github.com/kattgu7/Anti-996-License/blob/master/LICENSE_CN_EN)
|
[Anti 996 License](https://github.com/kattgu7/Anti-996-License/blob/master/LICENSE_CN_EN)
|
||||||
|
|
|
@ -218,7 +218,6 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
margin-bottom: 100px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-body-title {
|
.chat-body-title {
|
||||||
|
@ -342,9 +341,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-input-panel {
|
.chat-input-panel {
|
||||||
position: absolute;
|
|
||||||
bottom: 0px;
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
|
@ -57,6 +57,7 @@ const cn = {
|
||||||
cn: "简体中文",
|
cn: "简体中文",
|
||||||
en: "English",
|
en: "English",
|
||||||
tw: "繁體中文",
|
tw: "繁體中文",
|
||||||
|
es: "Español",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Avatar: "头像",
|
Avatar: "头像",
|
||||||
|
|
|
@ -54,11 +54,12 @@ const en: LocaleType = {
|
||||||
Close: "Close",
|
Close: "Close",
|
||||||
},
|
},
|
||||||
Lang: {
|
Lang: {
|
||||||
Name: "语言",
|
Name: "Language",
|
||||||
Options: {
|
Options: {
|
||||||
cn: "简体中文",
|
cn: "简体中文",
|
||||||
en: "English",
|
en: "English",
|
||||||
tw: "繁體中文",
|
tw: "繁體中文",
|
||||||
|
es: "Español",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Avatar: "Avatar",
|
Avatar: "Avatar",
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
import { SubmitKey } from "../store/app";
|
||||||
|
import type { LocaleType } from "./index";
|
||||||
|
|
||||||
|
const es: LocaleType = {
|
||||||
|
WIP: "En construcción...",
|
||||||
|
Error: {
|
||||||
|
Unauthorized:
|
||||||
|
"Acceso no autorizado, por favor ingrese el código de acceso en la página de configuración.",
|
||||||
|
},
|
||||||
|
ChatItem: {
|
||||||
|
ChatItemCount: (count: number) => `${count} mensajes`,
|
||||||
|
},
|
||||||
|
Chat: {
|
||||||
|
SubTitle: (count: number) => `${count} mensajes con ChatGPT`,
|
||||||
|
Actions: {
|
||||||
|
ChatList: "Ir a la lista de chats",
|
||||||
|
CompressedHistory: "Historial de memoria comprimido",
|
||||||
|
Export: "Exportar todos los mensajes como Markdown",
|
||||||
|
Copy: "Copiar",
|
||||||
|
Stop: "Detener",
|
||||||
|
Retry: "Reintentar",
|
||||||
|
},
|
||||||
|
Rename: "Renombrar chat",
|
||||||
|
Typing: "Escribiendo...",
|
||||||
|
Input: (submitKey: string) => {
|
||||||
|
var inputHints = `Escribe algo y presiona ${submitKey} para enviar`;
|
||||||
|
if (submitKey === String(SubmitKey.Enter)) {
|
||||||
|
inputHints += ", presiona Shift + Enter para nueva línea";
|
||||||
|
}
|
||||||
|
return inputHints;
|
||||||
|
},
|
||||||
|
Send: "Enviar",
|
||||||
|
},
|
||||||
|
Export: {
|
||||||
|
Title: "Todos los mensajes",
|
||||||
|
Copy: "Copiar todo",
|
||||||
|
Download: "Descargar",
|
||||||
|
},
|
||||||
|
Memory: {
|
||||||
|
Title: "Historial de memoria",
|
||||||
|
EmptyContent: "Aún no hay nada.",
|
||||||
|
Copy: "Copiar todo",
|
||||||
|
},
|
||||||
|
Home: {
|
||||||
|
NewChat: "Nuevo chat",
|
||||||
|
DeleteChat: "¿Confirmar eliminación de la conversación seleccionada?",
|
||||||
|
},
|
||||||
|
Settings: {
|
||||||
|
Title: "Configuración",
|
||||||
|
SubTitle: "Todas las configuraciones",
|
||||||
|
Actions: {
|
||||||
|
ClearAll: "Borrar todos los datos",
|
||||||
|
ResetAll: "Restablecer todas las configuraciones",
|
||||||
|
Close: "Cerrar",
|
||||||
|
},
|
||||||
|
Lang: {
|
||||||
|
Name: "Language",
|
||||||
|
Options: {
|
||||||
|
cn: "简体中文",
|
||||||
|
en: "Inglés",
|
||||||
|
tw: "繁體中文",
|
||||||
|
es: "Español",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Avatar: "Avatar",
|
||||||
|
FontSize: {
|
||||||
|
Title: "Tamaño de fuente",
|
||||||
|
SubTitle: "Ajustar el tamaño de fuente del contenido del chat",
|
||||||
|
},
|
||||||
|
Update: {
|
||||||
|
Version: (x: string) => `Versión: ${x}`,
|
||||||
|
IsLatest: "Última versión",
|
||||||
|
CheckUpdate: "Buscar actualizaciones",
|
||||||
|
IsChecking: "Buscando actualizaciones...",
|
||||||
|
FoundUpdate: (x: string) => `Se encontró una nueva versión: ${x}`,
|
||||||
|
GoToUpdate: "Actualizar",
|
||||||
|
},
|
||||||
|
SendKey: "Tecla de envío",
|
||||||
|
Theme: "Tema",
|
||||||
|
TightBorder: "Borde ajustado",
|
||||||
|
Prompt: {
|
||||||
|
Disable: {
|
||||||
|
Title: "Desactivar autocompletado",
|
||||||
|
SubTitle: "Escribe / para activar el autocompletado",
|
||||||
|
},
|
||||||
|
List: "Lista de autocompletado",
|
||||||
|
ListCount: (builtin: number, custom: number) =>
|
||||||
|
`${builtin} incorporado, ${custom} definido por el usuario`,
|
||||||
|
Edit: "Editar",
|
||||||
|
},
|
||||||
|
HistoryCount: {
|
||||||
|
Title: "Cantidad de mensajes adjuntos",
|
||||||
|
SubTitle: "Número de mensajes enviados adjuntos por solicitud",
|
||||||
|
},
|
||||||
|
CompressThreshold: {
|
||||||
|
Title: "Umbral de compresión de historial",
|
||||||
|
SubTitle:
|
||||||
|
"Se comprimirán los mensajes si la longitud de los mensajes no comprimidos supera el valor",
|
||||||
|
},
|
||||||
|
Token: {
|
||||||
|
Title: "Clave de API",
|
||||||
|
SubTitle: "Utiliza tu clave para ignorar el límite de código de acceso",
|
||||||
|
Placeholder: "Clave de la API de OpenAI",
|
||||||
|
},
|
||||||
|
Usage: {
|
||||||
|
Title: "Saldo de la cuenta",
|
||||||
|
SubTitle(granted: any, used: any) {
|
||||||
|
return `Total $${granted}, Usado $${used}`;
|
||||||
|
},
|
||||||
|
IsChecking: "Comprobando...",
|
||||||
|
Check: "Comprobar de nuevo",
|
||||||
|
},
|
||||||
|
AccessCode: {
|
||||||
|
Title: "Código de acceso",
|
||||||
|
SubTitle: "Control de acceso habilitado",
|
||||||
|
Placeholder: "Necesita código de acceso",
|
||||||
|
},
|
||||||
|
Model: "Modelo",
|
||||||
|
Temperature: {
|
||||||
|
Title: "Temperatura",
|
||||||
|
SubTitle: "Un valor mayor genera una salida más aleatoria",
|
||||||
|
},
|
||||||
|
MaxTokens: {
|
||||||
|
Title: "Máximo de tokens",
|
||||||
|
SubTitle: "Longitud máxima de tokens de entrada y tokens generados",
|
||||||
|
},
|
||||||
|
PresencePenlty: {
|
||||||
|
Title: "Penalización de presencia",
|
||||||
|
SubTitle:
|
||||||
|
"Un valor mayor aumenta la probabilidad de hablar sobre nuevos temas",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Store: {
|
||||||
|
DefaultTopic: "Nueva conversación",
|
||||||
|
BotHello: "¡Hola! ¿Cómo puedo ayudarte hoy?",
|
||||||
|
Error: "Algo salió mal, por favor intenta nuevamente más tarde.",
|
||||||
|
Prompt: {
|
||||||
|
History: (content: string) =>
|
||||||
|
"Este es un resumen del historial del chat entre la IA y el usuario como recapitulación: " +
|
||||||
|
content,
|
||||||
|
Topic:
|
||||||
|
"Por favor, genera un título de cuatro a cinco palabras que resuma nuestra conversación sin ningún inicio, puntuación, comillas, puntos, símbolos o texto adicional. Elimina las comillas que lo envuelven.",
|
||||||
|
Summarize:
|
||||||
|
"Resuma nuestra discusión brevemente en 50 caracteres o menos para usarlo como un recordatorio para futuros contextos.",
|
||||||
|
},
|
||||||
|
ConfirmClearAll: "¿Confirmar para borrar todos los datos de chat y configuración?",
|
||||||
|
},
|
||||||
|
Copy: {
|
||||||
|
Success: "Copiado al portapapeles",
|
||||||
|
Failed: "La copia falló, por favor concede permiso para acceder al portapapeles",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default es;
|
|
@ -1,10 +1,11 @@
|
||||||
import CN from "./cn";
|
import CN from "./cn";
|
||||||
import EN from "./en";
|
import EN from "./en";
|
||||||
import TW from "./tw";
|
import TW from "./tw";
|
||||||
|
import ES from "./es";
|
||||||
|
|
||||||
export type { LocaleType } from "./cn";
|
export type { LocaleType } from "./cn";
|
||||||
|
|
||||||
export const AllLangs = ["en", "cn", "tw"] as const;
|
export const AllLangs = ["en", "cn", "tw", "es"] as const;
|
||||||
type Lang = (typeof AllLangs)[number];
|
type Lang = (typeof AllLangs)[number];
|
||||||
|
|
||||||
const LANG_KEY = "lang";
|
const LANG_KEY = "lang";
|
||||||
|
@ -44,6 +45,8 @@ export function getLang(): Lang {
|
||||||
return "cn";
|
return "cn";
|
||||||
} else if (lang.includes("tw")) {
|
} else if (lang.includes("tw")) {
|
||||||
return "tw";
|
return "tw";
|
||||||
|
} else if (lang.includes("es")) {
|
||||||
|
return "es";
|
||||||
} else {
|
} else {
|
||||||
return "en";
|
return "en";
|
||||||
}
|
}
|
||||||
|
@ -54,4 +57,4 @@ export function changeLang(lang: Lang) {
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { en: EN, cn: CN, tw: TW }[getLang()];
|
export default { en: EN, cn: CN, tw: TW, es: ES }[getLang()];
|
|
@ -53,11 +53,12 @@ const tw: LocaleType = {
|
||||||
Close: "關閉",
|
Close: "關閉",
|
||||||
},
|
},
|
||||||
Lang: {
|
Lang: {
|
||||||
Name: "語言",
|
Name: "Language",
|
||||||
Options: {
|
Options: {
|
||||||
cn: "简体中文",
|
cn: "简体中文",
|
||||||
en: "English",
|
en: "English",
|
||||||
tw: "繁體中文",
|
tw: "繁體中文",
|
||||||
|
es: "Español",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Avatar: "大頭貼",
|
Avatar: "大頭貼",
|
||||||
|
|
|
@ -9,7 +9,7 @@ const makeRequestParam = (
|
||||||
options?: {
|
options?: {
|
||||||
filterBot?: boolean;
|
filterBot?: boolean;
|
||||||
stream?: boolean;
|
stream?: boolean;
|
||||||
},
|
}
|
||||||
): ChatRequest => {
|
): ChatRequest => {
|
||||||
let sendMessages = messages.map((v) => ({
|
let sendMessages = messages.map((v) => ({
|
||||||
role: v.role,
|
role: v.role,
|
||||||
|
@ -69,10 +69,9 @@ export async function requestChat(messages: Message[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function requestUsage() {
|
export async function requestUsage() {
|
||||||
const res = await requestOpenaiClient("dashboard/billing/credit_grants")(
|
const res = await requestOpenaiClient(
|
||||||
null,
|
"dashboard/billing/credit_grants?_vercel_no_cache=1"
|
||||||
"GET",
|
)(null, "GET");
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = (await res.json()) as {
|
const response = (await res.json()) as {
|
||||||
|
@ -94,7 +93,7 @@ export async function requestChatStream(
|
||||||
onMessage: (message: string, done: boolean) => void;
|
onMessage: (message: string, done: boolean) => void;
|
||||||
onError: (error: Error) => void;
|
onError: (error: Error) => void;
|
||||||
onController?: (controller: AbortController) => void;
|
onController?: (controller: AbortController) => void;
|
||||||
},
|
}
|
||||||
) {
|
) {
|
||||||
const req = makeRequestParam(messages, {
|
const req = makeRequestParam(messages, {
|
||||||
stream: true,
|
stream: true,
|
||||||
|
@ -189,7 +188,7 @@ export const ControllerPool = {
|
||||||
addController(
|
addController(
|
||||||
sessionIndex: number,
|
sessionIndex: number,
|
||||||
messageIndex: number,
|
messageIndex: number,
|
||||||
controller: AbortController,
|
controller: AbortController
|
||||||
) {
|
) {
|
||||||
const key = this.key(sessionIndex, messageIndex);
|
const key = this.key(sessionIndex, messageIndex);
|
||||||
this.controllers[key] = controller;
|
this.controllers[key] = controller;
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
--sidebar-width: 300px;
|
--sidebar-width: 300px;
|
||||||
--window-content-width: calc(100% - var(--sidebar-width));
|
--window-content-width: calc(100% - var(--sidebar-width));
|
||||||
--message-max-width: 80%;
|
--message-max-width: 80%;
|
||||||
--full-height: 100vh;
|
--full-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 600px) {
|
@media only screen and (max-width: 600px) {
|
||||||
|
@ -75,6 +75,9 @@
|
||||||
@include dark;
|
@include dark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
html {
|
||||||
|
height: var(--full-height);
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: var(--gray);
|
background-color: var(--gray);
|
||||||
|
|
Loading…
Reference in New Issue