localization: Add additional English translations (#1987)

* Additional English translations
Provide an English version of the readme, and add a few translations
that were missing elsewhere

* Use browser language by default

* Support 'en' and 'vi' as languages

---------

Co-authored-by: Ed Burnette <ed.burnette@hiddenmind.ai>
This commit is contained in:
Ed Burnette
2023-12-03 05:27:38 -05:00
committed by GitHub
parent ed1e41c4f1
commit 15a6b19897
21 changed files with 7668 additions and 202 deletions

View File

@@ -0,0 +1,22 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
"name": "Node.js & TypeScript",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye"
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

339
README.md
View File

@@ -1,114 +1,112 @@
# ChatGPT Web
> 声明:此项目只发布于 GitHub基于 MIT 协议,免费且作为开源学习使用。并且不会有任何形式的卖号、付费服务、讨论群、讨论组等行为。谨防受骗。
> Disclaimer: This project is only published on GitHub, based on the MIT license, free and for open source learning usage. And there will be no any form of account selling, paid service, discussion group, discussion group and other behaviors. Beware of being deceived.
[中文](README.zh.md)
![cover](./docs/c1.png)
![cover2](./docs/c2.png)
- [ChatGPT Web](#chatgpt-web)
- [介绍](#介绍)
- [待实现路线](#待实现路线)
- [前置要求](#前置要求)
- [Introduction](#introduction)
- [To-Do List](#to-do-list)
- [Prerequisites](#prerequisites)
- [Node](#node)
- [PNPM](#pnpm)
- [填写密钥](#填写密钥)
- [安装依赖](#安装依赖)
- [后端](#后端)
- [前端](#前端)
- [测试环境运行](#测试环境运行)
- [后端服务](#后端服务)
- [前端网页](#前端网页)
- [环境变量](#环境变量)
- [打包](#打包)
- [使用 Docker](#使用-docker)
- [Docker 参数示例](#docker-参数示例)
- [Docker build \& Run](#docker-build--run)
- [Docker compose](#docker-compose)
- [防止爬虫抓取](#防止爬虫抓取)
- [使用 Railway 部署](#使用-railway-部署)
- [Railway 环境变量](#railway-环境变量)
- [使用 Sealos 部署](#使用-sealos-部署)
- [手动打包](#手动打包)
- [后端服务](#后端服务-1)
- [前端网页](#前端网页-1)
- [常见问题](#常见问题)
- [参与贡献](#参与贡献)
- [赞助](#赞助)
- [Fill in Keys](#fill-in-keys)
- [Install Dependencies](#install-dependencies)
- [Backend](#backend)
- [Frontend](#frontend)
- [Run in Test Environment](#run-in-test-environment)
- [Backend Service](#backend-service)
- [Frontend Webpage](#frontend-webpage)
- [Environment Variables](#environment-variables)
- [Packaging](#packaging)
- [Use Docker](#use-docker)
- [Docker Parameter Examples](#docker-parameter-examples)
- [Docker Build & Run](#docker-build--run)
- [Docker Compose](#docker-compose)
- [Prevent Crawlers](#prevent-crawlers)
- [Deploy with Railway](#deploy-with-railway)
- [Railway Environment Variables](#railway-environment-variables)
- [Deploy with Sealos](#deploy-with-sealos)
- [Package Manually](#package-manually)
- [Backend Service](#backend-service-1)
- [Frontend Webpage](#frontend-webpage-1)
- [FAQ](#faq)
- [Contributing](#contributing)
- [Sponsors](#sponsors)
- [License](#license)
## 介绍
## Introduction
支持双模型,提供了两种非官方 `ChatGPT API` 方法
Supports dual models and provides two unofficial `ChatGPT API` methods
| 方式 | 免费? | 可靠性 | 质量 |
| --------------------------------------------- | ------ | ---------- | ---- |
| `ChatGPTAPI(gpt-3.5-turbo-0301)` | 否 | 可靠 | 相对较笨 |
| `ChatGPTUnofficialProxyAPI(网页 accessToken)` | | 相对不可靠 | 聪明 |
| Method | Free? | Reliability | Quality |
| ---------------------------------- | ----- | ----------- | ------- |
| `ChatGPTAPI(gpt-3.5-turbo-0301)` | No | Reliable | Relatively stupid |
| `ChatGPTUnofficialProxyAPI(web accessToken)` | Yes | Relatively unreliable | Smart |
对比:
1. `ChatGPTAPI` 使用 `gpt-3.5-turbo` 通过 `OpenAI` 官方 `API` 调用 `ChatGPT`
2. `ChatGPTUnofficialProxyAPI` 使用非官方代理服务器访问 `ChatGPT` 的后端`API`,绕过`Cloudflare`(依赖于第三方服务器,并且有速率限制)
Comparison:
1. `ChatGPTAPI` uses `gpt-3.5-turbo` through `OpenAI` official `API` to call `ChatGPT`
2. `ChatGPTUnofficialProxyAPI` uses unofficial proxy server to access `ChatGPT`'s backend `API`, bypass `Cloudflare` (dependent on third-party servers, and has rate limits)
警告:
1. 你应该首先使用 `API` 方式
2. 使用 `API` 时,如果网络不通,那是国内被墙了,你需要自建代理,绝对不要使用别人的公开代理,那是危险的。
3. 使用 `accessToken` 方式时反向代理将向第三方暴露您的访问令牌,这样做应该不会产生任何不良影响,但在使用这种方法之前请考虑风险。
4. 使用 `accessToken` 时,不管你是国内还是国外的机器,都会使用代理。默认代理为 [pengzhile](https://github.com/pengzhile) 大佬的 `https://ai.fakeopen.com/api/conversation`,这不是后门也不是监听,除非你有能力自己翻过 `CF` 验证,用前请知悉。[社区代理](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy)(注意:只有这两个是推荐,其他第三方来源,请自行甄别)
5. 把项目发布到公共网络时,你应该设置 `AUTH_SECRET_KEY` 变量添加你的密码访问权限,你也应该修改 `index.html` 中的 `title`,防止被关键词搜索到。
Warnings:
1. You should first use the `API` method
2. When using the `API`, if the network is not working, it is blocked in China, you need to build your own proxy, never use someone else's public proxy, which is dangerous.
3. When using the `accessToken` method, the reverse proxy will expose your access token to third parties. This should not have any adverse effects, but please consider the risks before using this method.
4. When using `accessToken`, whether you are a domestic or foreign machine, proxies will be used. The default proxy is [pengzhile](https://github.com/pengzhile)'s `https://ai.fakeopen.com/api/conversation`. This is not a backdoor or monitoring unless you have the ability to flip over `CF` verification yourself. Use beforehand acknowledge. [Community Proxy](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy) (Note: Only these two are recommended, other third-party sources, please identify for yourself)
5. When publishing the project to public network, you should set the `AUTH_SECRET_KEY` variable to add your password access, you should also modify the `title` in `index. html` to prevent it from being searched by keywords.
切换方式:
1. 进入 `service/.env.example` 文件,复制内容到 `service/.env` 文件
2. 使用 `OpenAI API Key` 请填写 `OPENAI_API_KEY` 字段 [(获取 apiKey)](https://platform.openai.com/overview)
3. 使用 `Web API` 请填写 `OPENAI_ACCESS_TOKEN` 字段 [(获取 accessToken)](https://chat.openai.com/api/auth/session)
4. 同时存在时以 `OpenAI API Key` 优先
Switching methods:
1. Enter the `service/.env.example` file, copy the contents to the `service/.env` file
2. To use `OpenAI API Key`, fill in the `OPENAI_API_KEY` field [(get apiKey)](https://platform.openai.com/overview)
3. To use `Web API`, fill in the `OPENAI_ACCESS_TOKEN` field [(get accessToken)](https://chat.openai.com/api/auth/session)
4. `OpenAI API Key` takes precedence when both exist
环境变量:
Environment variables:
全部参数变量请查看或[这里](#环境变量)
See all parameter variables [here](#environment-variables)
```
/service/.env.example
```
## Roadmap
[✓] Dual models
## 待实现路线
[✓] 双模型
[✓] Multi-session storage and context logic
[✓] 多会话储存和上下文逻辑
[✓] Formatting and beautification of code and other message types
[✓] 对代码等消息类型的格式化美化处理
[✓] Access control
[✓] 访问权限控制
[✓] Data import/export
[✓] 数据导入、导出
[✓] Save messages as local images
[✓] 保存消息到本地图片
[✓] Multilingual interface
[✓] 界面多语言
[✓] 界面主题
[✓] Interface themes
[✗] More...
## 前置要求
## Prerequisites
### Node
`node` 需要 `^16 || ^18 || ^19` 版本(`node >= 14` 需要安装 [fetch polyfill](https://github.com/developit/unfetch#usage-as-a-polyfill)),使用 [nvm](https://github.com/nvm-sh/nvm) 可管理本地多个 `node` 版本
`node` requires version `^16 || ^18 || ^19` (`node >= 14` needs [fetch polyfill](https://github.com/developit/unfetch#usage-as-a-polyfill) installation), use [nvm](https://github.com/nvm-sh/nvm) to manage multiple local `node` versions
```shell
node -v
```
### PNPM
如果你没有安装过 `pnpm`
If you haven't installed `pnpm`
```shell
npm install pnpm -g
```
### 填写密钥
获取 `Openai Api Key` `accessToken` 并填写本地环境变量 [跳转](#介绍)
### Filling in the Key
Get `Openai Api Key` or `accessToken` and fill in the local environment variables [Go to Introduction](#introduction)
```
# service/.env 文件
# service/.env file
# OpenAI API Key - https://platform.openai.com/overview
OPENAI_API_KEY=
@@ -117,68 +115,68 @@ OPENAI_API_KEY=
OPENAI_ACCESS_TOKEN=
```
## 安装依赖
## Install Dependencies
> 为了简便 `后端开发人员` 的了解负担,所以并没有采用前端 `workspace` 模式,而是分文件夹存放。如果只需要前端页面做二次开发,删除 `service` 文件夹即可。
> For the convenience of "backend developers" to understand the burden, the front-end "workspace" mode is not adopted, but separate folders are used to store them. If you only need to do secondary development of the front-end page, delete the `service` folder.
### 后端
### Backend
进入文件夹 `/service` 运行以下命令
Enter the folder `/service` and run the following commands
```shell
pnpm install
```
### 前端
根目录下运行以下命令
### Frontend
Run the following commands at the root directory
```shell
pnpm bootstrap
```
## 测试环境运行
### 后端服务
## Run in Test Environment
### Backend Service
进入文件夹 `/service` 运行以下命令
Enter the folder `/service` and run the following commands
```shell
pnpm start
```
### 前端网页
根目录下运行以下命令
### Frontend Webpage
Run the following commands at the root directory
```shell
pnpm dev
```
## 环境变量
## Environment Variables
`API` 可用:
`API` available:
- `OPENAI_API_KEY` `OPENAI_ACCESS_TOKEN` 二选一
- `OPENAI_API_MODEL` 设置模型,可选,默认:`gpt-3.5-turbo`
- `OPENAI_API_BASE_URL` 设置接口地址,可选,默认:`https://api.openai.com`
- `OPENAI_API_DISABLE_DEBUG` 设置接口关闭 debug 日志可选默认empty 不关闭
- `OPENAI_API_KEY` and `OPENAI_ACCESS_TOKEN` choose one
- `OPENAI_API_MODEL` Set model, optional, default: `gpt-3.5-turbo`
- `OPENAI_API_BASE_URL` Set interface address, optional, default: `https://api.openai.com`
- `OPENAI_API_DISABLE_DEBUG` Set interface to close debug logs, optional, default: empty does not close
`ACCESS_TOKEN` 可用:
`ACCESS_TOKEN` available:
- `OPENAI_ACCESS_TOKEN` `OPENAI_API_KEY` 二选一,同时存在时,`OPENAI_API_KEY` 优先
- `API_REVERSE_PROXY` 设置反向代理,可选,默认:`https://ai.fakeopen.com/api/conversation`[社区](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy)(注意:只有这两个是推荐,其他第三方来源,请自行甄别)
- `OPENAI_ACCESS_TOKEN` and `OPENAI_API_KEY` choose one, `OPENAI_API_KEY` takes precedence when both exist
- `API_REVERSE_PROXY` Set reverse proxy, optional, default: `https://ai.fakeopen.com/api/conversation`, [Community](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy) (Note: Only these two are recommended, other third party sources, please identify for yourself)
通用:
Common:
- `AUTH_SECRET_KEY` 访问权限密钥,可选
- `MAX_REQUEST_PER_HOUR` 每小时最大请求次数,可选,默认无限
- `TIMEOUT_MS` 超时,单位毫秒,可选
- `SOCKS_PROXY_HOST` `SOCKS_PROXY_PORT` 一起时生效,可选
- `SOCKS_PROXY_PORT` `SOCKS_PROXY_HOST` 一起时生效,可选
- `HTTPS_PROXY` 支持 `http``https`, `socks5`,可选
- `ALL_PROXY` 支持 `http``https`, `socks5`,可选
- `AUTH_SECRET_KEY` Access permission key, optional
- `MAX_REQUEST_PER_HOUR` Maximum number of requests per hour, optional, unlimited by default
- `TIMEOUT_MS` Timeout, unit milliseconds, optional
- `SOCKS_PROXY_HOST` and `SOCKS_PROXY_PORT` take effect together, optional
- `SOCKS_PROXY_PORT` and `SOCKS_PROXY_HOST` take effect together, optional
- `HTTPS_PROXY` Support `http`, `https`, `socks5`, optional
- `ALL_PROXY` Support `http`, `https`, `socks5`, optional
## 打包
## Packaging
### 使用 Docker
### Use Docker
#### Docker 参数示例
#### Docker Parameter Examples
![docker](./docs/docker.png)
@@ -187,174 +185,175 @@ pnpm dev
```bash
docker build -t chatgpt-web .
# 前台运行
# Foreground running
docker run --name chatgpt-web --rm -it -p 127.0.0.1:3002:3002 --env OPENAI_API_KEY=your_api_key chatgpt-web
# 后台运行
# Background running
docker run --name chatgpt-web -d -p 127.0.0.1:3002:3002 --env OPENAI_API_KEY=your_api_key chatgpt-web
# 运行地址
# Run address
http://localhost:3002/
```
#### Docker compose
[Hub 地址](https://hub.docker.com/repository/docker/chenzhaoyu94/chatgpt-web/general)
[Hub address](https://hub.docker.com/repository/docker/chenzhaoyu94/chatgpt-web/general)
```yml
version: '3'
services:
app:
image: chenzhaoyu94/chatgpt-web # 总是使用 latest ,更新时重新 pull tag 镜像即可
image: chenzhaoyu94/chatgpt-web # always use latest, pull the tag image again to update
ports:
- 127.0.0.1:3002:3002
environment:
# 二选一
# choose one
OPENAI_API_KEY: sk-xxx
# 二选一
# choose one
OPENAI_ACCESS_TOKEN: xxx
# API接口地址,可选,设置 OPENAI_API_KEY 时可用
# API interface address, optional, available when OPENAI_API_KEY is set
OPENAI_API_BASE_URL: xxx
# API模型,可选,设置 OPENAI_API_KEY 时可用,https://platform.openai.com/docs/models
# API model, optional, available when OPENAI_API_KEY is set, https://platform.openai.com/docs/models
# gpt-4, gpt-4-1106-preview, gpt-4-0314, gpt-4-0613, gpt-4-32k, gpt-4-32k-0314, gpt-4-32k-0613, gpt-3.5-turbo-16k, gpt-3.5-turbo-16k-0613, gpt-3.5-turbo, gpt-3.5-turbo-0301, gpt-3.5-turbo-0613, text-davinci-003, text-davinci-002, code-davinci-002
OPENAI_API_MODEL: xxx
# 反向代理,可选
# reverse proxy, optional
API_REVERSE_PROXY: xxx
# 访问权限密钥,可选
# access permission key, optional
AUTH_SECRET_KEY: xxx
# 每小时最大请求次数,可选,默认无限
# maximum number of requests per hour, optional, unlimited by default
MAX_REQUEST_PER_HOUR: 0
# 超时,单位毫秒,可选
# timeout, unit milliseconds, optional
TIMEOUT_MS: 60000
# Socks代理,可选,和 SOCKS_PROXY_PORT 一起时生效
# Socks proxy, optional, take effect with SOCKS_PROXY_PORT
SOCKS_PROXY_HOST: xxx
# Socks代理端口,可选,和 SOCKS_PROXY_HOST 一起时生效
# Socks proxy port, optional, take effect with SOCKS_PROXY_HOST
SOCKS_PROXY_PORT: xxx
# HTTPS 代理,可选,支持 httphttpssocks5
# HTTPS proxy, optional, support http,https,socks5
HTTPS_PROXY: http://xxx:7890
```
- `OPENAI_API_BASE_URL` 可选,设置 `OPENAI_API_KEY` 时可用
- `OPENAI_API_MODEL` 可选,设置 `OPENAI_API_KEY` 时可用
#### 防止爬虫抓取
- `OPENAI_API_BASE_URL` Optional, available when `OPENAI_API_KEY` is set
- `OPENAI_API_MODEL` Optional, available when `OPENAI_API_KEY` is set
#### Prevent Crawlers
**nginx**
将下面配置填入nginx配置文件中可以参考 `docker-compose/nginx/nginx.conf` 文件中添加反爬虫的方法
Fill in the following configuration in the nginx configuration file to prevent crawlers. You can refer to the `docker-compose/nginx/nginx.conf` file to add anti-crawler methods
```
# 防止爬虫抓取
# Prevent crawlers
if ($http_user_agent ~* "360Spider|JikeSpider|Spider|spider|bot|Bot|2345Explorer|curl|wget|webZIP|qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo! Slurp|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot|ia_archiver|Tomato Bot|NSPlayer|bingbot")
{
return 403;
}
```
### 使用 Railway 部署
### Deploy with Railway
[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template/yytmgc)
#### Railway 环境变量
#### Railway Environment Variables
| 环境变量名称 | 必填 | 备注 |
| Environment variable name | Required | Remarks |
| --------------------- | ---------------------- | -------------------------------------------------------------------------------------------------- |
| `PORT` | 必填 | 默认 `3002`
| `AUTH_SECRET_KEY` | 可选 | 访问权限密钥 |
| `MAX_REQUEST_PER_HOUR` | 可选 | 每小时最大请求次数,可选,默认无限 |
| `TIMEOUT_MS` | 可选 | 超时时间,单位毫秒 |
| `OPENAI_API_KEY` | `OpenAI API` 二选一 | 使用 `OpenAI API` 所需的 `apiKey` [(获取 apiKey)](https://platform.openai.com/overview) |
| `OPENAI_ACCESS_TOKEN` | `Web API` 二选一 | 使用 `Web API` 所需的 `accessToken` [(获取 accessToken)](https://chat.openai.com/api/auth/session) |
| `OPENAI_API_BASE_URL` | 可选,`OpenAI API` 时可用 | `API`接口地址 |
| `OPENAI_API_MODEL` | 可选,`OpenAI API` 时可用 | `API`模型 |
| `API_REVERSE_PROXY` | 可选,`Web API` 时可用 | `Web API` 反向代理地址 [详情](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy) |
| `SOCKS_PROXY_HOST` | 可选,和 `SOCKS_PROXY_PORT` 一起时生效 | Socks代理 |
| `SOCKS_PROXY_PORT` | 可选,和 `SOCKS_PROXY_HOST` 一起时生效 | Socks代理端口 |
| `SOCKS_PROXY_USERNAME` | 可选,和 `SOCKS_PROXY_HOST` 一起时生效 | Socks代理用户名 |
| `SOCKS_PROXY_PASSWORD` | 可选,和 `SOCKS_PROXY_HOST` 一起时生效 | Socks代理密码 |
| `HTTPS_PROXY` | 可选 | HTTPS 代理,支持 httphttps, socks5 |
| `ALL_PROXY` | 可选 | 所有代理 代理,支持 httphttps, socks5 |
| `PORT` | Required | Default `3002` |
| `AUTH_SECRET_KEY` | Optional | Access permission key |
| `MAX_REQUEST_PER_HOUR` | Optional | Maximum number of requests per hour, optional, unlimited by default |
| `TIMEOUT_MS` | Optional | Timeout, unit milliseconds |
| `OPENAI_API_KEY` | `OpenAI API` choose one | `apiKey` required for `OpenAI API` [(get apiKey)](https://platform.openai.com/overview) |
| `OPENAI_ACCESS_TOKEN` | `Web API` choose one | `accessToken` required for `Web API` [(get accessToken)](https://chat.openai.com/api/auth/session) |
| `OPENAI_API_BASE_URL` | Optional, available when `OpenAI API` | `API` interface address |
| `OPENAI_API_MODEL` | Optional, available when `OpenAI API` | `API` model |
| `API_REVERSE_PROXY` | Optional, available when `Web API` | `Web API` reverse proxy address [Details](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy) |
| `SOCKS_PROXY_HOST` | Optional, take effect with `SOCKS_PROXY_PORT` | Socks proxy |
| `SOCKS_PROXY_PORT` | Optional, take effect with `SOCKS_PROXY_HOST` | Socks proxy port |
| `SOCKS_PROXY_USERNAME` | Optional, take effect with `SOCKS_PROXY_HOST` | Socks proxy username |
| `SOCKS_PROXY_PASSWORD` | Optional, take effect with `SOCKS_PROXY_HOST` | Socks proxy password |
| `HTTPS_PROXY` | Optional | HTTPS proxy, support http,https, socks5 |
| `ALL_PROXY` | Optional | All proxies, support http,https, socks5 |
> 注意: `Railway` 修改环境变量会重新 `Deploy`
> Note: Modifying environment variables on `Railway` will re-`Deploy`
### 使用 Sealos 部署
### Deploy with Sealos
[![](https://raw.githubusercontent.com/labring-actions/templates/main/Deploy-on-Sealos.svg)](https://cloud.sealos.io/?openapp=system-fastdeploy%3FtemplateName%3Dchatgpt-web)
> 环境变量与 Docker 环境变量一致
> Environment variables are consistent with Docker environment variables
### 手动打包
#### 后端服务
> 如果你不需要本项目的 `node` 接口,可以省略如下操作
### Package Manually
#### Backend Service
> If you don't need the `node` interface of this project, you can omit the following operations
复制 `service` 文件夹到你有 `node` 服务环境的服务器上。
Copy the `service` folder to the server where you have the `node` service environment.
```shell
# 安装
# Install
pnpm install
# 打包
# Pack
pnpm build
# 运行
# Run
pnpm prod
```
PS: 不进行打包,直接在服务器上运行 `pnpm start` 也可
PS: It is also okay to run `pnpm start` directly on the server without packing
#### 前端网页
#### Frontend Webpage
1、修改根目录下 `.env` 文件中的 `VITE_GLOB_API_URL` 为你的实际后端接口地址
1. Modify the `VITE_GLOB_API_URL` field in the `.env` file at the root directory to your actual backend interface address
2、根目录下运行以下命令然后将 `dist` 文件夹内的文件复制到你网站服务的根目录下
2. Run the following commands at the root directory, then copy the files in the `dist` folder to the root directory of your website service
[参考信息](https://cn.vitejs.dev/guide/static-deploy.html#building-the-app)
[Reference](https://cn.vitejs.dev/guide/static -deploy.html#building-the-app)
```shell
pnpm build
```
## 常见问题
Q: 为什么 `Git` 提交总是报错?
## FAQ
Q: Why does `Git` commit always report errors?
A: 因为有提交信息验证,请遵循 [Commit 指南](./CONTRIBUTING.md)
A: Because there is a commit message verification, please follow the [Commit Guide](./CONTRIBUTING.md)
Q: 如果只使用前端页面,在哪里改请求接口?
Q: Where to change the request interface if only the front-end page is used?
A: 根目录下 `.env` 文件中的 `VITE_GLOB_API_URL` 字段。
A: The `VITE_GLOB_API_URL` field in the `.env` file at the root directory.
Q: 文件保存时全部爆红?
Q: All files explode red when saving?
A: `vscode` 请安装项目推荐插件,或手动安装 `Eslint` 插件。
A: `vscode` please install the recommended plug-ins for the project, or manually install the `Eslint` plug-in.
Q: 前端没有打字机效果?
Q: No typewriter effect on the front end?
A: 一种可能原因是经过 Nginx 反向代理,开启了 buffer则 Nginx 会尝试从后端缓冲一定大小的数据再发送给浏览器。请尝试在反代参数后添加 `proxy_buffering off;`,然后重载 Nginx。其他 web server 配置同理。
A: One possible reason is that after Nginx reverse proxy, buffer is turned on, then Nginx will try to buffer some data from the backend before sending it to the browser. Please try adding `proxy_buffering off; ` after the reverse proxy parameter, then reload Nginx. Other web server configurations are similar.
## 参与贡献
## Contributing
贡献之前请先阅读 [贡献指南](./CONTRIBUTING.md)
Please read the [Contributing Guide](./CONTRIBUTING.md) before contributing
感谢所有做过贡献的人!
Thanks to everyone who has contributed!
<a href="https://github.com/Chanzhaoyu/chatgpt-web/graphs/contributors">
<img src="https://contrib.rocks/image?repo=Chanzhaoyu/chatgpt-web" />
</a>
## 赞助
## Sponsors
如果你觉得这个项目对你有帮助,并且情况允许的话,可以给我一点点支持,总之非常感谢支持~
If you find this project helpful and can afford it, you can give me a little support. Anyway, thanks for your support~
<div style="display: flex; gap: 20px;">
<div style="text-align: center">
<img style="max-width: 100%" src="./docs/wechat.png" alt="微信" />
<img style="max-width: 100%" src="./docs/wechat.png" alt="WeChat" />
<p>WeChat Pay</p>
</div>
<div style="text-align: center">
<img style="max-width: 100%" src="./docs/alipay.png" alt="支付宝" />
<img style="max-width: 100%" src="./docs/alipay.png" alt="Alipay" />
<p>Alipay</p>
</div>
</div>
## License
MIT © [ChenZhaoYu](./license)
MIT © [ChenZhaoYu]

362
README.zh.md Normal file
View File

@@ -0,0 +1,362 @@
# ChatGPT Web
> 声明:此项目只发布于 GitHub基于 MIT 协议,免费且作为开源学习使用。并且不会有任何形式的卖号、付费服务、讨论群、讨论组等行为。谨防受骗。
[English](README.md)
![cover](./docs/c1.png)
![cover2](./docs/c2.png)
- [ChatGPT Web](#chatgpt-web)
- [介绍](#介绍)
- [待实现路线](#待实现路线)
- [前置要求](#前置要求)
- [Node](#node)
- [PNPM](#pnpm)
- [填写密钥](#填写密钥)
- [安装依赖](#安装依赖)
- [后端](#后端)
- [前端](#前端)
- [测试环境运行](#测试环境运行)
- [后端服务](#后端服务)
- [前端网页](#前端网页)
- [环境变量](#环境变量)
- [打包](#打包)
- [使用 Docker](#使用-docker)
- [Docker 参数示例](#docker-参数示例)
- [Docker build \& Run](#docker-build--run)
- [Docker compose](#docker-compose)
- [防止爬虫抓取](#防止爬虫抓取)
- [使用 Railway 部署](#使用-railway-部署)
- [Railway 环境变量](#railway-环境变量)
- [使用 Sealos 部署](#使用-sealos-部署)
- [手动打包](#手动打包)
- [后端服务](#后端服务-1)
- [前端网页](#前端网页-1)
- [常见问题](#常见问题)
- [参与贡献](#参与贡献)
- [赞助](#赞助)
- [License](#license)
## 介绍
支持双模型,提供了两种非官方 `ChatGPT API` 方法
| 方式 | 免费? | 可靠性 | 质量 |
| --------------------------------------------- | ------ | ---------- | ---- |
| `ChatGPTAPI(gpt-3.5-turbo-0301)` | 否 | 可靠 | 相对较笨 |
| `ChatGPTUnofficialProxyAPI(网页 accessToken)` | 是 | 相对不可靠 | 聪明 |
对比:
1. `ChatGPTAPI` 使用 `gpt-3.5-turbo` 通过 `OpenAI` 官方 `API` 调用 `ChatGPT`
2. `ChatGPTUnofficialProxyAPI` 使用非官方代理服务器访问 `ChatGPT` 的后端`API`,绕过`Cloudflare`(依赖于第三方服务器,并且有速率限制)
警告:
1. 你应该首先使用 `API` 方式
2. 使用 `API` 时,如果网络不通,那是国内被墙了,你需要自建代理,绝对不要使用别人的公开代理,那是危险的。
3. 使用 `accessToken` 方式时反向代理将向第三方暴露您的访问令牌,这样做应该不会产生任何不良影响,但在使用这种方法之前请考虑风险。
4. 使用 `accessToken` 时,不管你是国内还是国外的机器,都会使用代理。默认代理为 [pengzhile](https://github.com/pengzhile) 大佬的 `https://ai.fakeopen.com/api/conversation`,这不是后门也不是监听,除非你有能力自己翻过 `CF` 验证,用前请知悉。[社区代理](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy)(注意:只有这两个是推荐,其他第三方来源,请自行甄别)
5. 把项目发布到公共网络时,你应该设置 `AUTH_SECRET_KEY` 变量添加你的密码访问权限,你也应该修改 `index.html` 中的 `title`,防止被关键词搜索到。
切换方式:
1. 进入 `service/.env.example` 文件,复制内容到 `service/.env` 文件
2. 使用 `OpenAI API Key` 请填写 `OPENAI_API_KEY` 字段 [(获取 apiKey)](https://platform.openai.com/overview)
3. 使用 `Web API` 请填写 `OPENAI_ACCESS_TOKEN` 字段 [(获取 accessToken)](https://chat.openai.com/api/auth/session)
4. 同时存在时以 `OpenAI API Key` 优先
环境变量:
全部参数变量请查看或[这里](#环境变量)
```
/service/.env.example
```
## 待实现路线
[✓] 双模型
[✓] 多会话储存和上下文逻辑
[✓] 对代码等消息类型的格式化美化处理
[✓] 访问权限控制
[✓] 数据导入、导出
[✓] 保存消息到本地图片
[✓] 界面多语言
[✓] 界面主题
[✗] More...
## 前置要求
### Node
`node` 需要 `^16 || ^18 || ^19` 版本(`node >= 14` 需要安装 [fetch polyfill](https://github.com/developit/unfetch#usage-as-a-polyfill)),使用 [nvm](https://github.com/nvm-sh/nvm) 可管理本地多个 `node` 版本
```shell
node -v
```
### PNPM
如果你没有安装过 `pnpm`
```shell
npm install pnpm -g
```
### 填写密钥
获取 `Openai Api Key``accessToken` 并填写本地环境变量 [跳转](#介绍)
```
# service/.env 文件
# OpenAI API Key - https://platform.openai.com/overview
OPENAI_API_KEY=
# change this to an `accessToken` extracted from the ChatGPT site's `https://chat.openai.com/api/auth/session` response
OPENAI_ACCESS_TOKEN=
```
## 安装依赖
> 为了简便 `后端开发人员` 的了解负担,所以并没有采用前端 `workspace` 模式,而是分文件夹存放。如果只需要前端页面做二次开发,删除 `service` 文件夹即可。
### 后端
进入文件夹 `/service` 运行以下命令
```shell
pnpm install
```
### 前端
根目录下运行以下命令
```shell
pnpm bootstrap
```
## 测试环境运行
### 后端服务
进入文件夹 `/service` 运行以下命令
```shell
pnpm start
```
### 前端网页
根目录下运行以下命令
```shell
pnpm dev
```
## 环境变量
`API` 可用:
- `OPENAI_API_KEY``OPENAI_ACCESS_TOKEN` 二选一
- `OPENAI_API_MODEL` 设置模型,可选,默认:`gpt-3.5-turbo`
- `OPENAI_API_BASE_URL` 设置接口地址,可选,默认:`https://api.openai.com`
- `OPENAI_API_DISABLE_DEBUG` 设置接口关闭 debug 日志可选默认empty 不关闭
`ACCESS_TOKEN` 可用:
- `OPENAI_ACCESS_TOKEN``OPENAI_API_KEY` 二选一,同时存在时,`OPENAI_API_KEY` 优先
- `API_REVERSE_PROXY` 设置反向代理,可选,默认:`https://ai.fakeopen.com/api/conversation`[社区](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy)(注意:只有这两个是推荐,其他第三方来源,请自行甄别)
通用:
- `AUTH_SECRET_KEY` 访问权限密钥,可选
- `MAX_REQUEST_PER_HOUR` 每小时最大请求次数,可选,默认无限
- `TIMEOUT_MS` 超时,单位毫秒,可选
- `SOCKS_PROXY_HOST``SOCKS_PROXY_PORT` 一起时生效,可选
- `SOCKS_PROXY_PORT``SOCKS_PROXY_HOST` 一起时生效,可选
- `HTTPS_PROXY` 支持 `http``https`, `socks5`,可选
- `ALL_PROXY` 支持 `http``https`, `socks5`,可选
## 打包
### 使用 Docker
#### Docker 参数示例
![docker](./docs/docker.png)
#### Docker build & Run
```bash
docker build -t chatgpt-web .
# 前台运行
docker run --name chatgpt-web --rm -it -p 127.0.0.1:3002:3002 --env OPENAI_API_KEY=your_api_key chatgpt-web
# 后台运行
docker run --name chatgpt-web -d -p 127.0.0.1:3002:3002 --env OPENAI_API_KEY=your_api_key chatgpt-web
# 运行地址
http://localhost:3002/
```
#### Docker compose
[Hub 地址](https://hub.docker.com/repository/docker/chenzhaoyu94/chatgpt-web/general)
```yml
version: '3'
services:
app:
image: chenzhaoyu94/chatgpt-web # 总是使用 latest ,更新时重新 pull 该 tag 镜像即可
ports:
- 127.0.0.1:3002:3002
environment:
# 二选一
OPENAI_API_KEY: sk-xxx
# 二选一
OPENAI_ACCESS_TOKEN: xxx
# API接口地址可选设置 OPENAI_API_KEY 时可用
OPENAI_API_BASE_URL: xxx
# API模型可选设置 OPENAI_API_KEY 时可用https://platform.openai.com/docs/models
# gpt-4, gpt-4-1106-preview, gpt-4-0314, gpt-4-0613, gpt-4-32k, gpt-4-32k-0314, gpt-4-32k-0613, gpt-3.5-turbo-16k, gpt-3.5-turbo-16k-0613, gpt-3.5-turbo, gpt-3.5-turbo-0301, gpt-3.5-turbo-0613, text-davinci-003, text-davinci-002, code-davinci-002
OPENAI_API_MODEL: xxx
# 反向代理,可选
API_REVERSE_PROXY: xxx
# 访问权限密钥,可选
AUTH_SECRET_KEY: xxx
# 每小时最大请求次数,可选,默认无限
MAX_REQUEST_PER_HOUR: 0
# 超时,单位毫秒,可选
TIMEOUT_MS: 60000
# Socks代理可选和 SOCKS_PROXY_PORT 一起时生效
SOCKS_PROXY_HOST: xxx
# Socks代理端口可选和 SOCKS_PROXY_HOST 一起时生效
SOCKS_PROXY_PORT: xxx
# HTTPS 代理,可选,支持 httphttpssocks5
HTTPS_PROXY: http://xxx:7890
```
- `OPENAI_API_BASE_URL` 可选,设置 `OPENAI_API_KEY` 时可用
- `OPENAI_API_MODEL` 可选,设置 `OPENAI_API_KEY` 时可用
#### 防止爬虫抓取
**nginx**
将下面配置填入nginx配置文件中可以参考 `docker-compose/nginx/nginx.conf` 文件中添加反爬虫的方法
```
# 防止爬虫抓取
if ($http_user_agent ~* "360Spider|JikeSpider|Spider|spider|bot|Bot|2345Explorer|curl|wget|webZIP|qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo! Slurp|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot|ia_archiver|Tomato Bot|NSPlayer|bingbot")
{
return 403;
}
```
### 使用 Railway 部署
[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template/yytmgc)
#### Railway 环境变量
| 环境变量名称 | 必填 | 备注 |
| --------------------- | ---------------------- | -------------------------------------------------------------------------------------------------- |
| `PORT` | 必填 | 默认 `3002`
| `AUTH_SECRET_KEY` | 可选 | 访问权限密钥 |
| `MAX_REQUEST_PER_HOUR` | 可选 | 每小时最大请求次数,可选,默认无限 |
| `TIMEOUT_MS` | 可选 | 超时时间,单位毫秒 |
| `OPENAI_API_KEY` | `OpenAI API` 二选一 | 使用 `OpenAI API` 所需的 `apiKey` [(获取 apiKey)](https://platform.openai.com/overview) |
| `OPENAI_ACCESS_TOKEN` | `Web API` 二选一 | 使用 `Web API` 所需的 `accessToken` [(获取 accessToken)](https://chat.openai.com/api/auth/session) |
| `OPENAI_API_BASE_URL` | 可选,`OpenAI API` 时可用 | `API`接口地址 |
| `OPENAI_API_MODEL` | 可选,`OpenAI API` 时可用 | `API`模型 |
| `API_REVERSE_PROXY` | 可选,`Web API` 时可用 | `Web API` 反向代理地址 [详情](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy) |
| `SOCKS_PROXY_HOST` | 可选,和 `SOCKS_PROXY_PORT` 一起时生效 | Socks代理 |
| `SOCKS_PROXY_PORT` | 可选,和 `SOCKS_PROXY_HOST` 一起时生效 | Socks代理端口 |
| `SOCKS_PROXY_USERNAME` | 可选,和 `SOCKS_PROXY_HOST` 一起时生效 | Socks代理用户名 |
| `SOCKS_PROXY_PASSWORD` | 可选,和 `SOCKS_PROXY_HOST` 一起时生效 | Socks代理密码 |
| `HTTPS_PROXY` | 可选 | HTTPS 代理,支持 httphttps, socks5 |
| `ALL_PROXY` | 可选 | 所有代理 代理,支持 httphttps, socks5 |
> 注意: `Railway` 修改环境变量会重新 `Deploy`
### 使用 Sealos 部署
[![](https://raw.githubusercontent.com/labring-actions/templates/main/Deploy-on-Sealos.svg)](https://cloud.sealos.io/?openapp=system-fastdeploy%3FtemplateName%3Dchatgpt-web)
> 环境变量与 Docker 环境变量一致
### 手动打包
#### 后端服务
> 如果你不需要本项目的 `node` 接口,可以省略如下操作
复制 `service` 文件夹到你有 `node` 服务环境的服务器上。
```shell
# 安装
pnpm install
# 打包
pnpm build
# 运行
pnpm prod
```
PS: 不进行打包,直接在服务器上运行 `pnpm start` 也可
#### 前端网页
1、修改根目录下 `.env` 文件中的 `VITE_GLOB_API_URL` 为你的实际后端接口地址
2、根目录下运行以下命令然后将 `dist` 文件夹内的文件复制到你网站服务的根目录下
[参考信息](https://cn.vitejs.dev/guide/static-deploy.html#building-the-app)
```shell
pnpm build
```
## 常见问题
Q: 为什么 `Git` 提交总是报错?
A: 因为有提交信息验证,请遵循 [Commit 指南](./CONTRIBUTING.md)
Q: 如果只使用前端页面,在哪里改请求接口?
A: 根目录下 `.env` 文件中的 `VITE_GLOB_API_URL` 字段。
Q: 文件保存时全部爆红?
A: `vscode` 请安装项目推荐插件,或手动安装 `Eslint` 插件。
Q: 前端没有打字机效果?
A: 一种可能原因是经过 Nginx 反向代理,开启了 buffer则 Nginx 会尝试从后端缓冲一定大小的数据再发送给浏览器。请尝试在反代参数后添加 `proxy_buffering off;`,然后重载 Nginx。其他 web server 配置同理。
## 参与贡献
贡献之前请先阅读 [贡献指南](./CONTRIBUTING.md)
感谢所有做过贡献的人!
<a href="https://github.com/Chanzhaoyu/chatgpt-web/graphs/contributors">
<img src="https://contrib.rocks/image?repo=Chanzhaoyu/chatgpt-web" />
</a>
## 赞助
如果你觉得这个项目对你有帮助,并且情况允许的话,可以给我一点点支持,总之非常感谢支持~
<div style="display: flex; gap: 20px;">
<div style="text-align: center">
<img style="max-width: 100%" src="./docs/wechat.png" alt="微信" />
<p>WeChat Pay</p>
</div>
<div style="text-align: center">
<img style="max-width: 100%" src="./docs/alipay.png" alt="支付宝" />
<p>Alipay</p>
</div>
</div>
## License
MIT © [ChenZhaoYu](./license)

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "chatgpt-web",
"version": "2.10.9",
"version": "2.11.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "chatgpt-web",
"version": "2.10.9",
"version": "2.11.1",
"dependencies": {
"@traptitech/markdown-it-katex": "^3.6.0",
"@vueuse/core": "^9.13.0",

7031
service/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -46,7 +46,7 @@ onMounted(() => {
</h2>
<div class="p-2 space-y-2 rounded-md bg-neutral-100 dark:bg-neutral-700">
<p>
此项目开源于
{{ $t("setting.openSource") }}
<a
class="text-blue-600 dark:text-blue-500"
href="https://github.com/Chanzhaoyu/chatgpt-web"
@@ -54,10 +54,10 @@ onMounted(() => {
>
GitHub
</a>
免费且基于 MIT 协议没有任何形式的付费行为
{{ $t("setting.freeMIT") }}
</p>
<p>
如果你觉得此项目对你有帮助请在 GitHub 帮我点个 Star 或者给予一点赞助谢谢
{{ $t("setting.stars") }}
</p>
</div>
<p>{{ $t("setting.api") }}{{ config?.apiModel ?? '-' }}</p>

View File

@@ -1,5 +1,5 @@
import { computed } from 'vue'
import { enUS, koKR, zhCN, zhTW } from 'naive-ui'
import { enUS, koKR, ruRU, viVN, zhCN, zhTW } from 'naive-ui'
import { useAppStore } from '@/store'
import { setLocale } from '@/locales'
@@ -7,25 +7,22 @@ export function useLanguage() {
const appStore = useAppStore()
const language = computed(() => {
setLocale(appStore.language)
switch (appStore.language) {
case 'en-US':
setLocale('en-US')
return enUS
case 'ru-RU':
setLocale('ru-RU')
return enUS
case 'ko-KR':
setLocale('ko-KR')
return koKR
case 'vi-VN':
return viVN
case 'ru-RU':
return ruRU
case 'zh-CN':
setLocale('zh-CN')
return zhCN
case 'zh-TW':
setLocale('zh-TW')
return zhTW
default:
setLocale('zh-CN')
return zhCN
return enUS
}
})

View File

@@ -30,11 +30,13 @@ export default {
},
chat: {
newChatButton: 'New Chat',
newChatTitle: 'New Chat',
placeholder: 'Ask me anything...(Shift + Enter = line break, "/" to trigger prompts)',
placeholderMobile: 'Ask me anything...',
copy: 'Copy',
copied: 'Copied',
copyCode: 'Copy Code',
copyFailed: 'Copy Failed',
clearChat: 'Clear Chat',
clearChatConfirm: 'Are you sure to clear this chat?',
exportImage: 'Export Image',
@@ -50,6 +52,7 @@ export default {
clearHistoryConfirm: 'Are you sure to clear chat history?',
preview: 'Preview',
showRawText: 'Show as raw text',
thinking: 'Thinking...',
},
setting: {
setting: 'Setting',
@@ -73,6 +76,9 @@ export default {
httpsProxy: 'HTTPS Proxy',
balance: 'API Balance',
monthlyUsage: 'Monthly Usage',
openSource: 'This project is open sourced at',
freeMIT: 'free and based on the MIT license, without any form of paid behavior!',
stars: 'If you find this project helpful, please give me a Star on GitHub or give a little sponsorship, thank you!',
},
store: {
siderButton: 'Prompt Store',

View File

@@ -2,9 +2,10 @@ import type { App } from 'vue'
import { createI18n } from 'vue-i18n'
import enUS from './en-US'
import koKR from './ko-KR'
import ruRU from './ru-RU'
import viVN from './vi-VN'
import zhCN from './zh-CN'
import zhTW from './zh-TW'
import ruRU from './ru-RU'
import { useAppStoreWithOut } from '@/store/modules/app'
import type { Language } from '@/store/modules/app/helper'
@@ -19,9 +20,10 @@ const i18n = createI18n({
messages: {
'en-US': enUS,
'ko-KR': koKR,
'ru-RU': ruRU,
'vi-VN': viVN,
'zh-CN': zhCN,
'zh-TW': zhTW,
'ru-RU': ruRU,
},
})

View File

@@ -30,11 +30,13 @@ export default {
},
chat: {
newChatButton: '새로운 채팅',
newChatTitle: '새로운 채팅',
placeholder: '무엇이든 물어보세요...(Shift + Enter = 줄바꿈, "/"를 눌러서 힌트를 보세요)',
placeholderMobile: '무엇이든 물어보세요...',
copy: '복사',
copied: '복사됨',
copyCode: '코드 복사',
copyFailed: '복사 실패',
clearChat: '채팅 비우기',
clearChatConfirm: '이 채팅을 비우시겠습니까?',
exportImage: '이미지 내보내기',
@@ -50,6 +52,7 @@ export default {
clearHistoryConfirm: '채팅 기록을 삭제하시겠습니까?',
preview: '미리보기',
showRawText: '원본 텍스트로 보기',
thinking: '생각 중...',
},
setting: {
setting: '설정',
@@ -73,6 +76,9 @@ export default {
httpsProxy: 'HTTPS 프록시',
balance: 'API 잔액',
monthlyUsage: '월 사용량',
openSource: '이 프로젝트는 다음에서 오픈 소스로 제공됩니다:',
freeMIT: '무료이며 MIT 라이선스에 기반하며, 어떠한 형태의 유료 행동도 없습니다!',
stars: '이 프로젝트가 도움이 되었다면, GitHub에서 별을 주거나 조금의 후원을 해주시면 감사하겠습니다!',
},
store: {
siderButton: '프롬프트 저장소',

View File

@@ -30,11 +30,13 @@ export default {
},
chat: {
newChatButton: 'Новый чат',
newChatTitle: 'Новый чат',
placeholder: 'Спросите меня о чем-нибудь ... (Shift + Enter = перенос строки, "/" для вызова подсказок)',
placeholderMobile: 'Спросите меня о чем-нибудь ...',
copy: 'Копировать',
copied: 'Скопировано',
copyCode: 'Копировать код',
copyFailed: 'Не удалось скопировать',
clearChat: 'Очистить чат',
clearChatConfirm: 'Вы уверены, что хотите очистить этот чат?',
exportImage: 'Экспорт в изображение',
@@ -50,6 +52,7 @@ export default {
clearHistoryConfirm: 'Вы уверены, что хотите очистить историю чата?',
preview: 'Предварительный просмотр',
showRawText: 'Показать как обычный текст',
thinking: 'Думаю...',
},
setting: {
setting: 'Настройки',
@@ -73,6 +76,9 @@ export default {
httpsProxy: 'HTTPS-прокси',
balance: 'Баланс API',
monthlyUsage: 'Ежемесячное использование',
openSource: 'Этот проект опубликован в открытом доступе на',
freeMIT: 'бесплатно и основан на лицензии MIT, без каких-либо форм оплаты!',
stars: 'Если вы считаете этот проект полезным, пожалуйста, поставьте мне звезду на GitHub или сделайте небольшое пожертвование, спасибо!',
},
store: {
siderButton: 'Хранилище подсказок',

View File

@@ -29,11 +29,13 @@ export default {
},
chat: {
newChatButton: 'Tạo hội thoại',
newChatTitle: 'Tạo hội thoại',
placeholder: 'Hỏi tôi bất cứ điều gì...(Shift + Enter = ngắt dòng, "/" to trigger prompts)',
placeholderMobile: 'Hỏi tôi bất cứ điều gì...',
copy: 'Sao chép',
copied: 'Đã sao chép',
copyCode: 'Sao chép Code',
copyFailed: 'Sao chép thất bại',
clearChat: 'Clear Chat',
clearChatConfirm: 'Bạn có chắc chắn xóa cuộc trò chuyện này?',
exportImage: 'Xuất hình ảnh',
@@ -49,6 +51,7 @@ export default {
clearHistoryConfirm: 'Bạn có chắc chắn để xóa lịch sử trò chuyện?',
preview: 'Xem trước',
showRawText: 'Hiển thị dưới dạng văn bản thô',
thinking: 'Đang suy nghĩ...',
},
setting: {
setting: 'Cài đặt',
@@ -72,6 +75,9 @@ export default {
httpsProxy: 'HTTPS Proxy',
balance: 'API Balance',
monthlyUsage: 'Sử dụng hàng tháng',
openSource: 'Dự án này được mở nguồn tại',
freeMIT: 'miễn phí và dựa trên giấy phép MIT, không có bất kỳ hình thức hành vi trả phí nào!',
stars: 'Nếu bạn thấy dự án này hữu ích, vui lòng cho tôi một Star trên GitHub hoặc tài trợ một chút, cảm ơn bạn!',
},
store: {
siderButton: 'Prompt Store',

View File

@@ -30,11 +30,13 @@ export default {
},
chat: {
newChatButton: '新建聊天',
newChatTitle: '新建聊天',
placeholder: '来说点什么吧...Shift + Enter = 换行,"/" 触发提示词)',
placeholderMobile: '来说点什么...',
copy: '复制',
copied: '复制成功',
copyCode: '复制代码',
copyFailed: '复制失败',
clearChat: '清空会话',
clearChatConfirm: '是否清空会话?',
exportImage: '保存会话到图片',
@@ -50,6 +52,7 @@ export default {
clearHistoryConfirm: '确定清空记录?',
preview: '预览',
showRawText: '显示原文',
thinking: '思考中...',
},
setting: {
setting: '设置',
@@ -73,6 +76,9 @@ export default {
httpsProxy: 'HTTPS Proxy',
balance: 'API余额',
monthlyUsage: '本月使用量',
openSource: '此项目开源于',
freeMIT: '免费且基于 MIT 协议,没有任何形式的付费行为',
stars: '如果你觉得此项目对你有帮助,请在 GitHub 上给我一个星星或者给予一点赞助,谢谢!',
},
store: {
siderButton: '提示词商店',

View File

@@ -30,11 +30,13 @@ export default {
},
chat: {
newChatButton: '新增對話',
newChatTitle: '新增對話',
placeholder: '來說點什麼...Shift + Enter = 換行,"/" 觸發提示詞)',
placeholderMobile: '來說點什麼...',
copy: '複製',
copied: '複製成功',
copyCode: '複製代碼',
copyFailed: '複製失敗',
clearChat: '清除對話',
clearChatConfirm: '是否清空對話?',
exportImage: '儲存對話為圖片',
@@ -50,6 +52,7 @@ export default {
clearHistoryConfirm: '確定清除紀錄?',
preview: '預覽',
showRawText: '顯示原文',
thinking: '思考中...',
},
setting: {
setting: '設定',
@@ -73,6 +76,9 @@ export default {
httpsProxy: 'HTTPS Proxy',
balance: 'API Credit 餘額',
monthlyUsage: '本月使用量',
openSource: '此專案在此開源:',
freeMIT: '免費且基於 MIT 授權,沒有任何形式的付費行為!',
stars: '如果你覺得此專案對你有幫助,請在 GitHub 上給我一顆星,或者贊助我,謝謝!',
},
store: {
siderButton: '提示詞商店',

View File

@@ -4,7 +4,21 @@ const LOCAL_NAME = 'appSetting'
export type Theme = 'light' | 'dark' | 'auto'
export type Language = 'zh-CN' | 'zh-TW' | 'en-US' | 'ko-KR' | 'ru-RU'
export type Language = 'en-US' | 'ko-KR' | 'ru-RU' | 'vi-VN' | 'zh-CN' | 'zh-TW'
const languageMap: { [key: string]: Language } = {
'en': 'en-US',
'en-US': 'en-US',
'ko': 'ko-KR',
'ko-KR': 'ko-KR',
'ru': 'ru-RU',
'ru-RU': 'ru-RU',
'vi': 'vi-VN',
'vi-VN': 'vi-VN',
'zh': 'zh-CN',
'zh-CN': 'zh-CN',
'zh-TW': 'zh-TW',
}
export interface AppState {
siderCollapsed: boolean
@@ -13,7 +27,8 @@ export interface AppState {
}
export function defaultSetting(): AppState {
return { siderCollapsed: false, theme: 'light', language: 'zh-CN' }
const language = languageMap[navigator.language]
return { siderCollapsed: false, theme: 'light', language }
}
export function getLocalSetting(): AppState {

View File

@@ -1,4 +1,5 @@
import { ss } from '@/utils/storage'
import { t } from '@/locales'
const LOCAL_NAME = 'chatStorage'
@@ -7,7 +8,7 @@ export function defaultState(): Chat.ChatState {
return {
active: uuid,
usingContext: true,
history: [{ uuid, title: 'New Chat', isEdit: false }],
history: [{ uuid, title: t('chat.newChatTitle'), isEdit: false }],
chat: [{ uuid, data: [] }],
}
}

View File

@@ -1,6 +1,7 @@
import { defineStore } from 'pinia'
import { defaultState, getLocalState, setLocalState } from './helper'
import { router } from '@/router'
import { t } from '@/locales'
export const useChatStore = defineStore('chat-store', {
state: (): Chat.ChatState => getLocalState(),
@@ -103,7 +104,7 @@ export const useChatStore = defineStore('chat-store', {
}
else {
this.chat[0].data.push(chat)
if (this.history[0].title === 'New Chat')
if (this.history[0].title === t('chat.newChatTitle'))
this.history[0].title = chat.text
this.recordState()
}
@@ -112,7 +113,7 @@ export const useChatStore = defineStore('chat-store', {
const index = this.chat.findIndex(item => item.uuid === uuid)
if (index !== -1) {
this.chat[index].data.push(chat)
if (this.history[index].title === 'New Chat')
if (this.history[index].title === t('chat.newChatTitle'))
this.history[index].title = chat.text
this.recordState()
}

View File

@@ -70,9 +70,9 @@ function addCopyEvents() {
const code = btn.parentElement?.nextElementSibling?.textContent
if (code) {
copyToClip(code).then(() => {
btn.textContent = '复制成功'
btn.textContent = t('chat.copied')
setTimeout(() => {
btn.textContent = '复制代码'
btn.textContent = t('chat.copyCode')
}, 1000)
})
}

View File

@@ -84,10 +84,10 @@ function handleRegenerate() {
async function handleCopy() {
try {
await copyToClip(props.text || '')
message.success('复制成功')
message.success(t('chat.copied'))
}
catch {
message.error('复制失败')
message.error(t('chat.copyFailed'))
}
}
</script>

View File

@@ -93,7 +93,7 @@ async function onConversation() {
+uuid,
{
dateTime: new Date().toLocaleString(),
text: '思考中',
text: t('chat.thinking'),
loading: true,
inversion: false,
error: false,
@@ -481,7 +481,7 @@ onUnmounted(() => {
<template v-if="!dataSources.length">
<div class="flex items-center justify-center mt-4 text-center text-neutral-300">
<SvgIcon icon="ri:bubble-chart-fill" class="mr-2 text-3xl" />
<span>Aha~</span>
<span>{{ t('chat.newChatTitle') }}</span>
</div>
</template>
<template v-else>

View File

@@ -20,7 +20,7 @@ const show = ref(false)
const collapsed = computed(() => appStore.siderCollapsed)
function handleAdd() {
chatStore.addHistory({ title: 'New Chat', uuid: Date.now(), isEdit: false })
chatStore.addHistory({ title: t('chat.newChatTitle'), uuid: Date.now(), isEdit: false })
if (isMobile.value)
appStore.setSiderCollapsed(true)
}