dvc890 commited on
Commit
41af422
1 Parent(s): f60c050

[feat]add project files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
CHANGELOG.md ADDED
@@ -0,0 +1,578 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## v2.10.9
2
+
3
+ `2023-04-03`
4
+
5
+ > 更新默认 `accessToken` 反代地址为 [[pengzhile](https://github.com/pengzhile)] 的 `https://ai.fakeopen.com/api/conversation`
6
+
7
+ ## Enhancement
8
+ - 添加 `socks5` 代理认证 [[yimiaoxiehou](https://github.com/Chanzhaoyu/chatgpt-web/pull/999)]
9
+ - 添加 `socks` 代理用户名密码的配置 [[hank-cp](https://github.com/Chanzhaoyu/chatgpt-web/pull/890)]
10
+ - 添加可选日志打印 [[zcong1993](https://github.com/Chanzhaoyu/chatgpt-web/pull/1041)]
11
+ - 更新侧边栏按钮本地化[[simonwu53](https://github.com/Chanzhaoyu/chatgpt-web/pull/911)]
12
+ - 优化代码块滚动条高度 [[Fog3211](https://github.com/Chanzhaoyu/chatgpt-web/pull/1153)]
13
+ ## BugFix
14
+ - 修复 `PWA` 问题 [[bingo235](https://github.com/Chanzhaoyu/chatgpt-web/pull/807)]
15
+ - 修复 `ESM` 错误 [[kidonng](https://github.com/Chanzhaoyu/chatgpt-web/pull/826)]
16
+ - 修复反向代理开启时限流失效的问题 [[gitgitgogogo](https://github.com/Chanzhaoyu/chatgpt-web/pull/863)]
17
+ - 修复 `docker` 构建时 `.env` 可能被忽略的问题 [[zaiMoe](https://github.com/Chanzhaoyu/chatgpt-web/pull/877)]
18
+ - 修复导出异常错误 [[KingTwinkle](https://github.com/Chanzhaoyu/chatgpt-web/pull/938)]
19
+ - 修复空值异常 [[vchenpeng](https://github.com/Chanzhaoyu/chatgpt-web/pull/1103)]
20
+ - 移动端上的体验问题
21
+
22
+ ## Other
23
+ - `Docker` 容器名字名义 [[LOVECHEN](https://github.com/Chanzhaoyu/chatgpt-web/pull/1035)]
24
+ - `kubernetes` 部署配置 [[CaoYunzhou](https://github.com/Chanzhaoyu/chatgpt-web/pull/1001)]
25
+ - 感谢 [[assassinliujie](https://github.com/Chanzhaoyu/chatgpt-web/pull/962)] 和 [[puppywang](https://github.com/Chanzhaoyu/chatgpt-web/pull/1017)] 的某些贡献
26
+ - 更新 `kubernetes/deploy.yaml` [[idawnwon](https://github.com/Chanzhaoyu/chatgpt-web/pull/1085)]
27
+ - 文档更新 [[#yi-ge](https://github.com/Chanzhaoyu/chatgpt-web/pull/883)]
28
+ - 文档更新 [[weifeng12x](https://github.com/Chanzhaoyu/chatgpt-web/pull/880)]
29
+ - 依赖更新
30
+
31
+ ## v2.10.8
32
+
33
+ `2023-03-23`
34
+
35
+ 如遇问题,请删除 `node_modules` 重新安装依赖。
36
+
37
+ ## Feature
38
+ - 显示回复消息原文的选项 [[yilozt](https://github.com/Chanzhaoyu/chatgpt-web/pull/672)]
39
+ - 添加单 `IP` 每小时请求限制。环境变量: `MAX_REQUEST_PER_HOUR` [[zhuxindong ](https://github.com/Chanzhaoyu/chatgpt-web/pull/718)]
40
+ - 前端添加角色设定,仅 `API` 方式可见 [[quzard](https://github.com/Chanzhaoyu/chatgpt-web/pull/768)]
41
+ - `OPENAI_API_MODEL` 变量现在对 `ChatGPTUnofficialProxyAPI` 也生效,注意:`Token` 和 `API` 的模型命名不一致,不能直接填入 `gpt-3.5` 或者 `gpt-4` [[hncboy](https://github.com/Chanzhaoyu/chatgpt-web/pull/632)]
42
+ - 添加繁体中文 `Prompts` [[PeterDaveHello](https://github.com/Chanzhaoyu/chatgpt-web/pull/796)]
43
+
44
+ ## Enhancement
45
+ - 重置回答时滚动定位至该回答 [[shunyue1320](https://github.com/Chanzhaoyu/chatgpt-web/pull/781)]
46
+ - 当 `API` 是 `gpt-4` 时增加可用的 `Max Tokens` [[simonwu53](https://github.com/Chanzhaoyu/chatgpt-web/pull/729)]
47
+ - 判断和忽略回复字符 [[liut](https://github.com/Chanzhaoyu/chatgpt-web/pull/474)]
48
+ - 切换会话时,自动聚焦输入框 [[JS-an](https://github.com/Chanzhaoyu/chatgpt-web/pull/735)]
49
+ - 渲染的链接新窗口打开
50
+ - 查询余额可选 `API_BASE_URL` 代理地址
51
+ - `config` 接口添加验证防止被无限制调用
52
+ - `PWA` 默认不开启,现在需手动修改 `.env` 文件 `VITE_GLOB_APP_PWA` 变量
53
+ - 当网络连接时,刷新页面,`500` 错误页自动跳转到主页
54
+
55
+ ## BugFix
56
+ - `scrollToBottom` 调回 `scrollToBottomIfAtBottom` [[shunyue1320](https://github.com/Chanzhaoyu/chatgpt-web/pull/771)]
57
+ - 重置异常的 `loading` 会话
58
+
59
+ ## Common
60
+ - 创建 `start.cmd` 在 `windows` 下也可以运行 [vulgatecnn](https://github.com/Chanzhaoyu/chatgpt-web/pull/656)]
61
+ - 添加 `visual-studio-code` 中调试配置 [[ChandlerVer5](https://github.com/Chanzhaoyu/chatgpt-web/pull/296)]
62
+ - 修复文档中 `docker` 端口为本地 [[kilvn](https://github.com/Chanzhaoyu/chatgpt-web/pull/802)]
63
+ ## Other
64
+ - 依赖更新
65
+
66
+
67
+ ## v2.10.7
68
+
69
+ `2023-03-17`
70
+
71
+ ## BugFix
72
+ - 回退 `chatgpt` 版本,原因:导致 `OPENAI_API_BASE_URL` 代理失效
73
+ - 修复缺省状态的 `usingContext` 默认值
74
+
75
+ ## v2.10.6
76
+
77
+ `2023-03-17`
78
+
79
+ ## Feature
80
+ - 显示 `API` 余额 [[pzcn](https://github.com/Chanzhaoyu/chatgpt-web/pull/582)]
81
+
82
+ ## Enhancement
83
+ - 美化滚动条样式和 `UI` 保持一致 [[haydenull](https://github.com/Chanzhaoyu/chatgpt-web/pull/617)]
84
+ - 优化移动端 `Prompt` 样式 [[CornerSkyless](https://github.com/Chanzhaoyu/chatgpt-web/pull/608)]
85
+ - 上下文开关改为全局开关,现在记录在本地缓存中
86
+ - 配置信息按接口类型显示
87
+
88
+ ## Perf
89
+ - 优化函数方法 [[kirklin](https://github.com/Chanzhaoyu/chatgpt-web/pull/583)]
90
+ - 字符错误 [[pdsuwwz](https://github.com/Chanzhaoyu/chatgpt-web/pull/585)]
91
+ - 文档描述错误 [[lizhongyuan3](https://github.com/Chanzhaoyu/chatgpt-web/pull/636)]
92
+
93
+ ## BugFix
94
+ - 修复 `Prompt` 导入、导出兼容性错误
95
+ - 修复 `highlight.js` 控制台兼容性警告
96
+
97
+ ## Other
98
+ - 依赖更新
99
+
100
+ ## v2.10.5
101
+
102
+ `2023-03-13`
103
+
104
+ 更新依赖,`access_token` 默认代理为 [pengzhile](https://github.com/pengzhile) 的 `https://bypass.duti.tech/api/conversation`
105
+
106
+ ## Feature
107
+ - `Prompt` 商店在线导入可以导入两种 `recommend.json`里提到的模板 [simonwu53](https://github.com/Chanzhaoyu/chatgpt-web/pull/521)
108
+ - 支持 `HTTPS_PROXY` [whatwewant](https://github.com/Chanzhaoyu/chatgpt-web/pull/308)
109
+ - `Prompt` 添加查询筛选
110
+
111
+ ## Enhancement
112
+ - 调整输入框最大行数 [yi-ge](https://github.com/Chanzhaoyu/chatgpt-web/pull/502)
113
+ - 优化 `docker` 打包 [whatwewant](https://github.com/Chanzhaoyu/chatgpt-web/pull/520)
114
+ - `Prompt` 添加翻译和优化布局
115
+ - 「繁体中文」补全和审阅 [PeterDaveHello](https://github.com/Chanzhaoyu/chatgpt-web/pull/542)
116
+ - 语言选择调整为下路框形式
117
+ - 权限输入框类型调整为密码形式
118
+
119
+ ## BugFix
120
+ - `JSON` 导入检查 [Nothing1024](https://github.com/Chanzhaoyu/chatgpt-web/pull/523)
121
+ - 修复 `AUTH_SECRET_KEY` 模式下跨域异常并添加对 `node.js 19` 版本的支持 [yi-ge](https://github.com/Chanzhaoyu/chatgpt-web/pull/499)
122
+ - 确定清空上下文时不应该重置会话标题
123
+
124
+ ## Other
125
+ - 调整文档
126
+ - 更新依赖
127
+
128
+ ## v2.10.4
129
+
130
+ `2023-03-11`
131
+
132
+ ## Feature
133
+ - 感谢 [Nothing1024](https://github.com/Chanzhaoyu/chatgpt-web/pull/268) 添加 `Prompt` 模板和 `Prompt` 商店支持
134
+
135
+ ## Enhancement
136
+ - 设置添加关闭按钮[#495]
137
+
138
+ ## Demo
139
+
140
+ ![Prompt](https://camo.githubusercontent.com/6a51af751eb29238cb7ef4f8fbd89f63db837562f97f33273095424e62dc9194/68747470733a2f2f73312e6c6f63696d672e636f6d2f323032332f30332f30342f333036326665633163613562632e676966)
141
+
142
+ ## v2.10.3
143
+
144
+ `2023-03-10`
145
+
146
+ > 声明:除 `ChatGPTUnofficialProxyAPI` 使用的非官方代理外,本项目代码包括上游引用包均开源在 `GitHub`,如果你觉得本项目有监控后门或有问题导致你的账号、API被封,那我很抱歉。我可能`BUG`写的多,但我不缺德。此次主要为前端界面调整,周末愉快。
147
+
148
+ ## Feature
149
+ - 支持长回复 [[yi-ge](https://github.com/Chanzhaoyu/chatgpt-web/pull/450)][[详情](https://github.com/Chanzhaoyu/chatgpt-web/pull/450)]
150
+ - 支持 `PWA` [[chenxch](https://github.com/Chanzhaoyu/chatgpt-web/pull/452)]
151
+
152
+ ## Enhancement
153
+ - 调整移动端按钮和优化布局
154
+ - 调整 `iOS` 上安全距离
155
+ - 简化 `docker-compose` 部署 [[cloudGrin](https://github.com/Chanzhaoyu/chatgpt-web/pull/466)]
156
+
157
+ ## BugFix
158
+ - 修复清空会话侧边栏标题不会重置的问题 [[RyanXinOne](https://github.com/Chanzhaoyu/chatgpt-web/pull/453)]
159
+ - 修复设置文字过长时导致的设置按钮消失的问题
160
+
161
+ ## Other
162
+ - 更新依赖
163
+
164
+ ## v2.10.2
165
+
166
+ `2023-03-09`
167
+
168
+ 衔接 `2.10.1` 版本[详情](https://github.com/Chanzhaoyu/chatgpt-web/releases/tag/v2.10.1)
169
+
170
+ ## Enhancement
171
+ - 移动端下输入框获得焦点时左侧按钮隐藏
172
+
173
+ ## BugFix
174
+ - 修复 `2.10.1` 中添加 `OPENAI_API_MODEL` 变量的判断错误,会导致默认模型指定失效,抱歉
175
+ - 回退 `2.10.1` 中前端变量影响 `Docker` 打包
176
+
177
+ ## v2.10.1
178
+
179
+ `2023-03-09`
180
+
181
+ 注意:删除了 `.env` 文件改用 `.env.example` 代替,如果是手动部署的同学现在需要手动创建 `.env` 文件并从 `.env.example` 中复制需要的变量,并且 `.env` 文件现在会在 `Git` 提交中被忽略,原因如下:
182
+
183
+ - 在项目中添加 `.env` 从一开始就是个错误的示范
184
+ - 如果是 `Fork` 项目进行修改测试总是会被 `Git` 修改提示给打扰
185
+ - 感谢 [yi-ge](https://github.com/Chanzhaoyu/chatgpt-web/pull/395) 的提醒和修改
186
+
187
+
188
+ 这两天开始,官方已经开始对第三方代理进行了拉闸, `accessToken` 即将或已经开始可能会不可使用。异常 `API` 使用也开始封号,封号缘由不明,如果出现使用 `API` 提示错误,请查看后端控制台信息,或留意邮箱。
189
+
190
+ ## Feature
191
+ - 感谢 [CornerSkyless](https://github.com/Chanzhaoyu/chatgpt-web/pull/393) 添加是否发送上下文开关功能
192
+
193
+ ## Enhancement
194
+ - 感谢 [nagaame](https://github.com/Chanzhaoyu/chatgpt-web/pull/415) 优化`docker`打包镜像文件过大的问题
195
+ - 感谢 [xieccc](https://github.com/Chanzhaoyu/chatgpt-web/pull/404) 新增 `API` 模型配置变量 `OPENAI_API_MODEL`
196
+ - 感谢 [acongee](https://github.com/Chanzhaoyu/chatgpt-web/pull/394) 优化输出时滚动条问题
197
+
198
+ ## BugFix
199
+ - 感谢 [CornerSkyless](https://github.com/Chanzhaoyu/chatgpt-web/pull/392) 修复导出图片会丢失头像的问题
200
+ - 修复深色模式导出图片的样式问题
201
+
202
+
203
+ ## v2.10.0
204
+
205
+ `2023-03-07`
206
+
207
+ - 老规矩,手动部署的同学需要删除 `node_modules` 安装包重新安装降低出错概率,其他部署不受影响,但是可能会有缓存问题。
208
+ - 虽然说了更新放缓,但是 `issues` 不看, `PR` 不改我睡不着,我的邮箱从每天早上`8`点到凌晨`12`永远在滴滴滴,所以求求各位,超时的`issues`自己关闭下哈,我真的需要缓冲一下。
209
+ - 演示图片请看��后
210
+
211
+ ## Feature
212
+ - 添加权限功能,用法:`service/.env` 中的 `AUTH_SECRET_KEY` 变量添加密码
213
+ - 感谢 [PeterDaveHello](https://github.com/Chanzhaoyu/chatgpt-web/pull/348) 添加「繁体中文」翻译
214
+ - 感谢 [GermMC](https://github.com/Chanzhaoyu/chatgpt-web/pull/369) 添加聊天记录导入、导出、清空的功能
215
+ - 感谢 [CornerSkyless](https://github.com/Chanzhaoyu/chatgpt-web/pull/374) 添加会话保存为本地图片的功能
216
+
217
+
218
+ ## Enhancement
219
+ - 感谢 [CornerSkyless](https://github.com/Chanzhaoyu/chatgpt-web/pull/363) 添加 `ctrl+enter` 发送消息
220
+ - 现在新消息只有在结束了之后才滚动到底部,而不是之前的强制性
221
+ - 优化部分代码
222
+
223
+ ## BugFix
224
+ - 转义状态码前端显示,防止直接暴露 `key`(我可能需要更多的状态码补充)
225
+
226
+ ## Other
227
+ - 更新依赖到最新
228
+
229
+ ## 演示
230
+ > 不是界面最新效果,有美化改动
231
+
232
+ 权限
233
+
234
+ ![权限](https://user-images.githubusercontent.com/24789441/223438518-80d58d42-e344-4e39-b87c-251ff73925ed.png)
235
+
236
+ 聊天记录导出
237
+
238
+ ![聊天记录导出](https://user-images.githubusercontent.com/57023771/223372153-6d8e9ec1-d82c-42af-b4bd-232e50504a25.gif)
239
+
240
+ 保存图片到本地
241
+
242
+ ![保存图片到本地](https://user-images.githubusercontent.com/13901424/223423555-b69b95ef-8bcf-4951-a7c9-98aff2677e18.gif)
243
+
244
+ ## v2.9.3
245
+
246
+ `2023-03-06`
247
+
248
+ ## Enhancement
249
+ - 感谢 [ChandlerVer5](https://github.com/Chanzhaoyu/chatgpt-web/pull/305) 使用 `markdown-it` 替换 `marked`,解决代码块闪烁的问题
250
+ - 感谢 [shansing](https://github.com/Chanzhaoyu/chatgpt-web/pull/277) 改善文档
251
+ - 感谢 [nalf3in](https://github.com/Chanzhaoyu/chatgpt-web/pull/293) 添加英文翻译
252
+
253
+ ## BugFix
254
+ - 感谢[sepcnt ](https://github.com/Chanzhaoyu/chatgpt-web/pull/279) 修复切换记录时编辑状态未关闭的问题
255
+ - 修复复制代码的兼容性报错问题
256
+ - 修复部分优化小问题
257
+
258
+ ## v2.9.2
259
+
260
+ `2023-03-04`
261
+
262
+ 手动部署的同学,务必删除根目录和`service`中的`node_modules`重新安装依赖,降低出现问题的概率,自动部署的不需要做改动。
263
+
264
+ ### Feature
265
+ - 感谢 [hyln9](https://github.com/Chanzhaoyu/chatgpt-web/pull/247) 添加对渲染 `LaTex` 数学公式的支持
266
+ - 感谢 [ottocsb](https://github.com/Chanzhaoyu/chatgpt-web/pull/227) 添加支持 `webAPP` (苹果添加到主页书签访问)支持
267
+ - 添加 `OPENAI_API_BASE_URL` 可选环境变量[#249]
268
+ ## Enhancement
269
+ - 优化在高分屏上主题内容的最大宽度[#257]
270
+ - 现在文字按单词截断[#215][#225]
271
+ ### BugFix
272
+ - 修复动态生成时代码块不能被复制的问题[#251][#260]
273
+ - 修复 `iOS` 移动端输入框不会被键盘顶起的问题[#256]
274
+ - 修复控制台渲染警告
275
+ ## Other
276
+ - 更新依赖至最新
277
+ - 修改 `README` 内容
278
+
279
+ ## v2.9.1
280
+
281
+ `2023-03-02`
282
+
283
+ ### Feature
284
+ - 代码块添加当前代码语言显示和复制功能[#197][#196]
285
+ - 完善多语言,现在可以切换中英文显示
286
+
287
+ ## Enhancement
288
+ - 由[Zo3i](https://github.com/Chanzhaoyu/chatgpt-web/pull/187) 完善 `docker-compose` 部署文档
289
+
290
+ ### BugFix
291
+ - 由 [ottocsb](https://github.com/Chanzhaoyu/chatgpt-web/pull/200) 修复头像修改不同步的问题
292
+ ## Other
293
+ - 更新依赖至最新
294
+ - 修改 `README` 内容
295
+ ## v2.9.0
296
+
297
+ `2023-03-02`
298
+
299
+ ### Feature
300
+ - 现在能复制带格式的消息文本
301
+ - 新设计的设定页面,可以自定义姓名、描述、头像(链接方式)
302
+ - 新增`403`和`404`页面以便扩展
303
+
304
+ ## Enhancement
305
+ - 更新 `chatgpt` 使 `ChatGPTAPI` 支持 `gpt-3.5-turbo-0301`(默认)
306
+ - 取消了前端超时限制设定
307
+
308
+ ## v2.8.3
309
+
310
+ `2023-03-01`
311
+
312
+ ### Feature
313
+ - 消息已输出内容不会因为中断而消失[#167]
314
+ - 添加复制消息按钮[#133]
315
+
316
+ ### Other
317
+ - `README` 添加声明内容
318
+
319
+ ## v2.8.2
320
+
321
+ `2023-02-28`
322
+ ### Enhancement
323
+ - 代码主题调整为 `One Dark - light|dark` 适配深色模式
324
+ ### BugFix
325
+ - 修复普通文本代码渲染和深色模式下的问题[#139][#154]
326
+
327
+ ## v2.8.1
328
+
329
+ `2023-02-27`
330
+
331
+ ### BugFix
332
+ - 修复 `API` 版本不是 `Markdown` 时,普通 `HTML` 代码会被渲染的问题 [#146]
333
+
334
+ ## v2.8.0
335
+
336
+ `2023-02-27`
337
+
338
+ - 感谢 [puppywang](https://github.com/Chanzhaoyu/chatgpt-web/commit/628187f5c3348bda0d0518f90699a86525d19018) 修复了 `2.7.0` 版本中关于流输出数据的问题(使用 `nginx` 需要自行配置 `octet-stream` 相关内容)
339
+
340
+ - 关于为什么使用 `octet-stream` 而不是 `sse`,是因为更好的兼容之前的模式。
341
+
342
+ - 建议更新到此版本获得比较完整的体验
343
+
344
+ ### Enhancement
345
+ - 优化了部份代码和类型提示
346
+ - 输入框添加换行提示
347
+ - 移动端输入框现在回车为换行,而不是直接提交
348
+ - 移动端双击标题返回顶部,箭头返回底部
349
+
350
+ ### BugFix
351
+ - 流输出数据下的问题[#122]
352
+ - 修复了 `API Key` 下部份代码不换行的问题
353
+ - 修复移动端深色模式部份样式问题[#123][#126]
354
+ - 修复主题模式图标不一致的问题[#126]
355
+
356
+ ## v2.7.3
357
+
358
+ `2023-02-25`
359
+
360
+ ### Feature
361
+ - 适配系统深色模式 [#118](https://github.com/Chanzhaoyu/chatgpt-web/issues/103)
362
+ ### BugFix
363
+ - 修复用户消息能被渲染为 `HTML` 问题 [#117](https://github.com/Chanzhaoyu/chatgpt-web/issues/117)
364
+
365
+ ## v2.7.2
366
+
367
+ `2023-02-24`
368
+ ### Enhancement
369
+ - 消息使用 [github-markdown-css](https://www.npmjs.com/package/github-markdown-css) 进行美化,现在支持全语法
370
+ - 移除测试无用函数
371
+
372
+ ## v2.7.1
373
+
374
+ `2023-02-23`
375
+
376
+ 因为消息流在 `accessToken` 中存在解析失败和消息不完整等一系列的问题,调整回正常消息形式
377
+
378
+ ### Feature
379
+ - 现在可以中断请求过长没有答复的消息
380
+ - 现在可以删除单条消息
381
+ - 设置中显示当前版本信息
382
+
383
+ ### BugFix
384
+ - 回退 `2.7.0` 的消息不稳定的问题
385
+
386
+ ## v2.7.0
387
+
388
+ `2023-02-23`
389
+
390
+ ### Feature
391
+ - 使用消息流返回信息,反应更迅速
392
+
393
+ ### Enhancement
394
+ - 样式的一点小改动
395
+
396
+ ## v2.6.2
397
+
398
+ `2023-02-22`
399
+ ### BugFix
400
+ - 还原修改代理导致的异常问题
401
+
402
+ ## v2.6.1
403
+
404
+ `2023-02-22`
405
+
406
+ ### Feature
407
+ - 新增 `Railway` 部署模版
408
+
409
+ ### BugFix
410
+ - 手动打包 `Proxy` 问题
411
+
412
+ ## v2.6.0
413
+
414
+ `2023-02-21`
415
+ ### Feature
416
+ - 新增对 `网页 accessToken` 调用 `ChatGPT`,更智能不过不太稳定 [#51](https://github.com/Chanzhaoyu/chatgpt-web/issues/51)
417
+ - 前端页面设置按钮显示查看当前后端服务配置
418
+
419
+ ### Enhancement
420
+ - 新增 `TIMEOUT_MS` 环境变量设定后端超时时常(单位:毫秒)[#62](https://github.com/Chanzhaoyu/chatgpt-web/issues/62)
421
+
422
+ ## v2.5.2
423
+
424
+ `2023-02-21`
425
+ ### Feature
426
+ - 增加对 `markdown` 格式的支持 [Demo](https://github.com/Chanzhaoyu/chatgpt-web/pull/77)
427
+ ### BugFix
428
+ - 重载会话时滚动条保持
429
+
430
+ ## v2.5.1
431
+
432
+ `2023-02-21`
433
+
434
+ ### Enhancement
435
+ - 调整路由模式为 `hash`
436
+ - 调整新增会话添加到
437
+ - 调整移动端样式
438
+
439
+
440
+ ## v2.5.0
441
+
442
+ `2023-02-20`
443
+
444
+ ### Feature
445
+ - 会话 `loading` 现在显示为光标动画
446
+ - 会话现在可以再次生成回复
447
+ - 会话异常可以再次进行请求
448
+ - 所有删除选项添加确认操作
449
+
450
+ ### Enhancement
451
+ - 调整 `chat` 为路由页面而不是组件形式
452
+ - 更新依赖至最新
453
+ - 调整移动端体验
454
+
455
+ ### BugFix
456
+ - 修复移动端左侧菜单显示不完整的问题
457
+
458
+ ## v2.4.1
459
+
460
+ `2023-02-18`
461
+
462
+ ### Enhancement
463
+ - 调整部份移动端上的样式
464
+ - 输入框支持换行
465
+
466
+ ## v2.4.0
467
+
468
+ `2023-02-17`
469
+
470
+ ### Feature
471
+ - 响应式支持移动端
472
+ ### Enhancement
473
+ - 修改部份描述错误
474
+
475
+ ## v2.3.3
476
+
477
+ `2023-02-16`
478
+
479
+ ### Feature
480
+ - 添加 `README` 部份说明和贡献列表
481
+ - 添加 `docker` 镜像
482
+ - 添加 `GitHub Action` 自动化构建
483
+
484
+ ### BugFix
485
+ - 回退依赖更新导致的 [Eslint 报错](https://github.com/eslint/eslint/issues/16896)
486
+
487
+ ## v2.3.2
488
+
489
+ `2023-02-16`
490
+
491
+ ### Enhancement
492
+ - 更新依赖至最新
493
+ - 优化部份内容
494
+
495
+ ## v2.3.1
496
+
497
+ `2023-02-15`
498
+
499
+ ### BugFix
500
+ - 修复多会话状态下一些意想不到的问题
501
+
502
+ ## v2.3.0
503
+
504
+ `2023-02-15`
505
+ ### Feature
506
+ - 代码类型信息高亮显示
507
+ - 支持 `node ^16` 版本
508
+ - 移动端响应式初步支持
509
+ - `vite` 中 `proxy` 代理
510
+
511
+ ### Enhancement
512
+ - 调整超时处理范围
513
+
514
+ ### BugFix
515
+ - 修复取消请求错误提示会添加到信息中
516
+ - 修复部份情况下提交请求不可用
517
+ - 修复侧边栏宽度变化闪烁的问题
518
+
519
+ ## v2.2.0
520
+
521
+ `2023-02-14`
522
+ ### Feature
523
+ - 会话和上下文本地储存
524
+ - 侧边栏本地储存
525
+
526
+ ## v2.1.0
527
+
528
+ `2023-02-14`
529
+ ### Enhancement
530
+ - 更新依赖至最新
531
+ - 联想功能移动至前端提交,后端只做转发
532
+
533
+ ### BugFix
534
+ - 修复部份项目检测有关 `Bug`
535
+ - 修复清除上下文按钮失效
536
+
537
+ ## v2.0.0
538
+
539
+ `2023-02-13`
540
+ ### Refactor
541
+ 重构并优化大部分内容
542
+
543
+ ## v1.0.5
544
+
545
+ `2023-02-12`
546
+
547
+ ### Enhancement
548
+ - 输入框焦点,连续提交
549
+
550
+ ### BugFix
551
+ - 修复信息框样式问题
552
+ - 修复中文输入法提交问题
553
+
554
+ ## v1.0.4
555
+
556
+ `2023-02-11`
557
+
558
+ ### Feature
559
+ - 支持上下文联想
560
+
561
+ ## v1.0.3
562
+
563
+ `2023-02-11`
564
+
565
+ ### Enhancement
566
+ - 拆分 `service` 文件以便扩展
567
+ - 调整 `Eslint` 相关验证
568
+
569
+ ### BugFix
570
+ - 修复部份控制台报错
571
+
572
+ ## v1.0.2
573
+
574
+ `2023-02-10`
575
+
576
+ ### BugFix
577
+ - 修复新增信息容器不会自动滚动到问题
578
+ - 修复文本过长不换行到问题 [#1](https://github.com/Chanzhaoyu/chatgpt-web/issues/1)
CONTRIBUTING.en.md ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contribution Guide
2
+ Thank you for your valuable time. Your contributions will make this project better! Before submitting a contribution, please take some time to read the getting started guide below.
3
+
4
+ ## Semantic Versioning
5
+ This project follows semantic versioning. We release patch versions for important bug fixes, minor versions for new features or non-important changes, and major versions for significant and incompatible changes.
6
+
7
+ Each major change will be recorded in the `changelog`.
8
+
9
+ ## Submitting Pull Request
10
+ 1. Fork [this repository](https://github.com/Chanzhaoyu/chatgpt-web) and create a branch from `main`. For new feature implementations, submit a pull request to the `feature` branch. For other changes, submit to the `main` branch.
11
+ 2. Install the `pnpm` tool using `npm install pnpm -g`.
12
+ 3. Install the `Eslint` plugin for `VSCode`, or enable `eslint` functionality for other editors such as `WebStorm`.
13
+ 4. Execute `pnpm bootstrap` in the root directory.
14
+ 5. Execute `pnpm install` in the `/service/` directory.
15
+ 6. Make changes to the codebase. If applicable, ensure that appropriate testing has been done.
16
+ 7. Execute `pnpm lint:fix` in the root directory to perform a code formatting check.
17
+ 8. Execute `pnpm type-check` in the root directory to perform a type check.
18
+ 9. Submit a git commit, following the [Commit Guidelines](#commit-guidelines).
19
+ 10. Submit a `pull request`. If there is a corresponding `issue`, please link it using the [linking-a-pull-request-to-an-issue keyword](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword).
20
+
21
+ ## Commit Guidelines
22
+
23
+ Commit messages should follow the [conventional-changelog standard](https://www.conventionalcommits.org/en/v1.0.0/):
24
+
25
+ ```bash
26
+ <type>[optional scope]: <description>
27
+
28
+ [optional body]
29
+
30
+ [optional footer]
31
+ ```
32
+
33
+ ### Commit Types
34
+
35
+ The following is a list of commit types:
36
+
37
+ - feat: New feature or functionality
38
+ - fix: Bug fix
39
+ - docs: Documentation update
40
+ - style: Code style or component style update
41
+ - refactor: Code refactoring, no new features or bug fixes introduced
42
+ - perf: Performance optimization
43
+ - test: Unit test
44
+ - chore: Other commits that do not modify src or test files
45
+
46
+
47
+ ## License
48
+
49
+ [MIT](./license)
CONTRIBUTING.md ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 贡献指南
2
+ 感谢你的宝贵时间。你的贡献将使这个项目变得更好!在提交贡献之前,请务必花点时间阅读下面的入门指南。
3
+
4
+ ## 语义化版本
5
+ 该项目遵循语义化版本。我们对重要的漏洞修复发布修订号,对新特性或不重要的变更发布次版本号,对重大且不兼容的变更发布主版本号。
6
+
7
+ 每个重大更改都将记录在 `changelog` 中。
8
+
9
+ ## 提交 Pull Request
10
+ 1. Fork [此仓库](https://github.com/Chanzhaoyu/chatgpt-web),从 `main` 创建分支。新功能实现请发 pull request 到 `feature` 分支。其他更改发到 `main` 分支。
11
+ 2. 使用 `npm install pnpm -g` 安装 `pnpm` 工具。
12
+ 3. `vscode` 安装了 `Eslint` 插件,其它编辑器如 `webStorm` 打开了 `eslint` 功能。
13
+ 4. 根目录下执行 `pnpm bootstrap`。
14
+ 5. `/service/` 目录下执行 `pnpm install`。
15
+ 6. 对代码库进行更改。如果适用的话,请确保进行了相应的测试。
16
+ 7. 请在根目录下执行 `pnpm lint:fix` 进行代码格式检查。
17
+ 8. 请在根目录下执行 `pnpm type-check` 进行类型检查。
18
+ 9. 提交 git commit, 请同时遵守 [Commit 规范](#commit-指南)
19
+ 10. 提交 `pull request`, 如果有对应的 `issue`,请进行[关联](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword)。
20
+
21
+ ## Commit 指南
22
+
23
+ Commit messages 请遵循[conventional-changelog 标准](https://www.conventionalcommits.org/en/v1.0.0/):
24
+
25
+ ```bash
26
+ <类型>[可选 范围]: <描述>
27
+
28
+ [可选 正文]
29
+
30
+ [可选 脚注]
31
+ ```
32
+
33
+ ### Commit 类型
34
+
35
+ 以下是 commit 类型列表:
36
+
37
+ - feat: 新特性或功能
38
+ - fix: 缺陷修复
39
+ - docs: 文档更新
40
+ - style: 代码风格或者组件样式更新
41
+ - refactor: 代码重构,不引入新功能和缺陷修复
42
+ - perf: 性能优化
43
+ - test: 单元测试
44
+ - chore: 其他不修改 src 或测试文件的提交
45
+
46
+
47
+ ## License
48
+
49
+ [MIT](./license)
Dockerfile ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # build front-end
2
+ FROM node:lts-alpine AS frontend
3
+
4
+ RUN npm install pnpm -g
5
+
6
+ WORKDIR /app
7
+
8
+ COPY ./package.json /app
9
+
10
+ COPY ./pnpm-lock.yaml /app
11
+
12
+ RUN pnpm install
13
+
14
+ COPY . /app
15
+
16
+ RUN pnpm run build
17
+
18
+ # build backend
19
+ FROM node:lts-alpine as backend
20
+
21
+ RUN npm install pnpm -g
22
+
23
+ WORKDIR /app
24
+
25
+ COPY /service/package.json /app
26
+
27
+ COPY /service/pnpm-lock.yaml /app
28
+
29
+ RUN pnpm install
30
+
31
+ COPY /service /app
32
+
33
+ RUN pnpm build
34
+
35
+ # service
36
+ FROM node:lts-alpine
37
+
38
+ RUN npm install pnpm -g
39
+
40
+ WORKDIR /app
41
+
42
+ COPY /service/package.json /app
43
+
44
+ COPY /service/pnpm-lock.yaml /app
45
+
46
+ RUN pnpm install --production && rm -rf /root/.npm /root/.pnpm-store /usr/local/share/.cache /tmp/*
47
+
48
+ COPY /service /app
49
+
50
+ COPY --from=frontend /app/replace-title.sh /app
51
+
52
+ RUN chmod +x /app/replace-title.sh
53
+
54
+ COPY --from=frontend /app/dist /app/public
55
+
56
+ COPY --from=backend /app/build /app/build
57
+
58
+ COPY --from=backend /app/src/utils/templates /app/build/templates
59
+
60
+ EXPOSE 3002
61
+
62
+ RUN --mount=type=secret,id=AUTH_SECRET_KEY,mode=0444,required=true
63
+ RUN --mount=type=secret,id=API_REVERSE_PROXY,mode=0444,required=true
64
+ RUN --mount=type=secret,id=OPENAI_ACCESS_TOKEN,mode=0444,required=true
65
+ RUN --mount=type=secret,id=MONGODB_URL,mode=0444,required=true
66
+ RUN --mount=type=secret,id=OPENAI_API_MODEL,mode=0444,required=true
67
+ RUN --mount=type=secret,id=PASSWORD_MD5_SALT,mode=0444,required=true
68
+ RUN --mount=type=secret,id=REGISTER_ENABLED,mode=0444,required=true
69
+ RUN --mount=type=secret,id=ROOT_USER,mode=0444,required=true
70
+ RUN --mount=type=secret,id=SITE_DOMAIN,mode=0444,required=true
71
+ RUN --mount=type=secret,id=SITE_TITLE,mode=0444,required=true
72
+ RUN --mount=type=secret,id=SMTP_HOST,mode=0444,required=true
73
+ RUN --mount=type=secret,id=SMTP_PASSWORD,mode=0444,required=true
74
+ RUN --mount=type=secret,id=SMTP_PORT,mode=0444,required=true
75
+ RUN --mount=type=secret,id=SMTP_TSL,mode=0444,required=true
76
+ RUN --mount=type=secret,id=SMTP_USERNAME,mode=0444,required=true
77
+
78
+ CMD ["sh", "-c", "./replace-title.sh && pnpm run prod"]
README.en.md ADDED
@@ -0,0 +1,410 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ChatGPT Web
2
+
3
+ <div style="font-size: 1.5rem;">
4
+ <a href="./README.md">中文</a> |
5
+ <a href="./README.en.md">English</a>
6
+ </div>
7
+ </br>
8
+
9
+ ## Introduction
10
+ > **This project is forked from [Chanzhaoyu/chatgpt-web](https://github.com/Chanzhaoyu/chatgpt-web), some unique features have been added:**
11
+
12
+ [✓] Register & Login & Reset Password
13
+
14
+ [✓] Sync chat history
15
+
16
+ [✓] Front-end page setting apikey
17
+
18
+ [✓] Custom Sensitive Words
19
+
20
+ [✓] Set unique prompts for each chat room
21
+
22
+ [✓] Users manager
23
+
24
+ [✓] Random Key
25
+
26
+ </br>
27
+
28
+ ## Screenshots
29
+ > Disclaimer: This project is only released on GitHub, under the MIT License, free and for open-source learning purposes. There will be no account selling, paid services, discussion groups, or forums. Beware of fraud.
30
+
31
+ ![cover3](./docs/login.jpg)
32
+ ![cover](./docs/c1.png)
33
+ ![cover2](./docs/c2.png)
34
+ ![cover3](./docs/basesettings.jpg)
35
+ ![cover3](./docs/prompt_en.jpg)
36
+ ![cover3](./docs/user-manager.jpg)
37
+ ![cover3](./docs/key-manager-en.jpg)
38
+
39
+ - [ChatGPT Web](#chatgpt-web)
40
+ - [Introduction](#introduction)
41
+ - [Roadmap](#roadmap)
42
+ - [Prerequisites](#prerequisites)
43
+ - [Node](#node)
44
+ - [PNPM](#pnpm)
45
+ - [Fill in the Keys](#fill-in-the-keys)
46
+ - [Install Dependencies](#install-dependencies)
47
+ - [Backend](#backend)
48
+ - [Frontend](#frontend)
49
+ - [Run in Test Environment](#run-in-test-environment)
50
+ - [Backend Service](#backend-service)
51
+ - [Frontend Webpage](#frontend-webpage)
52
+ - [Packaging](#packaging)
53
+ - [Using Docker](#using-docker)
54
+ - [Docker Parameter Example](#docker-parameter-example)
55
+ - [Docker Build \& Run](#docker-build--run)
56
+ - [Docker Compose](#docker-compose)
57
+ - [Deployment with Railway](#deployment-with-railway)
58
+ - [Railway Environment Variables](#railway-environment-variables)
59
+ - [Manual packaging](#manual-packaging)
60
+ - [Backend service](#backend-service-1)
61
+ - [Frontend webpage](#frontend-webpage-1)
62
+ - [Frequently Asked Questions](#frequently-asked-questions)
63
+ - [Contributing](#contributing)
64
+ - [Sponsorship](#sponsorship)
65
+ - [License](#license)
66
+
67
+ ## Introduction
68
+
69
+ Supports dual models, provides two unofficial `ChatGPT API` methods:
70
+
71
+ | Method | Free? | Reliability | Quality |
72
+ | --------------------------------------------- | ------ | ----------- | ------- |
73
+ | `ChatGPTAPI(gpt-3.5-turbo-0301)` | No | Reliable | Relatively clumsy |
74
+ | `ChatGPTUnofficialProxyAPI(Web accessToken)` | Yes | Relatively unreliable | Smart |
75
+
76
+ Comparison:
77
+ 1. `ChatGPTAPI` uses `gpt-3.5-turbo-0301` to simulate `ChatGPT` through the official `OpenAI` completion `API` (the most reliable method, but it is not free and does not use models specifically tuned for chat).
78
+ 2. `ChatGPTUnofficialProxyAPI` accesses `ChatGPT`'s backend `API` via an unofficial proxy server to bypass `Cloudflare` (uses the real `ChatGPT`, is very lightweight, but depends on third-party servers and has rate limits).
79
+
80
+ [Details](https://github.com/Chanzhaoyu/chatgpt-web/issues/138)
81
+
82
+ Switching Methods:
83
+ 1. Go to the `service/.env.example` file and copy the contents to the `service/.env` file.
84
+ 2. For `OpenAI API Key`, fill in the `OPENAI_API_KEY` field [(Get apiKey)](https://platform.openai.com/overview).
85
+ 3. For `Web API`, fill in the `OPENAI_ACCESS_TOKEN` field [(Get accessToken)](https://chat.openai.com/api/auth/session).
86
+ 4. When both are present, `OpenAI API Key` takes precedence.
87
+
88
+ Reverse Proxy:
89
+
90
+ Available when using `ChatGPTUnofficialProxyAPI`.[Details](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy)
91
+
92
+ ```shell
93
+ # service/.env
94
+ API_REVERSE_PROXY=
95
+ ```
96
+
97
+ Environment Variables:
98
+
99
+ For all parameter variables, check [here](#docker-parameter-example) or see:
100
+
101
+ ```
102
+ /service/.env
103
+ ```
104
+
105
+ ## Roadmap
106
+ [✓] Dual models
107
+
108
+ [✓] Multiple session storage and context logic
109
+
110
+ [✓] Formatting and beautifying code-like message types
111
+
112
+ [✓] Login or Register
113
+
114
+ [✓] Set API key and other information on the front-end page.
115
+
116
+ [✓] Data import and export
117
+
118
+ [✓] Save message to local image
119
+
120
+ [✓] Multilingual interface
121
+
122
+ [✓] Interface themes
123
+
124
+ [✗] More...
125
+
126
+ ## Prerequisites
127
+
128
+ ### Node
129
+
130
+ `node` requires version `^16 || ^18` (`node >= 14` requires installation of [fetch polyfill](https://github.com/developit/unfetch#usage-as-a-polyfill)), and multiple local `node` versions can be managed using [nvm](https://github.com/nvm-sh/nvm).
131
+
132
+ ```shell
133
+ node -v
134
+ ```
135
+
136
+ ### PNPM
137
+ If you have not installed `pnpm` before:
138
+ ```shell
139
+ npm install pnpm -g
140
+ ```
141
+
142
+ ### Fill in the Keys
143
+
144
+ Get `Openai Api Key` or `accessToken` and fill in the local environment variables [jump](#introduction)
145
+
146
+ ```
147
+ # service/.env file
148
+
149
+ # OpenAI API Key - https://platform.openai.com/overview
150
+ OPENAI_API_KEY=
151
+
152
+ # change this to an `accessToken` extracted from the ChatGPT site's `https://chat.openai.com/api/auth/session` response
153
+ OPENAI_ACCESS_TOKEN=
154
+ ```
155
+
156
+ ## Install Dependencies
157
+
158
+ > To make it easier for `backend developers` to understand, we did not use the front-end `workspace` mode, but stored it in different folders. If you only need to do secondary development of the front-end page, delete the `service` folder.
159
+
160
+ ### Backend
161
+
162
+ Enter the `/service` folder and run the following command
163
+
164
+ ```shell
165
+ pnpm install
166
+ ```
167
+
168
+ ### Frontend
169
+ Run the following command in the root directory
170
+ ```shell
171
+ pnpm bootstrap
172
+ ```
173
+
174
+ ## Run in Test Environment
175
+ ### Backend Service
176
+
177
+ Enter the `/service` folder and run the following command
178
+
179
+ ```shell
180
+ pnpm start
181
+ ```
182
+
183
+ ### Frontend Webpage
184
+ Run the following command in the root directory
185
+ ```shell
186
+ pnpm dev
187
+ ```
188
+
189
+ ## Packaging
190
+
191
+ ### Using Docker
192
+
193
+ #### Docker Parameter Example
194
+
195
+ - `OPENAI_API_KEY` one of two
196
+ - `OPENAI_ACCESS_TOKEN` one of two, `OPENAI_API_KEY` takes precedence when both are present
197
+ - `OPENAI_API_BASE_URL` optional, available when `OPENAI_API_KEY` is set
198
+ - `OPENAI_API_MODEL` `ChatGPTAPI` OR `ChatGPTUnofficialProxyAPI`
199
+ - `API_REVERSE_PROXY` optional, available when `OPENAI_ACCESS_TOKEN` is set [Reference](#introduction)
200
+ - `AUTH_SECRET_KEY` Access Password,optional
201
+ - `TIMEOUT_MS` timeout, in milliseconds, optional
202
+ - `SOCKS_PROXY_HOST` optional, effective with SOCKS_PROXY_PORT
203
+ - `SOCKS_PROXY_PORT` optional, effective with SOCKS_PROXY_HOST
204
+ - `SOCKS_PROXY_USERNAME` optional, effective with SOCKS_PROXY_HOST and SOCKS_PROXY_PORT
205
+ - `SOCKS_PROXY_PASSWORD` optional, effective with SOCKS_PROXY_HOST and SOCKS_PROXY_PORT
206
+ - `HTTPS_PROXY` optional, support http,https, socks5
207
+
208
+ ![docker](./docs/docker.png)
209
+
210
+ #### Docker Build & Run
211
+
212
+ ```bash
213
+ docker build -t chatgpt-web .
214
+
215
+ # foreground operation
216
+ docker run --name chatgpt-web --rm -it -p 127.0.0.1:3002:3002 --env OPENAI_API_KEY=your_api_key chatgpt-web
217
+
218
+ # background operation
219
+ docker run --name chatgpt-web -d -p 127.0.0.1:3002:3002 --env OPENAI_API_KEY=your_api_key chatgpt-web
220
+
221
+ # running address
222
+ http://localhost:3002/
223
+ ```
224
+
225
+ #### Docker Compose
226
+
227
+ [Hub Address](https://hub.docker.com/repository/docker/kerwin1202/chatgpt-web/general)
228
+
229
+ ```yml
230
+ version: '3'
231
+
232
+ services:
233
+ app:
234
+ image: kerwin1202/chatgpt-web # always use latest, pull the tag image again when updating
235
+ container_name: chatgptweb
236
+ restart: unless-stopped
237
+ ports:
238
+ - 3002:3002
239
+ depends_on:
240
+ - database
241
+ environment:
242
+ TZ: Asia/Shanghai
243
+ # one of two
244
+ OPENAI_API_KEY: xxxxxx
245
+ # one of two
246
+ OPENAI_ACCESS_TOKEN: xxxxxx
247
+ # api interface url, optional, available when OPENAI_API_KEY is set
248
+ OPENAI_API_BASE_URL: xxxx
249
+ # ChatGPTAPI 或者 ChatGPTUnofficialProxyAPI
250
+ OPENAI_API_MODEL: xxxx
251
+ # reverse proxy, optional
252
+ API_REVERSE_PROXY: xxx
253
+ # timeout, in milliseconds, optional
254
+ TIMEOUT_MS: 600000
255
+ # socks proxy, optional, effective with SOCKS_PROXY_PORT
256
+ SOCKS_PROXY_HOST: xxxx
257
+ # socks proxy port, optional, effective with SOCKS_PROXY_HOST
258
+ SOCKS_PROXY_PORT: xxxx
259
+ # socks proxy, optional, effective with SOCKS_PROXY_HOST and SOCKS_PROXY_PORT
260
+ SOCKS_PROXY_USERNAME: xxxx
261
+ # socks proxy port, optional, effective with SOCKS_PROXY_HOST and SOCKS_PROXY_PORT
262
+ SOCKS_PROXY_PASSWORD: xxxx
263
+ # HTTPS Proxy,optional, support http, https, socks5
264
+ HTTPS_PROXY: http://xxx:7890
265
+ # Title for site
266
+ SITE_TITLE: ChatGpt Web
267
+ # access salt,optional Allow login if not empty.
268
+ AUTH_SECRET_KEY: xxx
269
+ # mongodb's connection string
270
+ MONGODB_URL: 'mongodb://chatgpt:xxxx@database:27017'
271
+ # Register enabled
272
+ REGISTER_ENABLED: true
273
+ # After register enabled, Allowed mailbox suffixes for website registration. If empty, any suffix is allowed
274
+ REGISTER_MAILS: '@qq.com,@sina.com,@163.com'
275
+ # After register enabled, Salt for password encryption
276
+ PASSWORD_MD5_SALT: xxx
277
+ # After register enabled, super administrator
278
+ ROOT_USER: me@example.com
279
+ # After register enabled, The website's domain ending without /
280
+ SITE_DOMAIN: http://127.0.0.1:3002
281
+ # After register enabled, The smtp settings
282
+ SMTP_HOST: smtp.exmail.qq.com
283
+ SMTP_PORT: 465
284
+ SMTP_TSL: true
285
+ SMTP_USERNAME: noreply@examile.com
286
+ SMTP_PASSWORD: xxx
287
+ # Enable sensitive word review, because the response result is streaming, so there is currently no review.
288
+ AUDIT_ENABLED: false
289
+ # https://ai.baidu.com/ai-doc/ANTIPORN/Vk3h6xaga
290
+ AUDIT_PROVIDER: baidu
291
+ AUDIT_API_KEY: xxx
292
+ AUDIT_API_SECRET: xxx
293
+ AUDIT_TEXT_LABEL: xxx
294
+ links:
295
+ - database
296
+
297
+ database:
298
+ image: mongo
299
+ container_name: chatgptweb-database
300
+ restart: unless-stopped
301
+ ports:
302
+ - '27017:27017'
303
+ expose:
304
+ - '27017'
305
+ volumes:
306
+ - mongodb:/data/db
307
+ environment:
308
+ MONGO_INITDB_ROOT_USERNAME: chatgpt
309
+ MONGO_INITDB_ROOT_PASSWORD: xxxx
310
+ MONGO_INITDB_DATABASE: chatgpt
311
+
312
+ volumes:
313
+ mongodb: {}
314
+ ```
315
+ The `OPENAI_API_BASE_URL` is optional and only used when setting the `OPENAI_API_KEY`.
316
+
317
+ ### Deployment with Railway
318
+
319
+ [![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template/yytmgc)
320
+
321
+ #### Railway Environment Variables
322
+
323
+ | Environment Variable | Required | Description |
324
+ |------------------------|-------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|
325
+ | `PORT` | Required | Default: `3002` |
326
+ | `AUTH_SECRET_KEY` | Optional | access password |
327
+ | `TIMEOUT_MS` | Optional | Timeout in milliseconds |
328
+ | `OPENAI_API_KEY` | Optional | Required for `OpenAI API`. `apiKey` can be obtained from [here](https://platform.openai.com/overview). |
329
+ | `OPENAI_ACCESS_TOKEN` | Optional | Required for `Web API`. `accessToken` can be obtained from [here](https://chat.openai.com/api/auth/session). |
330
+ | `OPENAI_API_BASE_URL` | Optional, only for `OpenAI API` | API endpoint. |
331
+ | `OPENAI_API_MODEL` | `ChatGPTAPI` OR `ChatGPTUnofficialProxyAPI` | API model. |
332
+ | `API_REVERSE_PROXY` | Optional, only for `Web API` | Reverse proxy address for `Web API`. [Details](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy) |
333
+ | `SOCKS_PROXY_HOST` | Optional, effective with `SOCKS_PROXY_PORT` | Socks proxy. |
334
+ | `SOCKS_PROXY_PORT` | Optional, effective with `SOCKS_PROXY_HOST` | Socks proxy port. |
335
+ | `SOCKS_PROXY_USERNAME` | Optional, effective with `SOCKS_PROXY_HOST` & `SOCKS_PROXY_PORT` | Socks proxy username. |
336
+ | `SOCKS_PROXY_PASSWORD` | Optional, effective with `SOCKS_PROXY_HOST` & `SOCKS_PROXY_PORT` | Socks proxy password. |
337
+ | `HTTPS_PROXY` | Optional | HTTPS Proxy. |
338
+
339
+ > Note: Changing environment variables in Railway will cause re-deployment.
340
+
341
+ ### Manual packaging
342
+
343
+ #### Backend service
344
+
345
+ > If you don't need the `node` interface of this project, you can skip the following steps.
346
+
347
+ Copy the `service` folder to a server that has a `node` service environment.
348
+
349
+ ```shell
350
+ # Install
351
+ pnpm install
352
+
353
+ # Build
354
+ pnpm build
355
+
356
+ # Run
357
+ pnpm prod
358
+ ```
359
+
360
+ PS: You can also run `pnpm start` directly on the server without packaging.
361
+
362
+ #### Frontend webpage
363
+
364
+ 1. Refer to the root directory `.env.example` file content to create `.env` file, modify `VITE_GLOB_API_URL` in `.env` at the root directory to your actual backend interface address.
365
+ 2. Run the following command in the root directory and then copy the files in the `dist` folder to the root directory of your website service.
366
+
367
+ [Reference information](https://cn.vitejs.dev/guide/static-deploy.html#building-the-app)
368
+
369
+ ```shell
370
+ pnpm build
371
+ ```
372
+
373
+ ## Frequently Asked Questions
374
+
375
+ Q: Why does Git always report an error when committing?
376
+
377
+ A: Because there is submission information verification, please follow the [Commit Guidelines](./CONTRIBUTING.en.md).
378
+
379
+ Q: Where to change the request interface if only the frontend page is used?
380
+
381
+ A: The `VITE_GLOB_API_URL` field in the `.env` file at the root directory.
382
+
383
+ Q: All red when saving the file?
384
+
385
+ A: For `vscode`, please install the recommended plug-in of the project or manually install the `Eslint` plug-in.
386
+
387
+ Q: Why doesn't the frontend have a typewriter effect?
388
+
389
+ A: One possible reason is that after Nginx reverse proxying, buffering is turned on, and Nginx will try to buffer a certain amount of data from the backend before sending it to the browser. Please try adding `proxy_buffering off;` after the reverse proxy parameter and then reloading Nginx. Other web server configurations are similar.
390
+
391
+ Q: The content returned is incomplete?
392
+
393
+ A: There is a length limit for the content returned by the API each time. You can modify the `VITE_GLOB_OPEN_LONG_REPLY` field in the `.env` file under the root directory, set it to `true`, and rebuild the front-end to enable the long reply feature, which can return the full content. It should be noted that using this feature may bring more API usage fees.
394
+
395
+ ## Contributing
396
+
397
+ Please read the [Contributing Guidelines](./CONTRIBUTING.en.md) before contributing.
398
+
399
+ Thanks to all the contributors!
400
+
401
+ <a href="https://github.com/Chanzhaoyu/chatgpt-web/graphs/contributors">
402
+ <img src="https://contrib.rocks/image?repo=Chanzhaoyu/chatgpt-web" />
403
+ </a>
404
+
405
+ ## Sponsorship
406
+
407
+ If you find this project helpful, please give me a star.
408
+
409
+ ## License
410
+ MIT © [Kerwin1202](./license)
README.md CHANGED
@@ -1,10 +1,445 @@
1
  ---
2
- title: Chatup Pro
3
- emoji:
4
- colorFrom: purple
5
- colorTo: red
6
  sdk: docker
7
  pinned: false
 
 
8
  ---
9
 
10
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: dvcchat-pro
3
+ emoji: 🐠
4
+ colorFrom: green
5
+ colorTo: blue
6
  sdk: docker
7
  pinned: false
8
+ app_port: 3002
9
+ duplicated_from: dvc890/chatup
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
13
+
14
+ # ChatGPT Web
15
+
16
+ <div style="font-size: 1.5rem;">
17
+ <a href="./README.md">中文</a> |
18
+ <a href="./README.en.md">English</a>
19
+ </div>
20
+ </br>
21
+
22
+ ## 说明
23
+ > **此项目 Fork 自 [Chanzhaoyu/chatgpt-web](https://github.com/Chanzhaoyu/chatgpt-web), 新增了部分特色功能:**
24
+
25
+ [✓] 注册&登录&重置密码
26
+
27
+ [✓] 同步历史会话
28
+
29
+ [✓] 前端页面设置apikey
30
+
31
+ [✓] 自定义敏感词
32
+
33
+ [✓] 每个会话设置独有 Prompt
34
+
35
+ [✓] 用户管理
36
+
37
+ [✓] 多 Key 随机
38
+ </br>
39
+
40
+ ## 截图
41
+ > 声明:此项目只发布于 Github,基于 MIT 协议,免费且作为开源学习使用。并且不会有任何形式的卖号、付费服务、讨论群、讨论组等行为。谨防受骗。
42
+
43
+ ![cover3](./docs/login.jpg)
44
+ ![cover](./docs/c1.png)
45
+ ![cover2](./docs/c2.png)
46
+ ![cover3](./docs/basesettings.jpg)
47
+ ![cover3](./docs/prompt.jpg)
48
+ ![cover3](./docs/user-manager.jpg)
49
+ ![cover3](./docs/key-manager.jpg)
50
+
51
+ - [ChatGPT Web](#chatgpt-web)
52
+ - [说明](#说明)
53
+ - [截图](#截图)
54
+ - [介绍](#介绍)
55
+ - [待实现路线](#待实现路线)
56
+ - [前置要求](#前置要求)
57
+ - [Node](#node)
58
+ - [PNPM](#pnpm)
59
+ - [填写密钥](#填写密钥)
60
+ - [安装依赖](#安装依赖)
61
+ - [后端](#后端)
62
+ - [前端](#前端)
63
+ - [测试环境运行](#测试环境运行)
64
+ - [后端服务](#后端服务)
65
+ - [前端网页](#前端网页)
66
+ - [环境变量](#环境变量)
67
+ - [打包](#打包)
68
+ - [使用 Docker](#使用-docker)
69
+ - [Docker 参数示例](#docker-参数示例)
70
+ - [Docker build \& Run](#docker-build--run)
71
+ - [Docker compose](#docker-compose)
72
+ - [防止爬虫抓取](#防止爬虫抓取)
73
+ - [使用 Railway 部署](#使用-railway-部署)
74
+ - [Railway 环境变量](#railway-环境变量)
75
+ - [手动打包](#手动打包)
76
+ - [后端服务](#后端服务-1)
77
+ - [前端网页](#前端网页-1)
78
+ - [常见问题](#常见问题)
79
+ - [参与贡献](#参与贡献)
80
+ - [赞助](#赞助)
81
+ - [License](#license)
82
+ ## 介绍
83
+
84
+ 支持双模型,提供了两种非官方 `ChatGPT API` 方法
85
+
86
+ | 方式 | 免费? | 可靠性 | 质量 |
87
+ | --------------------------------------------- | ------ | ---------- | ---- |
88
+ | `ChatGPTAPI(gpt-3.5-turbo-0301)` | 否 | 可靠 | 相对较笨 |
89
+ | `ChatGPTUnofficialProxyAPI(网页 accessToken)` | 是 | 相对不可靠 | 聪明 |
90
+
91
+ 对比:
92
+ 1. `ChatGPTAPI` 使用 `gpt-3.5-turbo` 通过 `OpenAI` 官方 `API` 调用 `ChatGPT`
93
+ 2. `ChatGPTUnofficialProxyAPI` 使用非官方代理服务器访问 `ChatGPT` 的后端`API`,绕过`Cloudflare`(依赖于第三方服务器,并且有速率限制)
94
+
95
+ 警告:
96
+ 1. 你应该首先使用 `API` 方式
97
+ 2. 使用 `API` 时,如果网络不通,那是国内被墙了,你需要自建代理,绝对不要使用别人的公开代理,那是危险的。
98
+ 3. 使用 `accessToken` 方式时反向代理将向第三方暴露您的访问令牌,这样做应该不会产生任何不良影响,但在使用这种方法之前请考虑风险。
99
+ 4. 使用 `accessToken` 时,不管你是国内还是国外的机器,都会使用代理。默认代理为 [pengzhile](https://github.com/pengzhile) 大佬的 `https://ai.fakeopen.com/api/conversation`,这不是后门也不是监听,除非你有能力自己翻过 `CF` 验证,用前请知悉。[社区代理](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy)(注意:只有这两个是推荐,其他第三方来源,请自行甄别)
100
+ 5. 把项目发布到公共网络时,你应该设置 `AUTH_SECRET_KEY` 变量添加你的密码访问权限,你也应该修改 `index.html` 中的 `title`,防止被关键词搜索到。
101
+
102
+ 切换方式:
103
+ 1. 进入 `service/.env.example` 文件,复制内容到 `service/.env` 文件
104
+ 2. 使用 `OpenAI API Key` 请填写 `OPENAI_API_KEY` 字段 [(获取 apiKey)](https://platform.openai.com/overview)
105
+ 3. 使用 `Web API` 请填写 `OPENAI_ACCESS_TOKEN` 字段 [(获取 accessToken)](https://chat.openai.com/api/auth/session)
106
+ 4. 同时存在时以 `OpenAI API Key` 优先
107
+
108
+ 环境变量:
109
+
110
+ 全部参数变量请查看或[这里](#环境变量)
111
+
112
+ ```
113
+ /service/.env.example
114
+ ```
115
+
116
+ ## 待实现路线
117
+ [✓] 双模型
118
+
119
+ [✓] 多会话储存和上下文逻辑
120
+
121
+ [✓] 对代码等消息类型的格式化美化处理
122
+
123
+ [✓] 支持用户登录注册
124
+
125
+ [✓] 前端页面设置 apikey 等信息
126
+
127
+ [✓] 数据导入、导出
128
+
129
+ [✓] 保存消息到本地图片
130
+
131
+ [✓] 界面多语言
132
+
133
+ [✓] 界面主题
134
+
135
+ [✗] More...
136
+
137
+ ## 前置要求
138
+
139
+ ### Node
140
+
141
+ `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` 版本
142
+
143
+ ```shell
144
+ node -v
145
+ ```
146
+
147
+ ### PNPM
148
+ 如果你没有安装过 `pnpm`
149
+ ```shell
150
+ npm install pnpm -g
151
+ ```
152
+
153
+ ### 填写密钥
154
+ 获取 `Openai Api Key` 或 `accessToken` 并填写本地环境变量 [跳转](#介绍)
155
+
156
+ ```
157
+ # service/.env 文件
158
+
159
+ # OpenAI API Key - https://platform.openai.com/overview
160
+ OPENAI_API_KEY=
161
+
162
+ # change this to an `accessToken` extracted from the ChatGPT site's `https://chat.openai.com/api/auth/session` response
163
+ OPENAI_ACCESS_TOKEN=
164
+ ```
165
+
166
+ ## 安装依赖
167
+
168
+ > 为了简便 `后端开发人员` 的了解负担,所以并没有采用前端 `workspace` 模式,而是分文件夹存放。如果只需要前端页面做二次开发,删除 `service` 文件夹即可。
169
+
170
+ ### 后端
171
+
172
+ 进入文件夹 `/service` 运行以下命令
173
+
174
+ ```shell
175
+ pnpm install
176
+ ```
177
+
178
+ ### 前端
179
+ 根目录下运行以下命令
180
+ ```shell
181
+ pnpm bootstrap
182
+ ```
183
+
184
+ ## 测试环境运行
185
+ ### 后端服务
186
+
187
+ 进入文件夹 `/service` 运行以下命令
188
+
189
+ ```shell
190
+ pnpm start
191
+ ```
192
+
193
+ ### 前端网页
194
+ 根目录下运行以下命令
195
+ ```shell
196
+ pnpm dev
197
+ ```
198
+
199
+ ## 环境变量
200
+
201
+ `API` 可用:
202
+
203
+ - `OPENAI_API_KEY` 和 `OPENAI_ACCESS_TOKEN` 二选一
204
+ - `OPENAI_API_BASE_URL` 设置接口地址,可选,默认:`https://api.openai.com`
205
+ - `OPENAI_API_DISABLE_DEBUG` 设置接口关闭 debug 日志,可选,默认:empty 不关闭
206
+
207
+ `ACCESS_TOKEN` 可用:
208
+
209
+ - `OPENAI_ACCESS_TOKEN` 和 `OPENAI_API_KEY` 二选一,同时存在时,`OPENAI_API_KEY` 优先
210
+ - `API_REVERSE_PROXY` 设置反向代理,可选,默认:`https://ai.fakeopen.com/api/conversation`,[社区](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy)(注意:只有这两个是推荐,其他第三方来源,请自行甄别)
211
+
212
+ 通用:
213
+
214
+ - `AUTH_SECRET_KEY` 访问权限密钥,可选
215
+ - `MAX_REQUEST_PER_HOUR` 每小时最大请求次数,可选,默认无限
216
+ - `TIMEOUT_MS` 超时,单位毫秒,可选
217
+ - `SOCKS_PROXY_HOST` 和 `SOCKS_PROXY_PORT` 一起时生效,可选
218
+ - `SOCKS_PROXY_PORT` 和 `SOCKS_PROXY_HOST` 一起时生效,可选
219
+ - `HTTPS_PROXY` 支持 `http`,`https`, `socks5`,可选
220
+
221
+ ## 打包
222
+
223
+ ### 使用 Docker
224
+
225
+ #### Docker 参数示例
226
+
227
+ ![docker](./docs/docker.png)
228
+
229
+ #### Docker build & Run
230
+
231
+ ```bash
232
+ docker build -t chatgpt-web .
233
+
234
+ # 前台运行
235
+ docker run --name chatgpt-web --rm -it -p 127.0.0.1:3002:3002 --env OPENAI_API_KEY=your_api_key chatgpt-web
236
+
237
+ # 后台运行
238
+ docker run --name chatgpt-web -d -p 127.0.0.1:3002:3002 --env OPENAI_API_KEY=your_api_key chatgpt-web
239
+
240
+ # 运行地址
241
+ http://localhost:3002/
242
+ ```
243
+
244
+ #### Docker compose
245
+
246
+ [Hub 地址](https://hub.docker.com/repository/docker/kerwin1202/chatgpt-web/general)
247
+
248
+ ```yml
249
+ version: '3'
250
+
251
+ services:
252
+ app:
253
+ image: kerwin1202/chatgpt-web # 总是使用latest,更新时重新pull该tag镜像即可
254
+ container_name: chatgptweb
255
+ restart: unless-stopped
256
+ ports:
257
+ - 3002:3002
258
+ depends_on:
259
+ - database
260
+ environment:
261
+ TZ: Asia/Shanghai
262
+ # 二选一
263
+ OPENAI_API_KEY: sk-xxx
264
+ # 二选一
265
+ OPENAI_ACCESS_TOKEN: xxx
266
+ # API接口地址,可选,设置 OPENAI_API_KEY 时可用
267
+ OPENAI_API_BASE_URL: xxx
268
+ # ChatGPTAPI ChatGPTUnofficialProxyAPI
269
+ OPENAI_API_MODEL: ChatGPTAPI
270
+ # 反向代理,可选
271
+ API_REVERSE_PROXY: xxx
272
+ # 每小时最大请求次数,可选,默认无限
273
+ MAX_REQUEST_PER_HOUR: 0
274
+ # 超时,单位毫秒,可选
275
+ TIMEOUT_MS: 600000
276
+ # Socks代理,可选,和 SOCKS_PROXY_PORT 一起时生效
277
+ SOCKS_PROXY_HOST: xxx
278
+ # Socks代理端口,可选,和 SOCKS_PROXY_HOST 一起时生效
279
+ SOCKS_PROXY_PORT: xxx
280
+ # HTTPS 代理,可选,支持 http,https,socks5
281
+ HTTPS_PROXY: http://xxx:7890
282
+ # 访问jwt加密参数,可选 不为空则允许登录 同时需要设置 MONGODB_URL
283
+ AUTH_SECRET_KEY: xxx
284
+ # 网站名称
285
+ SITE_TITLE: ChatGpt Web
286
+ # mongodb 的连接字符串
287
+ MONGODB_URL: 'mongodb://chatgpt:xxxx@database:27017'
288
+ # 网站是否开启注册
289
+ REGISTER_ENABLED: 'true'
290
+ # 开启注册之后 网站注册允许的邮箱后缀 如果空 则允许任意后缀
291
+ REGISTER_MAILS: '@qq.com,@sina.com,@163.com'
292
+ # 开启注册之后 密码加密的盐
293
+ PASSWORD_MD5_SALT: xxx
294
+ # 开启注册之后 超级管理邮箱
295
+ ROOT_USER: me@example.com
296
+ # 开启注册之后 网站域名 不含 / 注册的时候发送验证邮箱使用
297
+ SITE_DOMAIN: http://127.0.0.1:3002
298
+ # 开启注册之后 发送验证邮箱配置
299
+ SMTP_HOST: smtp.exmail.qq.com
300
+ SMTP_PORT: 465
301
+ SMTP_TSL: 'true'
302
+ SMTP_USERNAME: noreply@examile.com
303
+ SMTP_PASSWORD: xxx
304
+ # 是否开启敏感词审核, 因为响应结果是流式 所以暂时没审核
305
+ AUDIT_ENABLED: 'false'
306
+ # https://ai.baidu.com/ai-doc/ANTIPORN/Vk3h6xaga
307
+ AUDIT_PROVIDER: baidu
308
+ AUDIT_API_KEY: xxx
309
+ AUDIT_API_SECRET: xxx
310
+ AUDIT_TEXT_LABEL: xxx
311
+ links:
312
+ - database
313
+
314
+ database:
315
+ image: mongo
316
+ container_name: chatgptweb-database
317
+ restart: unless-stopped
318
+ ports:
319
+ - '27017:27017'
320
+ expose:
321
+ - '27017'
322
+ volumes:
323
+ - mongodb:/data/db
324
+ environment:
325
+ MONGO_INITDB_ROOT_USERNAME: chatgpt
326
+ MONGO_INITDB_ROOT_PASSWORD: xxxx
327
+ MONGO_INITDB_DATABASE: chatgpt
328
+
329
+ volumes:
330
+ mongodb: {}
331
+ ```
332
+ - `OPENAI_API_BASE_URL` 可选,设置 `OPENAI_API_KEY` 时可用
333
+
334
+ #### 防止爬虫抓取
335
+
336
+ **nginx**
337
+
338
+ 将下面配置填入nginx配置文件中,可以参考 `docker-compose/nginx/nginx.conf` 文件中添加反爬虫的方法
339
+
340
+ ```
341
+ # 防止爬虫抓取
342
+ 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"){
343
+ return 403;
344
+ }
345
+ ```
346
+
347
+ ### 使用 Railway 部署
348
+
349
+ [![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template/yytmgc)
350
+
351
+ #### Railway 环境变量
352
+
353
+ | 环境变量名称 | 必填 | 备注 |
354
+ | --------------------- | ---------------------- | -------------------------------------------------------------------------------------------------- |
355
+ | `PORT` | 必填 | 默认 `3002`
356
+ | `AUTH_SECRET_KEY` | 可选 | 访问权限密钥 |
357
+ | `MAX_REQUEST_PER_HOUR` | 可选 | 每小时最大请求次数,可选,默认无限 |
358
+ | `TIMEOUT_MS` | 可选 | 超时时间,单位毫秒 |
359
+ | `OPENAI_API_KEY` | `OpenAI API` 二选一 | 使用 `OpenAI API` 所需的 `apiKey` [(获取 apiKey)](https://platform.openai.com/overview) |
360
+ | `OPENAI_ACCESS_TOKEN` | `Web API` 二选一 | 使用 `Web API` 所需的 `accessToken` [(获取 accessToken)](https://chat.openai.com/api/auth/session) |
361
+ | `OPENAI_API_BASE_URL` | 可选,`OpenAI API` 时可用 | `API`接口地址 |
362
+ | `OPENAI_API_MODEL` | ChatGPTAPI OR ChatGPTUnofficialProxyAPI | `API`模型 |
363
+ | `API_REVERSE_PROXY` | 可选,`Web API` 时可用 | `Web API` 反向代理地址 [详情](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy) |
364
+ | `SOCKS_PROXY_HOST` | 可选,和 `SOCKS_PROXY_PORT` 一起时生效 | Socks代理 |
365
+ | `SOCKS_PROXY_PORT` | 可选,和 `SOCKS_PROXY_HOST` 一起时生效 | Socks代理端口 |
366
+ | `SOCKS_PROXY_USERNAME` | 可选,和 `SOCKS_PROXY_HOST` 一起时生效 | Socks代理用户名 |
367
+ | `SOCKS_PROXY_PASSWORD` | 可选,和 `SOCKS_PROXY_HOST` 一起时生效 | Socks代理密码 |
368
+ | `HTTPS_PROXY` | 可选 | HTTPS 代理,支持 http,https, socks5 |
369
+
370
+ > 注意: `Railway` 修改环境变量会重新 `Deploy`
371
+
372
+ ### 手动打包
373
+ #### 后端服务
374
+ > 如果你不需要本项目的 `node` 接口,可以省略如下操作
375
+
376
+ 复制 `service` 文件夹到你有 `node` 服务环境的服务器上。
377
+
378
+ ```shell
379
+ # 安装
380
+ pnpm install
381
+
382
+ # 打包
383
+ pnpm build
384
+
385
+ # 运行
386
+ pnpm prod
387
+ ```
388
+
389
+ PS: 不进行打包,直接在服务器上运行 `pnpm start` 也可
390
+
391
+ #### 前端网页
392
+
393
+ 1、修改根目录下 `.env` 文件中的 `VITE_GLOB_API_URL` 为你的实际后端接口地址
394
+
395
+ 2、根目录下运行以下命令,然后将 `dist` 文件夹内的文件复制到你网站服务的根目录下
396
+
397
+ [参考信息](https://cn.vitejs.dev/guide/static-deploy.html#building-the-app)
398
+
399
+ ```shell
400
+ pnpm build
401
+ ```
402
+
403
+ ## 常见问题
404
+ Q: 为什么 `Git` 提交总是报错?
405
+
406
+ A: 因为有提交信息验证,请遵循 [Commit 指南](./CONTRIBUTING.md)
407
+
408
+ Q: 如果只使用前端页面,在哪里改请求接口?
409
+
410
+ A: 根目录下 `.env` 文件中的 `VITE_GLOB_API_URL` 字段。
411
+
412
+ Q: 文件保存时全部爆红?
413
+
414
+ A: `vscode` 请安装项目推荐插件,或手动安装 `Eslint` 插件。
415
+
416
+ Q: 前端没有打字机效果?
417
+
418
+ A: 一种可能原因是经过 Nginx 反向代理,开启了 buffer,则 Nginx 会尝试从后端缓冲一定大小的数据再发送给浏览器。请尝试在反代参数后添加 `proxy_buffering off;`,然后重载 Nginx。其他 web server 配置同理。
419
+
420
+ ## 参与贡献
421
+
422
+ 贡献之前请先阅读 [贡献指南](./CONTRIBUTING.md)
423
+
424
+ 感谢所有做过贡献的人!
425
+
426
+ <a href="https://github.com/Chanzhaoyu/chatgpt-web/graphs/contributors">
427
+ <img src="https://contrib.rocks/image?repo=Chanzhaoyu/chatgpt-web" />
428
+ </a>
429
+
430
+ ## 赞助
431
+ 如果你觉得这个项目对你有帮助,请给我点个Star。并且情况允许的话��可以给我一点点支持,总之非常感谢支持~
432
+
433
+ <div style="display: flex; gap: 20px;">
434
+ <div style="text-align: center">
435
+ <img style="width: 200px" src="./docs/wechat.png" alt="微信" />
436
+ <p>WeChat Pay</p>
437
+ </div>
438
+ <div style="text-align: center">
439
+ <img style="width: 200px" src="./docs/alipay.png" alt="支付宝" />
440
+ <p>Alipay</p>
441
+ </div>
442
+ </div>
443
+
444
+ ## License
445
+ MIT © [Kerwin1202](./license)
docker-compose/docker-compose-mongodb.yml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3'
2
+
3
+ services:
4
+ mongo:
5
+ image: mongo
6
+ container_name: mongodb
7
+ restart: always
8
+ ports:
9
+ - '27017:27017'
10
+ volumes:
11
+ - ./mongodb:/data/db
12
+ environment:
13
+ MONGO_INITDB_ROOT_USERNAME: chatgpt
14
+ MONGO_INITDB_ROOT_PASSWORD: password
15
+ MONGO_INITDB_DATABASE: chatgpt
docker-compose/docker-compose.yml ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3'
2
+
3
+ services:
4
+ app:
5
+ image: kerwin1202/chatgpt-web # 总是使用latest,更新时重新pull该tag镜像即可
6
+ container_name: chatgptweb
7
+ restart: unless-stopped
8
+ ports:
9
+ - 3002:3002
10
+ depends_on:
11
+ - database
12
+ environment:
13
+ TZ: Asia/Shanghai
14
+ # 访问jwt加密参数,可选 不为空则允许登录 同时需要设置 MONGODB_URL
15
+ AUTH_SECRET_KEY:
16
+ # 每小时最大请求次数,可选,默认无限
17
+ MAX_REQUEST_PER_HOUR: 0
18
+ # 超时,单位毫秒,可选
19
+ TIMEOUT_MS: 600000
20
+ # Socks代理,可选,和 SOCKS_PROXY_PORT 一起时生效
21
+ SOCKS_PROXY_HOST:
22
+ # Socks代理端口,可选,和 SOCKS_PROXY_HOST 一起时生效
23
+ SOCKS_PROXY_PORT:
24
+ # Socks代理用户名,可选,和 SOCKS_PROXY_HOST & SOCKS_PROXY_PORT 一起时生效
25
+ SOCKS_PROXY_USERNAME:
26
+ # Socks代理密码,可选,和 SOCKS_PROXY_HOST & SOCKS_PROXY_PORT 一起时生效
27
+ SOCKS_PROXY_PASSWORD:
28
+ # 网站名称
29
+ SITE_TITLE: ChatGpt Web
30
+ # mongodb 的连接字符串
31
+ MONGODB_URL: 'mongodb://chatgpt:xxxx@database:27017'
32
+ # 网站是否开启注册
33
+ REGISTER_ENABLED: false
34
+ # 开启注册之后 网站注册允许的邮箱后缀 如果空 则允许任意后缀
35
+ REGISTER_MAILS: '@qq.com,@sina.com,@163.com'
36
+ # 开启注册之后 密码加密的盐
37
+ PASSWORD_MD5_SALT: anysalt
38
+ # 开启注册之后 超级管理邮箱
39
+ ROOT_USER: xxx@qq.com
40
+ # 开启注册之后 网站域名 不含 / 注册的时候发送验证邮箱使用
41
+ SITE_DOMAIN: http://127.0.0.1:1002
42
+ # 开启注册之后 发送验证邮箱配置
43
+ SMTP_HOST: smtp.exmail.qq.com
44
+ SMTP_PORT: 465
45
+ SMTP_TSL: true
46
+ SMTP_USERNAME: ${SMTP_USERNAME}
47
+ SMTP_PASSWORD: ${SMTP_PASSWORD}
48
+ # 是否开启敏感词审核, 因为响应结果是流式 所以暂时没审核
49
+ AUDIT_ENABLED: false
50
+ # https://ai.baidu.com/ai-doc/ANTIPORN/Vk3h6xaga
51
+ AUDIT_PROVIDER: baidu
52
+ AUDIT_API_KEY:
53
+ AUDIT_API_SECRET:
54
+ AUDIT_TEXT_LABEL:
55
+ links:
56
+ - database
57
+
58
+ database:
59
+ image: mongo
60
+ ports:
61
+ - '27017:27017'
62
+ expose:
63
+ - '27017'
64
+ volumes:
65
+ - mongodb:/data/db
66
+ environment:
67
+ MONGO_INITDB_ROOT_USERNAME: chatgpt
68
+ MONGO_INITDB_ROOT_PASSWORD: xxxx
69
+ MONGO_INITDB_DATABASE: chatgpt
70
+
71
+ mongo-gui:
72
+ container_name: mongo-gui
73
+ image: ugleiton/mongo-gui
74
+ restart: always
75
+ ports:
76
+ - '4321:4321'
77
+ environment:
78
+ - MONGO_URL=mongodb://chatgpt:xxxx@database:27017
79
+ links:
80
+ - database
81
+ depends_on:
82
+ - database
83
+
84
+ nginx:
85
+ image: nginx:alpine
86
+ container_name: chatgptweb-database
87
+ restart: unless-stopped
88
+ ports:
89
+ - '80:80'
90
+ expose:
91
+ - '80'
92
+ volumes:
93
+ - ./nginx/html:/usr/share/nginx/html
94
+ - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
95
+ links:
96
+ - app
97
+
98
+ volumes:
99
+ mongodb: {}
docker-compose/nginx/nginx.conf ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ server {
2
+ listen 80;
3
+ server_name localhost;
4
+ charset utf-8;
5
+ error_page 500 502 503 504 /50x.html;
6
+
7
+ # 防止爬虫抓取
8
+ 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"){
9
+ return 403;
10
+ }
11
+
12
+
13
+ location / {
14
+ root /usr/share/nginx/html;
15
+ try_files $uri /index.html;
16
+ }
17
+
18
+ location /api {
19
+ proxy_set_header X-Real-IP $remote_addr; #转发用户IP
20
+ proxy_pass http://app:3002;
21
+ }
22
+
23
+ proxy_set_header Host $host;
24
+ proxy_set_header X-Real-IP $remote_addr;
25
+ proxy_set_header REMOTE-HOST $remote_addr;
26
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
27
+ }
docker-compose/readme.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### docker-compose 部署教程
2
+ - 将打包好的前端文件放到 `nginx/html` 目录下
3
+ - ```shell
4
+ # 启动
5
+ docker-compose up -d
6
+ ```
7
+ - ```shell
8
+ # 查看运行状态
9
+ docker ps
10
+ ```
11
+ - ```shell
12
+ # 结束运行
13
+ docker-compose down
14
+ ```
docs/alipay.png ADDED
docs/basesettings.jpg ADDED
docs/c1-2.8.0.png ADDED
docs/c1-2.9.0.png ADDED
docs/c1.png ADDED
docs/c2-2.8.0.png ADDED
docs/c2-2.9.0.png ADDED
docs/c2.png ADDED
docs/docker.png ADDED
docs/key-manager-en.jpg ADDED
docs/key-manager.jpg ADDED
docs/login.jpg ADDED
docs/mailsettings.jpg ADDED
docs/prompt.jpg ADDED
docs/prompt_en.jpg ADDED
docs/sitesettings.jpg ADDED
docs/user-manager.jpg ADDED
docs/wechat.png ADDED
index.html ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-cmn-Hans">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
6
+ <meta content="yes" name="apple-mobile-web-app-capable"/>
7
+ <link rel="apple-touch-icon" href="/favicon.ico">
8
+ <meta name="viewport"
9
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" />
10
+ <title>${SITE_TITLE}</title>
11
+ </head>
12
+
13
+ <body class="dark:bg-black">
14
+ <div id="app">
15
+ <style>
16
+ .loading-wrap {
17
+ display: flex;
18
+ justify-content: center;
19
+ align-items: center;
20
+ height: 100vh;
21
+ }
22
+
23
+ .balls {
24
+ width: 4em;
25
+ display: flex;
26
+ flex-flow: row nowrap;
27
+ align-items: center;
28
+ justify-content: space-between;
29
+ }
30
+
31
+ .balls div {
32
+ width: 0.8em;
33
+ height: 0.8em;
34
+ border-radius: 50%;
35
+ background-color: #4b9e5f;
36
+ }
37
+
38
+ .balls div:nth-of-type(1) {
39
+ transform: translateX(-100%);
40
+ animation: left-swing 0.5s ease-in alternate infinite;
41
+ }
42
+
43
+ .balls div:nth-of-type(3) {
44
+ transform: translateX(-95%);
45
+ animation: right-swing 0.5s ease-out alternate infinite;
46
+ }
47
+
48
+ @keyframes left-swing {
49
+
50
+ 50%,
51
+ 100% {
52
+ transform: translateX(95%);
53
+ }
54
+ }
55
+
56
+ @keyframes right-swing {
57
+ 50% {
58
+ transform: translateX(-95%);
59
+ }
60
+
61
+ 100% {
62
+ transform: translateX(100%);
63
+ }
64
+ }
65
+
66
+ @media (prefers-color-scheme: dark) {
67
+ body {
68
+ background: #121212;
69
+ }
70
+ }
71
+ </style>
72
+ <div class="loading-wrap">
73
+ <div class="balls">
74
+ <div></div>
75
+ <div></div>
76
+ <div></div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ <script type="module" src="/src/main.ts"></script>
81
+ </body>
82
+
83
+ </html>
kubernetes/README.md ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ ## 增加一个Kubernetes的部署方式
2
+ ```
3
+ kubectl apply -f deploy.yaml
4
+ ```
5
+
6
+ ### 如果需要Ingress域名接入
7
+ ```
8
+ kubectl apply -f ingress.yaml
9
+ ```
kubernetes/deploy.yaml ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ apiVersion: apps/v1
2
+ kind: Deployment
3
+ metadata:
4
+ name: chatgpt-web
5
+ labels:
6
+ app: chatgpt-web
7
+ spec:
8
+ replicas: 1
9
+ selector:
10
+ matchLabels:
11
+ app: chatgpt-web
12
+ strategy:
13
+ type: RollingUpdate
14
+ template:
15
+ metadata:
16
+ labels:
17
+ app: chatgpt-web
18
+ spec:
19
+ containers:
20
+ - image: chenzhaoyu94/chatgpt-web
21
+ name: chatgpt-web
22
+ imagePullPolicy: Always
23
+ ports:
24
+ - containerPort: 3002
25
+ env:
26
+ - name: OPENAI_API_KEY
27
+ value: sk-xxx
28
+ - name: OPENAI_API_BASE_URL
29
+ value: 'https://api.openai.com'
30
+ - name: OPENAI_API_MODEL
31
+ value: ChatGPTAPI
32
+ - name: API_REVERSE_PROXY
33
+ value: https://ai.fakeopen.com/api/conversation
34
+ - name: AUTH_SECRET_KEY
35
+ value: '123456'
36
+ - name: TIMEOUT_MS
37
+ value: '600000'
38
+ - name: SOCKS_PROXY_HOST
39
+ value: ''
40
+ - name: SOCKS_PROXY_PORT
41
+ value: ''
42
+ - name: HTTPS_PROXY
43
+ value: ''
44
+ resources:
45
+ limits:
46
+ cpu: 500m
47
+ memory: 500Mi
48
+ requests:
49
+ cpu: 300m
50
+ memory: 300Mi
51
+ ---
52
+ apiVersion: v1
53
+ kind: Service
54
+ metadata:
55
+ labels:
56
+ app: chatgpt-web
57
+ name: chatgpt-web
58
+ spec:
59
+ ports:
60
+ - name: chatgpt-web
61
+ port: 3002
62
+ protocol: TCP
63
+ targetPort: 3002
64
+ selector:
65
+ app: chatgpt-web
66
+ type: ClusterIP
kubernetes/ingress.yaml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ apiVersion: networking.k8s.io/v1
2
+ kind: Ingress
3
+ metadata:
4
+ annotations:
5
+ kubernetes.io/ingress.class: nginx
6
+ nginx.ingress.kubernetes.io/proxy-connect-timeout: '5'
7
+ name: chatgpt-web
8
+ spec:
9
+ rules:
10
+ - host: chatgpt.example.com
11
+ http:
12
+ paths:
13
+ - backend:
14
+ service:
15
+ name: chatgpt-web
16
+ port:
17
+ number: 3002
18
+ path: /
19
+ pathType: ImplementationSpecific
20
+ tls:
21
+ - secretName: chatgpt-web-tls
license ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT Kerwin1202
2
+
3
+ Copyright (c) 2023 ChenZhaoYu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package.json ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "chatgpt-web",
3
+ "version": "2.13.3",
4
+ "private": false,
5
+ "description": "ChatGPT Web",
6
+ "author": "ChenZhaoYu <chenzhaoyu1994@gmail.com>",
7
+ "keywords": [
8
+ "chatgpt-web",
9
+ "chatgpt",
10
+ "chatbot",
11
+ "vue"
12
+ ],
13
+ "scripts": {
14
+ "dev": "vite",
15
+ "build": "run-p type-check build-only",
16
+ "preview": "vite preview",
17
+ "build-only": "vite build",
18
+ "type-check": "vue-tsc --noEmit",
19
+ "lint": "eslint .",
20
+ "lint:fix": "eslint . --fix",
21
+ "bootstrap": "pnpm install && pnpm run common:prepare",
22
+ "common:cleanup": "rimraf node_modules && rimraf pnpm-lock.yaml",
23
+ "common:prepare": "husky install"
24
+ },
25
+ "dependencies": {
26
+ "@traptitech/markdown-it-katex": "^3.6.0",
27
+ "@vueuse/core": "^9.13.0",
28
+ "chart.js": "^4.3.0",
29
+ "dayjs": "^1.11.7",
30
+ "highlight.js": "^11.7.0",
31
+ "html2canvas": "^1.4.1",
32
+ "jwt-decode": "^3.1.2",
33
+ "katex": "^0.16.4",
34
+ "markdown-it": "^13.0.1",
35
+ "naive-ui": "^2.34.3",
36
+ "pinia": "^2.0.33",
37
+ "vue": "^3.2.47",
38
+ "vue-chartjs": "^5.2.0",
39
+ "vue-i18n": "^9.2.2",
40
+ "vue-router": "^4.1.6"
41
+ },
42
+ "devDependencies": {
43
+ "@antfu/eslint-config": "^0.35.3",
44
+ "@commitlint/cli": "^17.4.4",
45
+ "@commitlint/config-conventional": "^17.4.4",
46
+ "@iconify/vue": "^4.1.0",
47
+ "@types/chart.js": "^2.9.37",
48
+ "@types/crypto-js": "^4.1.1",
49
+ "@types/katex": "^0.16.0",
50
+ "@types/markdown-it": "^12.2.3",
51
+ "@types/markdown-it-link-attributes": "^3.0.1",
52
+ "@types/node": "^18.14.6",
53
+ "@vitejs/plugin-vue": "^4.0.0",
54
+ "autoprefixer": "^10.4.13",
55
+ "axios": "^1.3.4",
56
+ "crypto-js": "^4.1.1",
57
+ "eslint": "^8.35.0",
58
+ "husky": "^8.0.3",
59
+ "less": "^4.1.3",
60
+ "lint-staged": "^13.1.2",
61
+ "markdown-it-link-attributes": "^4.0.1",
62
+ "npm-run-all": "^4.1.5",
63
+ "postcss": "^8.4.21",
64
+ "rimraf": "^4.2.0",
65
+ "tailwindcss": "^3.2.7",
66
+ "typescript": "~4.9.5",
67
+ "vite": "^4.2.0",
68
+ "vite-plugin-pwa": "^0.14.4",
69
+ "vue-tsc": "^1.2.0"
70
+ },
71
+ "lint-staged": {
72
+ "*.{ts,tsx,vue}": [
73
+ "pnpm lint:fix"
74
+ ]
75
+ }
76
+ }
pnpm-lock.yaml ADDED
The diff for this file is too large to render. See raw diff
 
postcss.config.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ }
public/favicon.ico ADDED
public/favicon.svg ADDED
public/pwa-192x192.png ADDED
public/pwa-512x512.png ADDED
replace-title.sh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #!/bin/sh
2
+
3
+ SITE_TITLE=${SITE_TITLE:-ChatGPT Web}
4
+
5
+ sed -i -E "s/<title>([^<]*)<\/title>/<title>${SITE_TITLE}<\/title>/g" /app/public/index.html
service/.env.example ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # OpenAI API Key - https://platform.openai.com/overview
2
+ OPENAI_API_KEY=
3
+
4
+ # change this to an `accessToken` extracted from the ChatGPT site's `https://chat.openai.com/api/auth/session` response
5
+ OPENAI_ACCESS_TOKEN=
6
+
7
+ # OpenAI API Base URL - https://api.openai.com
8
+ OPENAI_API_BASE_URL=
9
+
10
+ # ChatGPTAPI 或者 ChatGPTUnofficialProxyAPI
11
+ OPENAI_API_MODEL:
12
+
13
+ # set `true` to disable OpenAI API debug log
14
+ OPENAI_API_DISABLE_DEBUG=
15
+
16
+ # Reverse Proxy - Available on accessToken
17
+ # Default: https://ai.fakeopen.com/api/conversation
18
+ # More: https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy
19
+ API_REVERSE_PROXY=
20
+
21
+ # timeout
22
+ TIMEOUT_MS=100000
23
+
24
+ # Rate Limit
25
+ MAX_REQUEST_PER_HOUR=
26
+
27
+ # Auth Rate Limit
28
+ AUTH_MAX_REQUEST_PER_MINUTE=5
29
+
30
+ # Socks Proxy Host
31
+ SOCKS_PROXY_HOST=
32
+
33
+ # Socks Proxy Port
34
+ SOCKS_PROXY_PORT=
35
+
36
+ # Socks Proxy Username
37
+ SOCKS_PROXY_USERNAME=
38
+
39
+ # Socks Proxy Password
40
+ SOCKS_PROXY_PASSWORD=
41
+
42
+ # HTTPS PROXY
43
+ HTTPS_PROXY=
44
+
45
+ # Title for site
46
+ SITE_TITLE="ChatGpt Web"
47
+
48
+ # Databse connection string
49
+ # MONGODB_URL=mongodb://chatgpt:xxxx@yourip:port
50
+ MONGODB_URL=mongodb://chatgpt:xxxx@database:27017
51
+
52
+ # Secret key for jwt
53
+ # If not empty, will need login
54
+ AUTH_SECRET_KEY=
55
+
56
+ # ----- Only valid after setting AUTH_SECRET_KEY begin ----
57
+
58
+ # Allow anyone register
59
+ REGISTER_ENABLED=false
60
+
61
+ # Enable register application review
62
+ REGISTER_REVIEW=false
63
+
64
+ # The site domain, Only for registration account verification
65
+ # without end /
66
+ SITE_DOMAIN=http://127.0.0.1:1002
67
+
68
+ # Allowed Email Providers, If it is empty, any mailbox is allowed
69
+ # REGISTER_MAILS=@qq.com,@sina.com,@163.com
70
+ REGISTER_MAILS=@qq.com,@sina.com,@163.com
71
+
72
+ # The roon user only email
73
+ ROOT_USER=
74
+
75
+ # Password salt
76
+ PASSWORD_MD5_SALT=anysalt
77
+
78
+ # User register email verify
79
+ SMTP_HOST=smtp.exmail.qq.com
80
+ SMTP_PORT=465
81
+ SMTP_TSL=true
82
+ SMTP_USERNAME=yourname@example.com
83
+ SMTP_PASSWORD=yourpassword
84
+
85
+ # ----- Only valid after setting AUTH_SECRET_KEY end ----
service/.eslintrc.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "root": true,
3
+ "ignorePatterns": ["build"],
4
+ "extends": ["@antfu"]
5
+ }
service/.gitignore ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ .DS_Store
12
+ dist
13
+ dist-ssr
14
+ coverage
15
+ *.local
16
+
17
+ /cypress/videos/
18
+ /cypress/screenshots/
19
+
20
+ # Editor directories and files
21
+ .vscode/*
22
+ !.vscode/settings.json
23
+ !.vscode/extensions.json
24
+ .idea
25
+ *.suo
26
+ *.ntvs*
27
+ *.njsproj
28
+ *.sln
29
+ *.sw?
30
+
31
+ build
service/.npmrc ADDED
@@ -0,0 +1 @@
 
 
1
+ enable-pre-post-scripts=true
service/.vscode/extensions.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "recommendations": ["dbaeumer.vscode-eslint"]
3
+ }
service/.vscode/settings.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "prettier.enable": false,
3
+ "editor.formatOnSave": false,
4
+ "editor.codeActionsOnSave": {
5
+ "source.fixAll.eslint": true
6
+ },
7
+ "eslint.validate": [
8
+ "javascript",
9
+ "typescript",
10
+ "json",
11
+ "jsonc",
12
+ "json5",
13
+ "yaml"
14
+ ],
15
+ "cSpell.words": [
16
+ "antfu",
17
+ "chatgpt",
18
+ "esno",
19
+ "GPTAPI",
20
+ "OPENAI"
21
+ ]
22
+ }
service/package.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "chatgpt-web-service",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "description": "ChatGPT Web Service",
6
+ "author": "ChenZhaoYu <chenzhaoyu1994@gmail.com>",
7
+ "keywords": [
8
+ "chatgpt-web",
9
+ "chatgpt",
10
+ "chatbot",
11
+ "express"
12
+ ],
13
+ "engines": {
14
+ "node": "^16 || ^18 || ^19"
15
+ },
16
+ "scripts": {
17
+ "start": "esno ./src/index.ts",
18
+ "dev": "esno watch ./src/index.ts",
19
+ "prod": "esno ./build/index.js",
20
+ "build": "pnpm clean && tsup",
21
+ "clean": "rimraf build",
22
+ "lint": "eslint .",
23
+ "lint:fix": "eslint . --fix",
24
+ "common:cleanup": "rimraf node_modules && rimraf pnpm-lock.yaml"
25
+ },
26
+ "dependencies": {
27
+ "axios": "^1.3.4",
28
+ "chatgpt": "^5.2.4",
29
+ "dayjs": "^1.11.7",
30
+ "dotenv": "^16.0.3",
31
+ "esno": "^0.16.3",
32
+ "express": "^4.18.2",
33
+ "express-rate-limit": "^6.7.0",
34
+ "https-proxy-agent": "^5.0.1",
35
+ "isomorphic-fetch": "^3.0.0",
36
+ "jwt-decode": "^3.1.2",
37
+ "mongodb": "^5.1.0",
38
+ "node-fetch": "^3.3.0",
39
+ "nodemailer": "^6.9.1",
40
+ "request-ip": "^3.3.0",
41
+ "socks-proxy-agent": "^7.0.0"
42
+ },
43
+ "devDependencies": {
44
+ "@antfu/eslint-config": "^0.35.3",
45
+ "@types/express": "^4.17.17",
46
+ "@types/mongodb": "^4.0.7",
47
+ "@types/node": "^18.14.6",
48
+ "eslint": "^8.35.0",
49
+ "jsonwebtoken": "^9.0.0",
50
+ "rimraf": "^4.3.0",
51
+ "tsup": "^6.6.3",
52
+ "typescript": "^4.9.5"
53
+ }
54
+ }
service/pnpm-lock.yaml ADDED
The diff for this file is too large to render. See raw diff
 
service/src/chatgpt/index.ts ADDED
@@ -0,0 +1,387 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as dotenv from 'dotenv'
2
+ import 'isomorphic-fetch'
3
+ import type { ChatGPTAPIOptions, ChatMessage, SendMessageOptions } from 'chatgpt'
4
+ import { ChatGPTAPI, ChatGPTUnofficialProxyAPI } from 'chatgpt'
5
+ import { SocksProxyAgent } from 'socks-proxy-agent'
6
+ import httpsProxyAgent from 'https-proxy-agent'
7
+ import fetch from 'node-fetch'
8
+ import type { AuditConfig, CHATMODEL, KeyConfig, UserInfo } from 'src/storage/model'
9
+ import jwt_decode from 'jwt-decode'
10
+ import dayjs from 'dayjs'
11
+ import type { TextAuditService } from '../utils/textAudit'
12
+ import { textAuditServices } from '../utils/textAudit'
13
+ import { getCacheApiKeys, getCacheConfig, getOriginConfig } from '../storage/config'
14
+ import { sendResponse } from '../utils'
15
+ import { hasAnyRole, isNotEmptyString } from '../utils/is'
16
+ import type { ChatContext, ChatGPTUnofficialProxyAPIOptions, JWT, ModelConfig } from '../types'
17
+ import { getChatByMessageId, updateRoomAccountId } from '../storage/mongo'
18
+ import type { RequestOptions } from './types'
19
+
20
+ const { HttpsProxyAgent } = httpsProxyAgent
21
+
22
+ dotenv.config()
23
+
24
+ const ErrorCodeMessage: Record<string, string> = {
25
+ 401: '[OpenAI] 提供错误的API密钥 | Incorrect API key provided',
26
+ 403: '[OpenAI] 服务器拒绝访问,请稍后再试 | Server refused to access, please try again later',
27
+ 502: '[OpenAI] 错误的网关 | Bad Gateway',
28
+ 503: '[OpenAI] 服务器繁忙,请稍后再试 | Server is busy, please try again later',
29
+ 504: '[OpenAI] 网关超时 | Gateway Time-out',
30
+ 500: '[OpenAI] 服务器繁忙,请稍后再试 | Internal Server Error',
31
+ }
32
+
33
+ let auditService: TextAuditService
34
+ const _lockedKeys: { key: string; lockedTime: number }[] = []
35
+
36
+ export async function initApi(key: KeyConfig, chatModel: CHATMODEL) {
37
+ // More Info: https://github.com/transitive-bullshit/chatgpt-api
38
+
39
+ const config = await getCacheConfig()
40
+ const model = chatModel as string
41
+
42
+ if (key.keyModel === 'ChatGPTAPI') {
43
+ const OPENAI_API_BASE_URL = config.apiBaseUrl
44
+
45
+ const options: ChatGPTAPIOptions = {
46
+ apiKey: key.key,
47
+ completionParams: { model },
48
+ debug: !config.apiDisableDebug,
49
+ messageStore: undefined,
50
+ getMessageById,
51
+ }
52
+ // increase max token limit if use gpt-4
53
+ if (model.toLowerCase().includes('gpt-4')) {
54
+ // if use 32k model
55
+ if (model.toLowerCase().includes('32k')) {
56
+ options.maxModelTokens = 32768
57
+ options.maxResponseTokens = 8192
58
+ }
59
+ else {
60
+ options.maxModelTokens = 8192
61
+ options.maxResponseTokens = 2048
62
+ }
63
+ }
64
+
65
+ if (isNotEmptyString(OPENAI_API_BASE_URL))
66
+ options.apiBaseUrl = `${OPENAI_API_BASE_URL}/v1`
67
+
68
+ await setupProxy(options)
69
+
70
+ return new ChatGPTAPI({ ...options })
71
+ }
72
+ else {
73
+ const options: ChatGPTUnofficialProxyAPIOptions = {
74
+ accessToken: key.key,
75
+ apiReverseProxyUrl: isNotEmptyString(config.reverseProxy) ? config.reverseProxy : 'https://ai.fakeopen.com/api/conversation',
76
+ model,
77
+ debug: !config.apiDisableDebug,
78
+ }
79
+
80
+ await setupProxy(options)
81
+
82
+ return new ChatGPTUnofficialProxyAPI({ ...options })
83
+ }
84
+ }
85
+ const processThreads: { userId: string; abort: AbortController; messageId: string }[] = []
86
+ async function chatReplyProcess(options: RequestOptions) {
87
+ const model = options.user.config.chatModel
88
+ const key = await getRandomApiKey(options.user, options.user.config.chatModel, options.room.accountId)
89
+ const userId = options.user._id.toString()
90
+ const messageId = options.messageId
91
+ if (key == null || key === undefined)
92
+ throw new Error('没有可用的配置。请再试一次 | No available configuration. Please try again.')
93
+
94
+ if (key.keyModel === 'ChatGPTUnofficialProxyAPI') {
95
+ if (!options.room.accountId)
96
+ updateRoomAccountId(userId, options.room.roomId, getAccountId(key.key))
97
+
98
+ if (options.lastContext && ((options.lastContext.conversationId && !options.lastContext.parentMessageId)
99
+ || (!options.lastContext.conversationId && options.lastContext.parentMessageId)))
100
+ throw new Error('无法在一个房间同时使用 AccessToken 以及 Api,请联系管理员,或新开聊天室进行对话 | Unable to use AccessToken and Api at the same time in the same room, please contact the administrator or open a new chat room for conversation')
101
+ }
102
+
103
+ const { message, lastContext, process, systemMessage, temperature, top_p } = options
104
+
105
+ try {
106
+ const timeoutMs = (await getCacheConfig()).timeoutMs
107
+ let options: SendMessageOptions = { timeoutMs }
108
+
109
+ if (key.keyModel === 'ChatGPTAPI') {
110
+ if (isNotEmptyString(systemMessage))
111
+ options.systemMessage = systemMessage
112
+ options.completionParams = { model, temperature, top_p }
113
+ }
114
+
115
+ if (lastContext != null) {
116
+ if (key.keyModel === 'ChatGPTAPI')
117
+ options.parentMessageId = lastContext.parentMessageId
118
+ else
119
+ options = { ...lastContext }
120
+ }
121
+ const api = await initApi(key, model)
122
+
123
+ const abort = new AbortController()
124
+ options.abortSignal = abort.signal
125
+ processThreads.push({ userId, abort, messageId })
126
+ const response = await api.sendMessage(message, {
127
+ ...options,
128
+ onProgress: (partialResponse) => {
129
+ process?.(partialResponse)
130
+ },
131
+ })
132
+
133
+ return sendResponse({ type: 'Success', data: response })
134
+ }
135
+ catch (error: any) {
136
+ const code = error.statusCode
137
+ if (code === 429 && (error.message.includes('Too Many Requests') || error.message.includes('Rate limit'))) {
138
+ // access token Only one message at a time
139
+ if (options.tryCount++ < 3) {
140
+ _lockedKeys.push({ key: key.key, lockedTime: Date.now() })
141
+ await new Promise(resolve => setTimeout(resolve, 2000))
142
+ return await chatReplyProcess(options)
143
+ }
144
+ }
145
+ global.console.error(error)
146
+ if (Reflect.has(ErrorCodeMessage, code))
147
+ return sendResponse({ type: 'Fail', message: ErrorCodeMessage[code] })
148
+ return sendResponse({ type: 'Fail', message: error.message ?? 'Please check the back-end console' })
149
+ }
150
+ finally {
151
+ const index = processThreads.findIndex(d => d.userId === userId)
152
+ if (index > -1)
153
+ processThreads.splice(index, 1)
154
+ }
155
+ }
156
+
157
+ export function abortChatProcess(userId: string) {
158
+ const index = processThreads.findIndex(d => d.userId === userId)
159
+ if (index <= -1)
160
+ return
161
+ const messageId = processThreads[index].messageId
162
+ processThreads[index].abort.abort()
163
+ processThreads.splice(index, 1)
164
+ return messageId
165
+ }
166
+
167
+ export function initAuditService(audit: AuditConfig) {
168
+ if (!audit || !audit.options || !audit.options.apiKey || !audit.options.apiSecret)
169
+ return
170
+ const Service = textAuditServices[audit.provider]
171
+ auditService = new Service(audit.options)
172
+ }
173
+
174
+ async function containsSensitiveWords(audit: AuditConfig, text: string): Promise<boolean> {
175
+ if (audit.customizeEnabled && isNotEmptyString(audit.sensitiveWords)) {
176
+ const textLower = text.toLowerCase()
177
+ const notSafe = audit.sensitiveWords.split('\n').filter(d => textLower.includes(d.trim().toLowerCase())).length > 0
178
+ if (notSafe)
179
+ return true
180
+ }
181
+ if (audit.enabled) {
182
+ if (!auditService)
183
+ initAuditService(audit)
184
+ return await auditService.containsSensitiveWords(text)
185
+ }
186
+ return false
187
+ }
188
+
189
+ async function fetchAccessTokenExpiredTime() {
190
+ const config = await getCacheConfig()
191
+ const jwt = jwt_decode(config.accessToken) as JWT
192
+ if (jwt.exp)
193
+ return dayjs.unix(jwt.exp).format('YYYY-MM-DD HH:mm:ss')
194
+ return '-'
195
+ }
196
+
197
+ let cachedBalance: number | undefined
198
+ let cacheExpiration = 0
199
+
200
+ async function fetchBalance() {
201
+ const now = new Date().getTime()
202
+ if (cachedBalance && cacheExpiration > now)
203
+ return Promise.resolve(cachedBalance.toFixed(3))
204
+
205
+ // 计算起始日期和结束日期
206
+ const startDate = new Date(now - 90 * 24 * 60 * 60 * 1000)
207
+ const endDate = new Date(now + 24 * 60 * 60 * 1000)
208
+
209
+ const config = await getCacheConfig()
210
+ const OPENAI_API_KEY = config.apiKey
211
+ const OPENAI_API_BASE_URL = config.apiBaseUrl
212
+
213
+ if (!isNotEmptyString(OPENAI_API_KEY))
214
+ return Promise.resolve('-')
215
+
216
+ const API_BASE_URL = isNotEmptyString(OPENAI_API_BASE_URL)
217
+ ? OPENAI_API_BASE_URL
218
+ : 'https://api.openai.com'
219
+
220
+ // 查是否订阅
221
+ const urlSubscription = `${API_BASE_URL}/v1/dashboard/billing/subscription`
222
+ // 查普通账单
223
+ // const urlBalance = `${API_BASE_URL}/dashboard/billing/credit_grants`
224
+ // 查使用量
225
+ const urlUsage = `${API_BASE_URL}/v1/dashboard/billing/usage?start_date=${formatDate(startDate)}&end_date=${formatDate(endDate)}`
226
+
227
+ const headers = {
228
+ 'Authorization': `Bearer ${OPENAI_API_KEY}`,
229
+ 'Content-Type': 'application/json',
230
+ }
231
+ let socksAgent
232
+ let httpsAgent
233
+ if (isNotEmptyString(config.socksProxy)) {
234
+ socksAgent = new SocksProxyAgent({
235
+ hostname: config.socksProxy.split(':')[0],
236
+ port: parseInt(config.socksProxy.split(':')[1]),
237
+ userId: isNotEmptyString(config.socksAuth) ? config.socksAuth.split(':')[0] : undefined,
238
+ password: isNotEmptyString(config.socksAuth) ? config.socksAuth.split(':')[1] : undefined,
239
+ })
240
+ }
241
+ else if (isNotEmptyString(config.httpsProxy)) {
242
+ httpsAgent = new HttpsProxyAgent(config.httpsProxy)
243
+ }
244
+
245
+ try {
246
+ // 获取API限额
247
+ let response = await fetch(urlSubscription, { agent: socksAgent === undefined ? httpsAgent : socksAgent, headers })
248
+ if (!response.ok) {
249
+ console.error('您的账户已被封禁,请登录OpenAI进行查看。')
250
+ return
251
+ }
252
+ const subscriptionData = await response.json()
253
+ const totalAmount = subscriptionData.hard_limit_usd
254
+
255
+ // 获取已使用量
256
+ response = await fetch(urlUsage, { agent: socksAgent === undefined ? httpsAgent : socksAgent, headers })
257
+ const usageData = await response.json()
258
+ const totalUsage = usageData.total_usage / 100
259
+
260
+ // 计算剩余额度
261
+ cachedBalance = totalAmount - totalUsage
262
+ cacheExpiration = now + 60 * 60 * 1000
263
+
264
+ return Promise.resolve(cachedBalance.toFixed(3))
265
+ }
266
+ catch (error) {
267
+ global.console.error(error)
268
+ return Promise.resolve('-')
269
+ }
270
+ }
271
+
272
+ function formatDate(date) {
273
+ const year = date.getFullYear()
274
+ const month = (date.getMonth() + 1).toString().padStart(2, '0')
275
+ const day = date.getDate().toString().padStart(2, '0')
276
+
277
+ return `${year}-${month}-${day}`
278
+ }
279
+
280
+ async function chatConfig() {
281
+ const config = await getOriginConfig() as ModelConfig
282
+ // if (config.apiModel === 'ChatGPTAPI')
283
+ // config.balance = await fetchBalance()
284
+ // else
285
+ // config.accessTokenExpiredTime = await fetchAccessTokenExpiredTime()
286
+ return sendResponse<ModelConfig>({
287
+ type: 'Success',
288
+ data: config,
289
+ })
290
+ }
291
+
292
+ async function setupProxy(options: ChatGPTAPIOptions | ChatGPTUnofficialProxyAPIOptions) {
293
+ const config = await getCacheConfig()
294
+ if (isNotEmptyString(config.socksProxy)) {
295
+ const agent = new SocksProxyAgent({
296
+ hostname: config.socksProxy.split(':')[0],
297
+ port: parseInt(config.socksProxy.split(':')[1]),
298
+ userId: isNotEmptyString(config.socksAuth) ? config.socksAuth.split(':')[0] : undefined,
299
+ password: isNotEmptyString(config.socksAuth) ? config.socksAuth.split(':')[1] : undefined,
300
+
301
+ })
302
+ options.fetch = (url, options) => {
303
+ return fetch(url, { agent, ...options })
304
+ }
305
+ }
306
+ else {
307
+ if (isNotEmptyString(config.httpsProxy)) {
308
+ const httpsProxy = config.httpsProxy
309
+ if (httpsProxy) {
310
+ const agent = new HttpsProxyAgent(httpsProxy)
311
+ options.fetch = (url, options) => {
312
+ return fetch(url, { agent, ...options })
313
+ }
314
+ }
315
+ }
316
+ }
317
+ }
318
+
319
+ async function getMessageById(id: string): Promise<ChatMessage | undefined> {
320
+ const isPrompt = id.startsWith('prompt_')
321
+ const chatInfo = await getChatByMessageId(isPrompt ? id.substring(7) : id)
322
+
323
+ if (chatInfo) {
324
+ if (isPrompt) { // prompt
325
+ return {
326
+ id,
327
+ conversationId: chatInfo.options.conversationId,
328
+ parentMessageId: chatInfo.options.parentMessageId,
329
+ role: 'user',
330
+ text: chatInfo.prompt,
331
+ }
332
+ }
333
+ else {
334
+ return { // completion
335
+ id,
336
+ conversationId: chatInfo.options.conversationId,
337
+ parentMessageId: `prompt_${id}`, // parent message is the prompt
338
+ role: 'assistant',
339
+ text: chatInfo.response,
340
+ }
341
+ }
342
+ }
343
+ else { return undefined }
344
+ }
345
+
346
+ async function randomKeyConfig(keys: KeyConfig[]): Promise<KeyConfig | null> {
347
+ if (keys.length <= 0)
348
+ return null
349
+ // cleanup old locked keys
350
+ _lockedKeys.filter(d => d.lockedTime <= Date.now() - 1000 * 20).forEach(d => _lockedKeys.splice(_lockedKeys.indexOf(d), 1))
351
+
352
+ let unsedKeys = keys.filter(d => _lockedKeys.filter(l => d.key === l.key).length <= 0)
353
+ const start = Date.now()
354
+ while (unsedKeys.length <= 0) {
355
+ if (Date.now() - start > 3000)
356
+ break
357
+ await new Promise(resolve => setTimeout(resolve, 1000))
358
+ unsedKeys = keys.filter(d => _lockedKeys.filter(l => d.key === l.key).length <= 0)
359
+ }
360
+ if (unsedKeys.length <= 0)
361
+ return null
362
+ const thisKey = unsedKeys[Math.floor(Math.random() * unsedKeys.length)]
363
+ return thisKey
364
+ }
365
+
366
+ async function getRandomApiKey(user: UserInfo, chatModel: CHATMODEL, accountId?: string): Promise<KeyConfig | undefined> {
367
+ let keys = (await getCacheApiKeys()).filter(d => hasAnyRole(d.userRoles, user.roles))
368
+ .filter(d => d.chatModels.includes(chatModel))
369
+ if (accountId)
370
+ keys = keys.filter(d => d.keyModel === 'ChatGPTUnofficialProxyAPI' && getAccountId(d.key) === accountId)
371
+
372
+ return randomKeyConfig(keys)
373
+ }
374
+
375
+ function getAccountId(accessToken: string): string {
376
+ try {
377
+ const jwt = jwt_decode(accessToken) as JWT
378
+ return jwt['https://api.openai.com/auth'].user_id
379
+ }
380
+ catch (error) {
381
+ return ''
382
+ }
383
+ }
384
+
385
+ export type { ChatContext, ChatMessage }
386
+
387
+ export { chatReplyProcess, chatConfig, containsSensitiveWords }