dvc890 commited on
Commit
a7b502d
·
0 Parent(s):

Duplicate from dvc890/chatup

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
.DS_Store ADDED
Binary file (6.15 kB). View file
 
.gitattributes ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tflite filter=lfs diff=lfs merge=lfs -text
29
+ *.tgz filter=lfs diff=lfs merge=lfs -text
30
+ *.wasm filter=lfs diff=lfs merge=lfs -text
31
+ *.xz filter=lfs diff=lfs merge=lfs -text
32
+ *.zip filter=lfs diff=lfs merge=lfs -text
33
+ *.zst filter=lfs diff=lfs merge=lfs -text
34
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
CHANGELOG.md ADDED
@@ -0,0 +1,548 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## v2.10.8
2
+
3
+ `2023-03-23`
4
+
5
+ 如遇问题,请删除 `node_modules` 重新安装依赖。
6
+
7
+ ## Feature
8
+ - 显示回复消息原文的选项 [[yilozt](https://github.com/Chanzhaoyu/chatgpt-web/pull/672)]
9
+ - 添加单 `IP` 每小时请求限制。环境变量: `MAX_REQUEST_PER_HOUR` [[zhuxindong ](https://github.com/Chanzhaoyu/chatgpt-web/pull/718)]
10
+ - 前端添加角色设定,仅 `API` 方式可见 [[quzard](https://github.com/Chanzhaoyu/chatgpt-web/pull/768)]
11
+ - `OPENAI_API_MODEL` 变量现在对 `ChatGPTUnofficialProxyAPI` 也生效,注意:`Token` 和 `API` 的模型命名不一致,不能直接填入 `gpt-3.5` 或者 `gpt-4` [[hncboy](https://github.com/Chanzhaoyu/chatgpt-web/pull/632)]
12
+ - 添加繁体中文 `Prompts` [[PeterDaveHello](https://github.com/Chanzhaoyu/chatgpt-web/pull/796)]
13
+
14
+ ## Enhancement
15
+ - 重置回答时滚动定位至该回答 [[shunyue1320](https://github.com/Chanzhaoyu/chatgpt-web/pull/781)]
16
+ - 当 `API` 是 `gpt-4` 时增加可用的 `Max Tokens` [[simonwu53](https://github.com/Chanzhaoyu/chatgpt-web/pull/729)]
17
+ - 判断和忽略回复字符 [[liut](https://github.com/Chanzhaoyu/chatgpt-web/pull/474)]
18
+ - 切换会话时,自动聚焦输入框 [[JS-an](https://github.com/Chanzhaoyu/chatgpt-web/pull/735)]
19
+ - 渲染的链接新窗口打开
20
+ - 查询余额可选 `API_BASE_URL` 代理地址
21
+ - `config` 接口添加验证防止被无限制调用
22
+ - `PWA` 默认不开启,现在需手动修改 `.env` 文件 `VITE_GLOB_APP_PWA` 变量
23
+ - 当网络连接时,刷新页面,`500` 错误页自动跳转到主页
24
+
25
+ ## BugFix
26
+ - `scrollToBottom` 调回 `scrollToBottomIfAtBottom` [[shunyue1320](https://github.com/Chanzhaoyu/chatgpt-web/pull/771)]
27
+ - 重置异常的 `loading` 会话
28
+
29
+ ## Common
30
+ - 创建 `start.cmd` 在 `windows` 下也可以运行 [vulgatecnn](https://github.com/Chanzhaoyu/chatgpt-web/pull/656)]
31
+ - 添加 `visual-studio-code` 中调试配置 [[ChandlerVer5](https://github.com/Chanzhaoyu/chatgpt-web/pull/296)]
32
+ - 修复文档中 `docker` 端口为本地 [[kilvn](https://github.com/Chanzhaoyu/chatgpt-web/pull/802)]
33
+ ## Other
34
+ - 依赖更新
35
+
36
+
37
+ ## v2.10.7
38
+
39
+ `2023-03-17`
40
+
41
+ ## BugFix
42
+ - 回退 `chatgpt` 版本,原因:导致 `OPENAI_API_BASE_URL` 代理失效
43
+ - 修复缺省状态的 `usingContext` 默认值
44
+
45
+ ## v2.10.6
46
+
47
+ `2023-03-17`
48
+
49
+ ## Feature
50
+ - 显示 `API` 余额 [[pzcn](https://github.com/Chanzhaoyu/chatgpt-web/pull/582)]
51
+
52
+ ## Enhancement
53
+ - 美化滚动条样式和 `UI` 保持一致 [[haydenull](https://github.com/Chanzhaoyu/chatgpt-web/pull/617)]
54
+ - 优化移动端 `Prompt` 样式 [[CornerSkyless](https://github.com/Chanzhaoyu/chatgpt-web/pull/608)]
55
+ - 上下文开关改为全局开关,现在记录在本地缓存中
56
+ - 配置信息按接口类型显示
57
+
58
+ ## Perf
59
+ - 优化函数方法 [[kirklin](https://github.com/Chanzhaoyu/chatgpt-web/pull/583)]
60
+ - 字符错误 [[pdsuwwz](https://github.com/Chanzhaoyu/chatgpt-web/pull/585)]
61
+ - 文档描述错误 [[lizhongyuan3](https://github.com/Chanzhaoyu/chatgpt-web/pull/636)]
62
+
63
+ ## BugFix
64
+ - 修复 `Prompt` 导入、导出兼容性错误
65
+ - 修复 `highlight.js` 控制台兼容性警告
66
+
67
+ ## Other
68
+ - 依赖更新
69
+
70
+ ## v2.10.5
71
+
72
+ `2023-03-13`
73
+
74
+ 更新依赖,`access_token` 默认代理为 [acheong08](https://github.com/acheong08) 的 `https://bypass.duti.tech/api/conversation`
75
+
76
+ ## Feature
77
+ - `Prompt` 商店在线导入可以导入两种 `recommend.json`里提到的模板 [simonwu53](https://github.com/Chanzhaoyu/chatgpt-web/pull/521)
78
+ - 支持 `HTTPS_PROXY` [whatwewant](https://github.com/Chanzhaoyu/chatgpt-web/pull/308)
79
+ - `Prompt` 添加查询筛选
80
+
81
+ ## Enhancement
82
+ - 调整输入框最大行数 [yi-ge](https://github.com/Chanzhaoyu/chatgpt-web/pull/502)
83
+ - 优化 `docker` 打包 [whatwewant](https://github.com/Chanzhaoyu/chatgpt-web/pull/520)
84
+ - `Prompt` 添加翻译和优化布局
85
+ - 「繁体中文」补全和审阅 [PeterDaveHello](https://github.com/Chanzhaoyu/chatgpt-web/pull/542)
86
+ - 语言选择调整为下路框形式
87
+ - 权限输入框类型调整为密码形式
88
+
89
+ ## BugFix
90
+ - `JSON` 导入检查 [Nothing1024](https://github.com/Chanzhaoyu/chatgpt-web/pull/523)
91
+ - 修复 `AUTH_SECRET_KEY` 模式下跨域异常并添加对 `node.js 19` 版本的支持 [yi-ge](https://github.com/Chanzhaoyu/chatgpt-web/pull/499)
92
+ - 确定清空上下文时不应该重置会话标题
93
+
94
+ ## Other
95
+ - 调整文档
96
+ - 更新依赖
97
+
98
+ ## v2.10.4
99
+
100
+ `2023-03-11`
101
+
102
+ ## Feature
103
+ - 感谢 [Nothing1024](https://github.com/Chanzhaoyu/chatgpt-web/pull/268) 添加 `Prompt` 模板和 `Prompt` 商店支持
104
+
105
+ ## Enhancement
106
+ - 设置添加关闭按钮[#495]
107
+
108
+ ## Demo
109
+
110
+ ![Prompt](https://camo.githubusercontent.com/6a51af751eb29238cb7ef4f8fbd89f63db837562f97f33273095424e62dc9194/68747470733a2f2f73312e6c6f63696d672e636f6d2f323032332f30332f30342f333036326665633163613562632e676966)
111
+
112
+ ## v2.10.3
113
+
114
+ `2023-03-10`
115
+
116
+ > 声明:除 `ChatGPTUnofficialProxyAPI` 使用的非官方代理外,本项目代码包括上游引用包均开源在 `GitHub`,如果你觉得本项目有监控后门或有问题导致你的账号、API被��,那我很抱歉。我可能`BUG`写的多,但我不缺德。此次主要为前端界面调整,周末愉快。
117
+
118
+ ## Feature
119
+ - 支持长回复 [[yi-ge](https://github.com/Chanzhaoyu/chatgpt-web/pull/450)][[详情](https://github.com/Chanzhaoyu/chatgpt-web/pull/450)]
120
+ - 支持 `PWA` [[chenxch](https://github.com/Chanzhaoyu/chatgpt-web/pull/452)]
121
+
122
+ ## Enhancement
123
+ - 调整移动端按钮和优化布局
124
+ - 调整 `iOS` 上安全距离
125
+ - 简化 `docker-compose` 部署 [[cloudGrin](https://github.com/Chanzhaoyu/chatgpt-web/pull/466)]
126
+
127
+ ## BugFix
128
+ - 修复清空会话侧边栏标题不会重置的问题 [[RyanXinOne](https://github.com/Chanzhaoyu/chatgpt-web/pull/453)]
129
+ - 修复设置文字过长时导致的设置按钮消失的问题
130
+
131
+ ## Other
132
+ - 更新依赖
133
+
134
+ ## v2.10.2
135
+
136
+ `2023-03-09`
137
+
138
+ 衔接 `2.10.1` 版本[详情](https://github.com/Chanzhaoyu/chatgpt-web/releases/tag/v2.10.1)
139
+
140
+ ## Enhancement
141
+ - 移动端下输入框获得焦点时左侧按钮隐藏
142
+
143
+ ## BugFix
144
+ - 修复 `2.10.1` 中添加 `OPENAI_API_MODEL` 变量的判断错误,会导致默认模型指定失效,抱歉
145
+ - 回退 `2.10.1` 中前端变量影响 `Docker` 打包
146
+
147
+ ## v2.10.1
148
+
149
+ `2023-03-09`
150
+
151
+ 注意:删除了 `.env` 文件改用 `.env.example` 代替,如果是手动部署的同学现在需要手动创建 `.env` 文件并从 `.env.example` 中复制需要的变量,并且 `.env` 文件现在会在 `Git` 提交中被忽略,原因如下:
152
+
153
+ - 在项目中添加 `.env` 从一开始就是个错误的示范
154
+ - 如果是 `Fork` 项目进行修改测试总是会被 `Git` 修改提示给打扰
155
+ - 感谢 [yi-ge](https://github.com/Chanzhaoyu/chatgpt-web/pull/395) 的提醒和修改
156
+
157
+
158
+ 这两天开始,官方已经开始对第三方代理进行了拉闸, `accessToken` 即将或已经开始可能会不可使用。异常 `API` 使用也开始封号,封号缘由不明,如果出现使用 `API` 提示错误,请查看后端控制台信息,或留意邮箱。
159
+
160
+ ## Feature
161
+ - 感谢 [CornerSkyless](https://github.com/Chanzhaoyu/chatgpt-web/pull/393) 添加是否发送上下文开关功能
162
+
163
+ ## Enhancement
164
+ - 感谢 [nagaame](https://github.com/Chanzhaoyu/chatgpt-web/pull/415) 优化`docker`打包镜像文件过大的问题
165
+ - 感谢 [xieccc](https://github.com/Chanzhaoyu/chatgpt-web/pull/404) 新增 `API` 模型配置变量 `OPENAI_API_MODEL`
166
+ - 感谢 [acongee](https://github.com/Chanzhaoyu/chatgpt-web/pull/394) 优化输出时滚动条问题
167
+
168
+ ## BugFix
169
+ - 感谢 [CornerSkyless](https://github.com/Chanzhaoyu/chatgpt-web/pull/392) 修复导出图片会丢失头像的问题
170
+ - 修复深色模式导出图片的样式问题
171
+
172
+
173
+ ## v2.10.0
174
+
175
+ `2023-03-07`
176
+
177
+ - 老规矩,手动部署的同学需要删除 `node_modules` 安装包重新安装降低出错概率,其他部署不受影响,但是可能会有缓存问题。
178
+ - 虽然说了更新放缓,但是 `issues` 不看, `PR` 不改我睡不着,我的邮箱从每天早上`8`点到凌晨`12`永远在滴滴滴,所以求求各位,超时的`issues`自己关闭下哈,我真的需要缓冲一下。
179
+ - 演示图片请看最后
180
+
181
+ ## Feature
182
+ - 添加权限功能,用法:`service/.env` 中的 `AUTH_SECRET_KEY` 变量添加密码
183
+ - 感谢 [PeterDaveHello](https://github.com/Chanzhaoyu/chatgpt-web/pull/348) 添加「繁体中文」翻译
184
+ - 感谢 [GermMC](https://github.com/Chanzhaoyu/chatgpt-web/pull/369) 添加聊天记录导入、导出、清空的功能
185
+ - 感谢 [CornerSkyless](https://github.com/Chanzhaoyu/chatgpt-web/pull/374) 添加会话保存为本地图片的功能
186
+
187
+
188
+ ## Enhancement
189
+ - 感谢 [CornerSkyless](https://github.com/Chanzhaoyu/chatgpt-web/pull/363) 添加 `ctrl+enter` 发送消息
190
+ - 现在新消息只有在结束了之后才滚动到底部,而不是之前的强制性
191
+ - 优化部分代码
192
+
193
+ ## BugFix
194
+ - 转义状态码前端显示,防止直接暴露 `key`(我可能需要更多的状态码补充)
195
+
196
+ ## Other
197
+ - 更新依赖到最新
198
+
199
+ ## 演示
200
+ > 不是界面最新效果,有美化改动
201
+
202
+ 权限
203
+
204
+ ![权限](https://user-images.githubusercontent.com/24789441/223438518-80d58d42-e344-4e39-b87c-251ff73925ed.png)
205
+
206
+ 聊天记录导出
207
+
208
+ ![聊天记录导出](https://user-images.githubusercontent.com/57023771/223372153-6d8e9ec1-d82c-42af-b4bd-232e50504a25.gif)
209
+
210
+ 保存图片到本地
211
+
212
+ ![保存图片到本地](https://user-images.githubusercontent.com/13901424/223423555-b69b95ef-8bcf-4951-a7c9-98aff2677e18.gif)
213
+
214
+ ## v2.9.3
215
+
216
+ `2023-03-06`
217
+
218
+ ## Enhancement
219
+ - 感谢 [ChandlerVer5](https://github.com/Chanzhaoyu/chatgpt-web/pull/305) 使用 `markdown-it` 替换 `marked`,解决代码块闪烁的问题
220
+ - 感谢 [shansing](https://github.com/Chanzhaoyu/chatgpt-web/pull/277) 改善文档
221
+ - 感谢 [nalf3in](https://github.com/Chanzhaoyu/chatgpt-web/pull/293) 添加英文翻译
222
+
223
+ ## BugFix
224
+ - 感谢[sepcnt ](https://github.com/Chanzhaoyu/chatgpt-web/pull/279) 修复切换记录时编辑状态未关闭的问题
225
+ - 修复复制代码的兼容性报错问题
226
+ - 修复部分优化小问题
227
+
228
+ ## v2.9.2
229
+
230
+ `2023-03-04`
231
+
232
+ 手动部署的同学,务必删除根目录和`service`中的`node_modules`重新安装依赖,降低出现问题的概率,自动部署的不需要做改动。
233
+
234
+ ### Feature
235
+ - 感谢 [hyln9](https://github.com/Chanzhaoyu/chatgpt-web/pull/247) 添加对渲染 `LaTex` 数学公式的支持
236
+ - 感谢 [ottocsb](https://github.com/Chanzhaoyu/chatgpt-web/pull/227) 添加支持 `webAPP` (苹果添加到主页书签访问)支持
237
+ - 添加 `OPENAI_API_BASE_URL` 可选环境变量[#249]
238
+ ## Enhancement
239
+ - 优化在高分屏上主题内容的最大宽度[#257]
240
+ - 现在文字按单词截断[#215][#225]
241
+ ### BugFix
242
+ - 修复动态生成时代码块不能被复制的问题[#251][#260]
243
+ - 修复 `iOS` 移动端输入框不会被键盘顶起的问题[#256]
244
+ - 修复控制台渲染警告
245
+ ## Other
246
+ - 更新依赖至最新
247
+ - 修改 `README` 内容
248
+
249
+ ## v2.9.1
250
+
251
+ `2023-03-02`
252
+
253
+ ### Feature
254
+ - 代码块添加当前代码语言显示和复制功能[#197][#196]
255
+ - 完善多语言,现在可以切换中英文显示
256
+
257
+ ## Enhancement
258
+ - 由[Zo3i](https://github.com/Chanzhaoyu/chatgpt-web/pull/187) 完善 `docker-compose` 部署文档
259
+
260
+ ### BugFix
261
+ - 由 [ottocsb](https://github.com/Chanzhaoyu/chatgpt-web/pull/200) 修复头像修改不同步的问题
262
+ ## Other
263
+ - 更新依赖至最新
264
+ - 修改 `README` 内容
265
+ ## v2.9.0
266
+
267
+ `2023-03-02`
268
+
269
+ ### Feature
270
+ - 现在能复制带格式的消息文本
271
+ - 新设计的设定页面,可以自定义姓名、描述、头像(链接方式)
272
+ - 新增`403`和`404`页面以便扩展
273
+
274
+ ## Enhancement
275
+ - 更新 `chatgpt` 使 `ChatGPTAPI` 支持 `gpt-3.5-turbo-0301`(默认)
276
+ - 取消了前端超时限制设定
277
+
278
+ ## v2.8.3
279
+
280
+ `2023-03-01`
281
+
282
+ ### Feature
283
+ - 消息已输出内容不会因为中断而消失[#167]
284
+ - 添加复制消息按钮[#133]
285
+
286
+ ### Other
287
+ - `README` 添加声明内容
288
+
289
+ ## v2.8.2
290
+
291
+ `2023-02-28`
292
+ ### Enhancement
293
+ - 代码主题调整为 `One Dark - light|dark` 适配深色模式
294
+ ### BugFix
295
+ - 修复普通文本代码渲染和深色模式下的问题[#139][#154]
296
+
297
+ ## v2.8.1
298
+
299
+ `2023-02-27`
300
+
301
+ ### BugFix
302
+ - 修复 `API` 版本不是 `Markdown` 时,普通 `HTML` 代码会被渲染的问题 [#146]
303
+
304
+ ## v2.8.0
305
+
306
+ `2023-02-27`
307
+
308
+ - 感谢 [puppywang](https://github.com/Chanzhaoyu/chatgpt-web/commit/628187f5c3348bda0d0518f90699a86525d19018) 修复了 `2.7.0` 版本中关于流输出数据的问题(使用 `nginx` 需要自行配置 `octet-stream` 相关内容)
309
+
310
+ - 关于为什么使用 `octet-stream` 而不是 `sse`,是因为更好的兼容之前的模式。
311
+
312
+ - 建议更新到此版本获得比较完整的体验
313
+
314
+ ### Enhancement
315
+ - 优化了部份代码和类型提示
316
+ - 输入框添加换行提示
317
+ - 移动端输入框现在回车为换行,而不是直接提交
318
+ - 移动端双击标题返回顶部,箭头返回底部
319
+
320
+ ### BugFix
321
+ - 流输出数据下的问题[#122]
322
+ - 修复了 `API Key` 下部份代码不换行的问题
323
+ - 修复移动端深色模式部份样式问题[#123][#126]
324
+ - 修复主题模式图标不一致的问题[#126]
325
+
326
+ ## v2.7.3
327
+
328
+ `2023-02-25`
329
+
330
+ ### Feature
331
+ - 适配系统深色模式 [#118](https://github.com/Chanzhaoyu/chatgpt-web/issues/103)
332
+ ### BugFix
333
+ - 修复用户消息能被渲染为 `HTML` 问题 [#117](https://github.com/Chanzhaoyu/chatgpt-web/issues/117)
334
+
335
+ ## v2.7.2
336
+
337
+ `2023-02-24`
338
+ ### Enhancement
339
+ - 消息使用 [github-markdown-css](https://www.npmjs.com/package/github-markdown-css) 进行美化,现在支持全语法
340
+ - 移除测试无用函数
341
+
342
+ ## v2.7.1
343
+
344
+ `2023-02-23`
345
+
346
+ 因为消息流在 `accessToken` 中存在解析失败和消息不完整等一系列的问题,调整回正常消息形式
347
+
348
+ ### Feature
349
+ - 现在可以中断请求过长没有答复的消息
350
+ - 现在可以删除单条消息
351
+ - 设置中显示当前版本信息
352
+
353
+ ### BugFix
354
+ - 回退 `2.7.0` 的消息不稳定的问题
355
+
356
+ ## v2.7.0
357
+
358
+ `2023-02-23`
359
+
360
+ ### Feature
361
+ - 使用消息流返回信息,反应更迅速
362
+
363
+ ### Enhancement
364
+ - 样式的一点小改动
365
+
366
+ ## v2.6.2
367
+
368
+ `2023-02-22`
369
+ ### BugFix
370
+ - 还原修改代理导致的异常问题
371
+
372
+ ## v2.6.1
373
+
374
+ `2023-02-22`
375
+
376
+ ### Feature
377
+ - 新增 `Railway` 部署模版
378
+
379
+ ### BugFix
380
+ - 手动打包 `Proxy` 问题
381
+
382
+ ## v2.6.0
383
+
384
+ `2023-02-21`
385
+ ### Feature
386
+ - 新增对 `网页 accessToken` 调用 `ChatGPT`,更智能不过不太稳定 [#51](https://github.com/Chanzhaoyu/chatgpt-web/issues/51)
387
+ - 前端页面设置按钮显示查看当前后端服务配置
388
+
389
+ ### Enhancement
390
+ - 新增 `TIMEOUT_MS` 环境变量设定后端超时时常(单位:毫秒)[#62](https://github.com/Chanzhaoyu/chatgpt-web/issues/62)
391
+
392
+ ## v2.5.2
393
+
394
+ `2023-02-21`
395
+ ### Feature
396
+ - 增加对 `markdown` 格式的支持 [Demo](https://github.com/Chanzhaoyu/chatgpt-web/pull/77)
397
+ ### BugFix
398
+ - 重载会话时滚动条保持
399
+
400
+ ## v2.5.1
401
+
402
+ `2023-02-21`
403
+
404
+ ### Enhancement
405
+ - 调整路由模式为 `hash`
406
+ - 调整新增会话添加到
407
+ - 调整移动端样式
408
+
409
+
410
+ ## v2.5.0
411
+
412
+ `2023-02-20`
413
+
414
+ ### Feature
415
+ - 会话 `loading` 现在显示为光标动画
416
+ - 会话现在可以再次生成回复
417
+ - 会话异常可以再次进行请求
418
+ - 所有删除选项添加确认��作
419
+
420
+ ### Enhancement
421
+ - 调整 `chat` 为路由页面而不是组件形式
422
+ - 更新依赖至最新
423
+ - 调整移动端体验
424
+
425
+ ### BugFix
426
+ - 修复移动端左侧菜单显示不完整的问题
427
+
428
+ ## v2.4.1
429
+
430
+ `2023-02-18`
431
+
432
+ ### Enhancement
433
+ - 调整部份移动端上的样式
434
+ - 输入框支持换行
435
+
436
+ ## v2.4.0
437
+
438
+ `2023-02-17`
439
+
440
+ ### Feature
441
+ - 响应式支持移动端
442
+ ### Enhancement
443
+ - 修改部份描述错误
444
+
445
+ ## v2.3.3
446
+
447
+ `2023-02-16`
448
+
449
+ ### Feature
450
+ - 添加 `README` 部份说明和贡献列表
451
+ - 添加 `docker` 镜像
452
+ - 添加 `GitHub Action` 自动化构建
453
+
454
+ ### BugFix
455
+ - 回退依赖更新导致的 [Eslint 报错](https://github.com/eslint/eslint/issues/16896)
456
+
457
+ ## v2.3.2
458
+
459
+ `2023-02-16`
460
+
461
+ ### Enhancement
462
+ - 更新依赖至最新
463
+ - 优化部份内容
464
+
465
+ ## v2.3.1
466
+
467
+ `2023-02-15`
468
+
469
+ ### BugFix
470
+ - 修复多会话状态下一些意想不到的问题
471
+
472
+ ## v2.3.0
473
+
474
+ `2023-02-15`
475
+ ### Feature
476
+ - 代码类型信息高亮显示
477
+ - 支持 `node ^16` 版本
478
+ - 移动端响应式初步支持
479
+ - `vite` 中 `proxy` 代理
480
+
481
+ ### Enhancement
482
+ - 调整超时处理范围
483
+
484
+ ### BugFix
485
+ - 修复取消请求错误提示会添加到信息中
486
+ - 修复部份情况下提交请求不可用
487
+ - 修复侧边栏宽度变化闪烁的问题
488
+
489
+ ## v2.2.0
490
+
491
+ `2023-02-14`
492
+ ### Feature
493
+ - 会话和上下文本地储存
494
+ - 侧边栏本地储存
495
+
496
+ ## v2.1.0
497
+
498
+ `2023-02-14`
499
+ ### Enhancement
500
+ - 更新依赖至最新
501
+ - 联想功能移动至前端提交,后端只做转发
502
+
503
+ ### BugFix
504
+ - 修复部份项目检测有关 `Bug`
505
+ - 修复清除上下文按钮失效
506
+
507
+ ## v2.0.0
508
+
509
+ `2023-02-13`
510
+ ### Refactor
511
+ 重构并优化大部分内容
512
+
513
+ ## v1.0.5
514
+
515
+ `2023-02-12`
516
+
517
+ ### Enhancement
518
+ - 输入框焦点,连续提交
519
+
520
+ ### BugFix
521
+ - 修复信息框样式问题
522
+ - 修复中文输入法提交问题
523
+
524
+ ## v1.0.4
525
+
526
+ `2023-02-11`
527
+
528
+ ### Feature
529
+ - 支持上下文联想
530
+
531
+ ## v1.0.3
532
+
533
+ `2023-02-11`
534
+
535
+ ### Enhancement
536
+ - 拆分 `service` 文件以便扩展
537
+ - 调整 `Eslint` 相关验证
538
+
539
+ ### BugFix
540
+ - 修复部份控制台报错
541
+
542
+ ## v1.0.2
543
+
544
+ `2023-02-10`
545
+
546
+ ### BugFix
547
+ - 修复新增信息容器不会自动滚动到问题
548
+ - 修复文本过长不换行到问题 [#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,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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/dist /app/public
51
+
52
+ COPY --from=backend /app/build /app/build
53
+
54
+ EXPOSE 3002
55
+
56
+ RUN --mount=type=secret,id=AUTH_SECRET_KEY,mode=0444,required=true
57
+ RUN --mount=type=secret,id=API_REVERSE_PROXY,mode=0444,required=true
58
+ RUN --mount=type=secret,id=OPENAI_ACCESS_TOKEN,mode=0444,required=true
59
+
60
+ CMD ["pnpm", "run", "prod"]
README.cn.md ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ > 声明:此项目只发布于 Github,基于 MIT 协议,免费且作为开源学习使用。并且不会有任何形式的卖号、付费服务、讨论群、讨论组等行为。谨防受骗。
10
+
11
+ ![cover](./docs/c1.png)
12
+ ![cover2](./docs/c2.png)
13
+
14
+ - [ChatGPT Web](#chatgpt-web)
15
+ - [介绍](#介绍)
16
+ - [待实现路线](#待实现路线)
17
+ - [前置要求](#前置要求)
18
+ - [Node](#node)
19
+ - [PNPM](#pnpm)
20
+ - [填写密钥](#填写密钥)
21
+ - [安装依赖](#安装依赖)
22
+ - [后端](#后端)
23
+ - [前端](#前端)
24
+ - [测试环境运行](#测试环境运行)
25
+ - [后端服务](#后端服务)
26
+ - [前端网页](#前端网页)
27
+ - [环境变量](#环境变量)
28
+ - [打包](#打包)
29
+ - [使用 Docker](#使用-docker)
30
+ - [Docker 参数示例](#docker-参数示例)
31
+ - [Docker build \& Run](#docker-build--run)
32
+ - [Docker compose](#docker-compose)
33
+ - [使用 Railway 部署](#使用-railway-部署)
34
+ - [Railway 环境变量](#railway-环境变量)
35
+ - [手动打包](#手动打包)
36
+ - [后端服务](#后端服务-1)
37
+ - [前端网页](#前端网页-1)
38
+ - [常见问题](#常见问题)
39
+ - [参与贡献](#参与贡献)
40
+ - [赞助](#赞助)
41
+ - [License](#license)
42
+ ## 介绍
43
+
44
+ 支持双模型,提供了两种非官方 `ChatGPT API` 方法
45
+
46
+ | 方式 | 免费? | 可靠性 | 质量 |
47
+ | --------------------------------------------- | ------ | ---------- | ---- |
48
+ | `ChatGPTAPI(gpt-3.5-turbo-0301)` | 否 | 可靠 | 相对较笨 |
49
+ | `ChatGPTUnofficialProxyAPI(网页 accessToken)` | 是 | 相对不可靠 | 聪明 |
50
+
51
+ 对比:
52
+ 1. `ChatGPTAPI` 使用 `gpt-3.5-turbo-0301` 通过官方`OpenAI`补全`API`模拟`ChatGPT`(最稳健的方法,但它不是免费的,并且没有使用针对聊天进行微调的模型)
53
+ 2. `ChatGPTUnofficialProxyAPI` 使用非官方代理服务器访问 `ChatGPT` 的后端`API`,绕过`Cloudflare`(使用真实的的`ChatGPT`,非常轻量级,但依赖于第三方服务器,并且有速率限制)
54
+
55
+ 警告:
56
+ 1. 你应该首先使用 `API` 方式
57
+ 2. 使用 `API` 时,如果网络不通,那是国内被墙了,你需要自建代理,绝对不要使用别人的公开代理,那是危险的。
58
+ 3. 使用 `accessToken` 方式时反向代理将向第三方暴露您的访问令牌,这样做应该不会产生任何不良影响,但在使用这种方法之前请考虑风险。
59
+ 4. 使用 `accessToken` 时,不管你是国内还是国外的机器,都会使用代理。默认代理为 [acheong08](https://github.com/acheong08) 大佬的 `https://bypass.churchless.tech/api/conversation`,这不是后门也不是监听,除非你有能力自己翻过 `CF` 验证,用前请知悉。[社区代理](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy)(注意:只有这两个是推荐,其他第三方来源,请自行甄别)
60
+ 5. 把项目发布到公共网络时,你应该设置 `AUTH_SECRET_KEY` 变量添加你的密码访问权限,你也应该修改 `index.html` 中的 `title`,防止被关键词搜索到。
61
+
62
+ 切换方式:
63
+ 1. 进入 `service/.env.example` 文件,复制内容到 `service/.env` 文件
64
+ 2. 使用 `OpenAI API Key` 请填写 `OPENAI_API_KEY` 字段 [(获取 apiKey)](https://platform.openai.com/overview)
65
+ 3. 使用 `Web API` 请填写 `OPENAI_ACCESS_TOKEN` 字段 [(获取 accessToken)](https://chat.openai.com/api/auth/session)
66
+ 4. 同时存在时以 `OpenAI API Key` 优先
67
+
68
+ 环境变量:
69
+
70
+ 全部参数变量请查看或[这里](#环境变量)
71
+
72
+ ```
73
+ /service/.env.example
74
+ ```
75
+
76
+ ## 待实现路线
77
+ [✓] 双模型
78
+
79
+ [✓] 多会话储存和上下文逻辑
80
+
81
+ [✓] 对代码等消息类型的格式化美化处理
82
+
83
+ [✓] 访问权限控制
84
+
85
+ [✓] 数据导入、导出
86
+
87
+ [✓] 保存消息到本地图片
88
+
89
+ [✓] 界面多语言
90
+
91
+ [✓] 界面主题
92
+
93
+ [✗] More...
94
+
95
+ ## 前置要求
96
+
97
+ ### Node
98
+
99
+ `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` 版本
100
+
101
+ ```shell
102
+ node -v
103
+ ```
104
+
105
+ ### PNPM
106
+ 如果你没有安装过 `pnpm`
107
+ ```shell
108
+ npm install pnpm -g
109
+ ```
110
+
111
+ ### 填写密钥
112
+ 获取 `Openai Api Key` 或 `accessToken` 并填写本地环境变量 [跳转](#介绍)
113
+
114
+ ```
115
+ # service/.env 文件
116
+
117
+ # OpenAI API Key - https://platform.openai.com/overview
118
+ OPENAI_API_KEY=
119
+
120
+ # change this to an `accessToken` extracted from the ChatGPT site's `https://chat.openai.com/api/auth/session` response
121
+ OPENAI_ACCESS_TOKEN=
122
+ ```
123
+
124
+ ## 安装依赖
125
+
126
+ > 为了简便 `后端开发人员` 的了解负担,所以并没有采用前端 `workspace` 模式,而是分文件夹存放。如果只需要前端页面做二次开发,删除 `service` 文件夹即可。
127
+
128
+ ### 后端
129
+
130
+ 进入文件夹 `/service` 运行以下命令
131
+
132
+ ```shell
133
+ pnpm install
134
+ ```
135
+
136
+ ### 前端
137
+ 根目录下运行以下命令
138
+ ```shell
139
+ pnpm bootstrap
140
+ ```
141
+
142
+ ## 测试环境运行
143
+ ### 后端服务
144
+
145
+ 进入文件夹 `/service` 运行以下命令
146
+
147
+ ```shell
148
+ pnpm start
149
+ ```
150
+
151
+ ### 前端网页
152
+ 根目录下运行以下命令
153
+ ```shell
154
+ pnpm dev
155
+ ```
156
+
157
+ ## 环境变量
158
+
159
+ `API` 可用:
160
+
161
+ - `OPENAI_API_KEY` 和 `OPENAI_ACCESS_TOKEN` 二选一
162
+ - `OPENAI_API_MODEL` 设置模型,可选,默认:`gpt-3.5-turbo`
163
+ - `OPENAI_API_BASE_URL` 设置接口地址,可选,默认:`https://api.openai.com`
164
+
165
+ `ACCESS_TOKEN` 可用:
166
+
167
+ - `OPENAI_ACCESS_TOKEN` 和 `OPENAI_API_KEY` 二选一,同时存在时,`OPENAI_API_KEY` 优先
168
+ - `API_REVERSE_PROXY` 设置反向代理,可选,默认:`https://bypass.churchless.tech/api/conversation`,[社区](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy)(注意:只有这两个是推荐,其他第三方来源,请自行甄别)
169
+
170
+ 通用:
171
+
172
+ - `AUTH_SECRET_KEY` 访问权限密钥,可选
173
+ - `MAX_REQUEST_PER_HOUR` 每小时最大请求次数,可选,默认无限
174
+ - `TIMEOUT_MS` 超时,单位毫秒,可选
175
+ - `SOCKS_PROXY_HOST` 和 `SOCKS_PROXY_PORT` 一起时生效,可选
176
+ - `SOCKS_PROXY_PORT` 和 `SOCKS_PROXY_HOST` 一起时生效,可选
177
+ - `HTTPS_PROXY` 支持 `http`,`https`, `socks5`,可选
178
+ - `ALL_PROXY` 支持 `http`,`https`, `socks5`,可选
179
+
180
+ ## 打包
181
+
182
+ ### 使用 Docker
183
+
184
+ #### Docker 参数示例
185
+
186
+ ![docker](./docs/docker.png)
187
+
188
+ #### Docker build & Run
189
+
190
+ ```bash
191
+ docker build -t chatgpt-web .
192
+
193
+ # 前台运行
194
+ docker run --name chatgpt-web --rm -it -p 127.0.0.1:3002:3002 --env OPENAI_API_KEY=your_api_key chatgpt-web
195
+
196
+ # 后台运行
197
+ docker run --name chatgpt-web -d -p 127.0.0.1:3002:3002 --env OPENAI_API_KEY=your_api_key chatgpt-web
198
+
199
+ # 运行地址
200
+ http://localhost:3002/
201
+ ```
202
+
203
+ #### Docker compose
204
+
205
+ [Hub 地址](https://hub.docker.com/repository/docker/chenzhaoyu94/chatgpt-web/general)
206
+
207
+ ```yml
208
+ version: '3'
209
+
210
+ services:
211
+ app:
212
+ image: chenzhaoyu94/chatgpt-web # 总是使用 latest ,更新时重新 pull 该 tag 镜像即可
213
+ ports:
214
+ - 127.0.0.1:3002:3002
215
+ environment:
216
+ # 二选一
217
+ OPENAI_API_KEY: sk-xxx
218
+ # 二选一
219
+ OPENAI_ACCESS_TOKEN: xxx
220
+ # API接口地址,可选,设置 OPENAI_API_KEY 时可用
221
+ OPENAI_API_BASE_URL: xxx
222
+ # API模型,可选,设置 OPENAI_API_KEY 时可用,https://platform.openai.com/docs/models
223
+ # gpt-4, gpt-4-0314, gpt-4-32k, gpt-4-32k-0314, gpt-3.5-turbo, gpt-3.5-turbo-0301, text-davinci-003, text-davinci-002, code-davinci-002
224
+ OPENAI_API_MODEL: xxx
225
+ # 反向代理,可选
226
+ API_REVERSE_PROXY: xxx
227
+ # 访问权限密钥,可选
228
+ AUTH_SECRET_KEY: xxx
229
+ # 每小时最大请求次数,可选,默认无限
230
+ MAX_REQUEST_PER_HOUR: 0
231
+ # 超时,单位毫秒,可选
232
+ TIMEOUT_MS: 60000
233
+ # Socks代理,可选,和 SOCKS_PROXY_PORT 一起时生效
234
+ SOCKS_PROXY_HOST: xxx
235
+ # Socks代理端口,可选,和 SOCKS_PROXY_HOST 一起时生效
236
+ SOCKS_PROXY_PORT: xxx
237
+ # HTTPS 代理,可选,支持 http,https,socks5
238
+ HTTPS_PROXY: http://xxx:7890
239
+ ```
240
+ - `OPENAI_API_BASE_URL` 可选,设置 `OPENAI_API_KEY` 时可用
241
+ - `OPENAI_API_MODEL` 可选,设置 `OPENAI_API_KEY` 时可用
242
+ ### 使用 Railway 部署
243
+
244
+ [![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template/yytmgc)
245
+
246
+ #### Railway 环境变量
247
+
248
+ | 环境变量名称 | 必填 | 备注 |
249
+ | --------------------- | ---------------------- | -------------------------------------------------------------------------------------------------- |
250
+ | `PORT` | 必填 | 默认 `3002`
251
+ | `AUTH_SECRET_KEY` | 可选 | 访问权限密钥 |
252
+ | `MAX_REQUEST_PER_HOUR` | 可选 | 每小时最大请求次数,可选,默认无限 |
253
+ | `TIMEOUT_MS` | 可选 | 超时时间,单位毫秒 |
254
+ | `OPENAI_API_KEY` | `OpenAI API` 二选一 | 使用 `OpenAI API` 所需的 `apiKey` [(获取 apiKey)](https://platform.openai.com/overview) |
255
+ | `OPENAI_ACCESS_TOKEN` | `Web API` 二选一 | 使用 `Web API` 所需的 `accessToken` [(获取 accessToken)](https://chat.openai.com/api/auth/session) |
256
+ | `OPENAI_API_BASE_URL` | 可选,`OpenAI API` 时可用 | `API`接口地址 |
257
+ | `OPENAI_API_MODEL` | 可选,`OpenAI API` 时可用 | `API`模型 |
258
+ | `API_REVERSE_PROXY` | 可选,`Web API` 时可用 | `Web API` 反向代理地址 [详情](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy) |
259
+ | `SOCKS_PROXY_HOST` | 可选,和 `SOCKS_PROXY_PORT` 一起时生效 | Socks代理 |
260
+ | `SOCKS_PROXY_PORT` | 可选,和 `SOCKS_PROXY_HOST` 一起时生效 | Socks代理端口 |
261
+ | `HTTPS_PROXY` | 可选 | HTTPS 代理,支持 http,https, socks5 |
262
+ | `ALL_PROXY` | 可选 | 所有代理 代理,支持 http,https, socks5 |
263
+
264
+ > 注意: `Railway` 修改环境变量会重新 `Deploy`
265
+
266
+ ### 手动打包
267
+ #### 后端服务
268
+ > 如果你不需要本项目的 `node` 接口,可以省略如下操作
269
+
270
+ 复制 `service` 文件夹到你有 `node` 服务环境的服务器上。
271
+
272
+ ```shell
273
+ # 安装
274
+ pnpm install
275
+
276
+ # 打包
277
+ pnpm build
278
+
279
+ # 运行
280
+ pnpm prod
281
+ ```
282
+
283
+ PS: 不进行打包,直接在服务器上运行 `pnpm start` 也可
284
+
285
+ #### 前端网页
286
+
287
+ 1、修改根目录下 `.env` 文件中的 `VITE_GLOB_API_URL` 为你的实际后端接口地址
288
+
289
+ 2、根目录下运行以下命令,然后将 `dist` 文件夹内的文件复制到你网站服务的根目录下
290
+
291
+ [参考信息](https://cn.vitejs.dev/guide/static-deploy.html#building-the-app)
292
+
293
+ ```shell
294
+ pnpm build
295
+ ```
296
+
297
+ ## 常见问题
298
+ Q: 为什么 `Git` 提交总是报错?
299
+
300
+ A: 因为有提交信息验证,请遵循 [Commit 指南](./CONTRIBUTING.md)
301
+
302
+ Q: 如果只使用前端页面,在哪里改请求接口?
303
+
304
+ A: 根目录下 `.env` 文件中的 `VITE_GLOB_API_URL` 字段。
305
+
306
+ Q: 文件保存时全部爆红?
307
+
308
+ A: `vscode` 请安装项目推荐插件,或手动安装 `Eslint` 插件。
309
+
310
+ Q: 前端没有打字机效果?
311
+
312
+ A: 一种可能原因是经过 Nginx 反向代理,开启了 buffer,则 Nginx 会尝试从后端缓冲一定大小的数据再发送给浏览器。请尝试在反代参数后添加 `proxy_buffering off;`,然后重载 Nginx。其他 web server 配置同理。
313
+
314
+ ## 参与贡献
315
+
316
+ 贡献之前请先阅读 [贡献指南](./CONTRIBUTING.md)
317
+
318
+ 感谢所有做过贡献的人!
319
+
320
+ <a href="https://github.com/Chanzhaoyu/chatgpt-web/graphs/contributors">
321
+ <img src="https://contrib.rocks/image?repo=Chanzhaoyu/chatgpt-web" />
322
+ </a>
323
+
324
+ ## 赞助
325
+
326
+ 如果你觉得这个项目对你有帮助,并且情况允许的话,可以给我一点点支持,总之非常感谢支持~
327
+
328
+ <div style="display: flex; gap: 20px;">
329
+ <div style="text-align: center">
330
+ <img style="max-width: 100%" src="./docs/wechat.png" alt="微信" />
331
+ <p>WeChat Pay</p>
332
+ </div>
333
+ <div style="text-align: center">
334
+ <img style="max-width: 100%" src="./docs/alipay.png" alt="支付宝" />
335
+ <p>Alipay</p>
336
+ </div>
337
+ </div>
338
+
339
+ ## License
340
+ MIT © [ChenZhaoYu](./license)
README.en.md ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ > 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.
10
+
11
+ ![cover](./docs/c1.png)
12
+ ![cover2](./docs/c2.png)
13
+
14
+ - [ChatGPT Web](#chatgpt-web)
15
+ - [Introduction](#introduction)
16
+ - [Roadmap](#roadmap)
17
+ - [Prerequisites](#prerequisites)
18
+ - [Node](#node)
19
+ - [PNPM](#pnpm)
20
+ - [Fill in the Keys](#fill-in-the-keys)
21
+ - [Install Dependencies](#install-dependencies)
22
+ - [Backend](#backend)
23
+ - [Frontend](#frontend)
24
+ - [Run in Test Environment](#run-in-test-environment)
25
+ - [Backend Service](#backend-service)
26
+ - [Frontend Webpage](#frontend-webpage)
27
+ - [Packaging](#packaging)
28
+ - [Using Docker](#using-docker)
29
+ - [Docker Parameter Example](#docker-parameter-example)
30
+ - [Docker Build \& Run](#docker-build--run)
31
+ - [Docker Compose](#docker-compose)
32
+ - [Deployment with Railway](#deployment-with-railway)
33
+ - [Railway Environment Variables](#railway-environment-variables)
34
+ - [Manual packaging](#manual-packaging)
35
+ - [Backend service](#backend-service-1)
36
+ - [Frontend webpage](#frontend-webpage-1)
37
+ - [Frequently Asked Questions](#frequently-asked-questions)
38
+ - [Contributing](#contributing)
39
+ - [Sponsorship](#sponsorship)
40
+ - [License](#license)
41
+
42
+ ## Introduction
43
+
44
+ Supports dual models, provides two unofficial `ChatGPT API` methods:
45
+
46
+ | Method | Free? | Reliability | Quality |
47
+ | --------------------------------------------- | ------ | ----------- | ------- |
48
+ | `ChatGPTAPI(gpt-3.5-turbo-0301)` | No | Reliable | Relatively clumsy |
49
+ | `ChatGPTUnofficialProxyAPI(Web accessToken)` | Yes | Relatively unreliable | Smart |
50
+
51
+ Comparison:
52
+ 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).
53
+ 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).
54
+
55
+ [Details](https://github.com/Chanzhaoyu/chatgpt-web/issues/138)
56
+
57
+ Switching Methods:
58
+ 1. Go to the `service/.env.example` file and copy the contents to the `service/.env` file.
59
+ 2. For `OpenAI API Key`, fill in the `OPENAI_API_KEY` field [(Get apiKey)](https://platform.openai.com/overview).
60
+ 3. For `Web API`, fill in the `OPENAI_ACCESS_TOKEN` field [(Get accessToken)](https://chat.openai.com/api/auth/session).
61
+ 4. When both are present, `OpenAI API Key` takes precedence.
62
+
63
+ Reverse Proxy:
64
+
65
+ Available when using `ChatGPTUnofficialProxyAPI`.[Details](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy)
66
+
67
+ ```shell
68
+ # service/.env
69
+ API_REVERSE_PROXY=
70
+ ```
71
+
72
+ Environment Variables:
73
+
74
+ For all parameter variables, check [here](#docker-parameter-example) or see:
75
+
76
+ ```
77
+ /service/.env
78
+ ```
79
+
80
+ ## Roadmap
81
+ [✓] Dual models
82
+
83
+ [✓] Multiple session storage and context logic
84
+
85
+ [✓] Formatting and beautifying code-like message types
86
+
87
+ [✓] Access rights control
88
+
89
+ [✓] Data import and export
90
+
91
+ [✓] Save message to local image
92
+
93
+ [✓] Multilingual interface
94
+
95
+ [✓] Interface themes
96
+
97
+ [✗] More...
98
+
99
+ ## Prerequisites
100
+
101
+ ### Node
102
+
103
+ `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).
104
+
105
+ ```shell
106
+ node -v
107
+ ```
108
+
109
+ ### PNPM
110
+ If you have not installed `pnpm` before:
111
+ ```shell
112
+ npm install pnpm -g
113
+ ```
114
+
115
+ ### Fill in the Keys
116
+
117
+ Get `Openai Api Key` or `accessToken` and fill in the local environment variables [jump](#introduction)
118
+
119
+ ```
120
+ # service/.env file
121
+
122
+ # OpenAI API Key - https://platform.openai.com/overview
123
+ OPENAI_API_KEY=
124
+
125
+ # change this to an `accessToken` extracted from the ChatGPT site's `https://chat.openai.com/api/auth/session` response
126
+ OPENAI_ACCESS_TOKEN=
127
+ ```
128
+
129
+ ## Install Dependencies
130
+
131
+ > 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.
132
+
133
+ ### Backend
134
+
135
+ Enter the `/service` folder and run the following command
136
+
137
+ ```shell
138
+ pnpm install
139
+ ```
140
+
141
+ ### Frontend
142
+ Run the following command in the root directory
143
+ ```shell
144
+ pnpm bootstrap
145
+ ```
146
+
147
+ ## Run in Test Environment
148
+ ### Backend Service
149
+
150
+ Enter the `/service` folder and run the following command
151
+
152
+ ```shell
153
+ pnpm start
154
+ ```
155
+
156
+ ### Frontend Webpage
157
+ Run the following command in the root directory
158
+ ```shell
159
+ pnpm dev
160
+ ```
161
+
162
+ ## Packaging
163
+
164
+ ### Using Docker
165
+
166
+ #### Docker Parameter Example
167
+
168
+ - `OPENAI_API_KEY` one of two
169
+ - `OPENAI_ACCESS_TOKEN` one of two, `OPENAI_API_KEY` takes precedence when both are present
170
+ - `OPENAI_API_BASE_URL` optional, available when `OPENAI_API_KEY` is set
171
+ - `OPENAI_API_MODEL` optional, available when `OPENAI_API_KEY` is set
172
+ - `API_REVERSE_PROXY` optional, available when `OPENAI_ACCESS_TOKEN` is set [Reference](#introduction)
173
+ - `AUTH_SECRET_KEY` Access Password,optional
174
+ - `TIMEOUT_MS` timeout, in milliseconds, optional
175
+ - `SOCKS_PROXY_HOST` optional, effective with SOCKS_PROXY_PORT
176
+ - `SOCKS_PROXY_PORT` optional, effective with SOCKS_PROXY_HOST
177
+ - `HTTPS_PROXY` optional, support http,https, socks5
178
+ - `ALL_PROXY` optional, support http,https, socks5
179
+
180
+ ![docker](./docs/docker.png)
181
+
182
+ #### Docker Build & Run
183
+
184
+ ```bash
185
+ docker build -t chatgpt-web .
186
+
187
+ # foreground operation
188
+ docker run --name chatgpt-web --rm -it -p 127.0.0.1:3002:3002 --env OPENAI_API_KEY=your_api_key chatgpt-web
189
+
190
+ # background operation
191
+ docker run --name chatgpt-web -d -p 127.0.0.1:3002:3002 --env OPENAI_API_KEY=your_api_key chatgpt-web
192
+
193
+ # running address
194
+ http://localhost:3002/
195
+ ```
196
+
197
+ #### Docker Compose
198
+
199
+ [Hub Address](https://hub.docker.com/repository/docker/chenzhaoyu94/chatgpt-web/general)
200
+
201
+ ```yml
202
+ version: '3'
203
+
204
+ services:
205
+ app:
206
+ image: chenzhaoyu94/chatgpt-web # always use latest, pull the tag image again when updating
207
+ ports:
208
+ - 127.0.0.1:3002:3002
209
+ environment:
210
+ # one of two
211
+ OPENAI_API_KEY: xxxxxx
212
+ # one of two
213
+ OPENAI_ACCESS_TOKEN: xxxxxx
214
+ # api interface url, optional, available when OPENAI_API_KEY is set
215
+ OPENAI_API_BASE_URL: xxxx
216
+ # api model, optional, available when OPENAI_API_KEY is set
217
+ OPENAI_API_MODEL: xxxx
218
+ # reverse proxy, optional
219
+ API_REVERSE_PROXY: xxx
220
+ # access password,optional
221
+ AUTH_SECRET_KEY: xxx
222
+ # timeout, in milliseconds, optional
223
+ TIMEOUT_MS: 60000
224
+ # socks proxy, optional, effective with SOCKS_PROXY_PORT
225
+ SOCKS_PROXY_HOST: xxxx
226
+ # socks proxy port, optional, effective with SOCKS_PROXY_HOST
227
+ SOCKS_PROXY_PORT: xxxx
228
+ # HTTPS Proxy,optional, support http, https, socks5
229
+ HTTPS_PROXY: http://xxx:7890
230
+ ```
231
+ The `OPENAI_API_BASE_URL` is optional and only used when setting the `OPENAI_API_KEY`.
232
+ The `OPENAI_API_MODEL` is optional and only used when setting the `OPENAI_API_KEY`.
233
+
234
+ ### Deployment with Railway
235
+
236
+ [![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template/yytmgc)
237
+
238
+ #### Railway Environment Variables
239
+
240
+ | Environment Variable | Required | Description |
241
+ | -------------------- | -------- | ------------------------------------------------------------------------------------------------- |
242
+ | `PORT` | Required | Default: `3002` |
243
+ | `AUTH_SECRET_KEY` | Optional | access password |
244
+ | `TIMEOUT_MS` | Optional | Timeout in milliseconds |
245
+ | `OPENAI_API_KEY` | Optional | Required for `OpenAI API`. `apiKey` can be obtained from [here](https://platform.openai.com/overview). |
246
+ | `OPENAI_ACCESS_TOKEN`| Optional | Required for `Web API`. `accessToken` can be obtained from [here](https://chat.openai.com/api/auth/session).|
247
+ | `OPENAI_API_BASE_URL` | Optional, only for `OpenAI API` | API endpoint. |
248
+ | `OPENAI_API_MODEL` | Optional, only for `OpenAI API` | API model. |
249
+ | `API_REVERSE_PROXY` | Optional, only for `Web API` | Reverse proxy address for `Web API`. [Details](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy) |
250
+ | `SOCKS_PROXY_HOST` | Optional, effective with `SOCKS_PROXY_PORT` | Socks proxy. |
251
+ | `SOCKS_PROXY_PORT` | Optional, effective with `SOCKS_PROXY_HOST` | Socks proxy port. |
252
+ | `HTTPS_PROXY` | Optional | HTTPS Proxy. |
253
+ | `ALL_PROXY` | Optional | ALL Proxy. |
254
+
255
+ > Note: Changing environment variables in Railway will cause re-deployment.
256
+
257
+ ### Manual packaging
258
+
259
+ #### Backend service
260
+
261
+ > If you don't need the `node` interface of this project, you can skip the following steps.
262
+
263
+ Copy the `service` folder to a server that has a `node` service environment.
264
+
265
+ ```shell
266
+ # Install
267
+ pnpm install
268
+
269
+ # Build
270
+ pnpm build
271
+
272
+ # Run
273
+ pnpm prod
274
+ ```
275
+
276
+ PS: You can also run `pnpm start` directly on the server without packaging.
277
+
278
+ #### Frontend webpage
279
+
280
+ 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.
281
+ 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.
282
+
283
+ [Reference information](https://cn.vitejs.dev/guide/static-deploy.html#building-the-app)
284
+
285
+ ```shell
286
+ pnpm build
287
+ ```
288
+
289
+ ## Frequently Asked Questions
290
+
291
+ Q: Why does Git always report an error when committing?
292
+
293
+ A: Because there is submission information verification, please follow the [Commit Guidelines](./CONTRIBUTING.en.md).
294
+
295
+ Q: Where to change the request interface if only the frontend page is used?
296
+
297
+ A: The `VITE_GLOB_API_URL` field in the `.env` file at the root directory.
298
+
299
+ Q: All red when saving the file?
300
+
301
+ A: For `vscode`, please install the recommended plug-in of the project or manually install the `Eslint` plug-in.
302
+
303
+ Q: Why doesn't the frontend have a typewriter effect?
304
+
305
+ 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.
306
+
307
+ Q: The content returned is incomplete?
308
+
309
+ 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.
310
+
311
+ ## Contributing
312
+
313
+ Please read the [Contributing Guidelines](./CONTRIBUTING.en.md) before contributing.
314
+
315
+ Thanks to all the contributors!
316
+
317
+ <a href="https://github.com/Chanzhaoyu/chatgpt-web/graphs/contributors">
318
+ <img src="https://contrib.rocks/image?repo=Chanzhaoyu/chatgpt-web" />
319
+ </a>
320
+
321
+ ## Sponsorship
322
+
323
+ If you find this project helpful and circumstances permit, you can give me a little support. Thank you very much for your support~
324
+
325
+ <div style="display: flex; gap: 20px;">
326
+ <div style="text-align: center">
327
+ <img style="max-width: 100%" src="./docs/wechat.png" alt="WeChat" />
328
+ <p>WeChat Pay</p>
329
+ </div>
330
+ <div style="text-align: center">
331
+ <img style="max-width: 100%" src="./docs/alipay.png" alt="Alipay" />
332
+ <p>Alipay</p>
333
+ </div>
334
+ </div>
335
+
336
+ ## License
337
+ MIT © [ChenZhaoYu](./license)
README.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: dvcchat
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
config/index.ts ADDED
@@ -0,0 +1 @@
 
 
1
+ export * from './proxy'
config/proxy.ts ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { ProxyOptions } from 'vite'
2
+
3
+ export function createViteProxy(isOpenProxy: boolean, viteEnv: ImportMetaEnv) {
4
+ if (!isOpenProxy)
5
+ return
6
+
7
+ const proxy: Record<string, string | ProxyOptions> = {
8
+ '/api': {
9
+ target: viteEnv.VITE_APP_API_BASE_URL,
10
+ changeOrigin: true,
11
+ rewrite: path => path.replace('/api/', '/'),
12
+ },
13
+ }
14
+
15
+ return proxy
16
+ }
docker-compose/docker-compose.yml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3'
2
+
3
+ services:
4
+ app:
5
+ image: chenzhaoyu94/chatgpt-web # 总是使用latest,更新时重新pull该tag镜像即可
6
+ ports:
7
+ - 3002:3002
8
+ environment:
9
+ # 二选一
10
+ OPENAI_API_KEY: sk-xxx
11
+ # 二选一
12
+ OPENAI_ACCESS_TOKEN: xxx
13
+ # API接口地址,可选,设置 OPENAI_API_KEY 时可用
14
+ OPENAI_API_BASE_URL: xxx
15
+ # API模型,可选,设置 OPENAI_API_KEY 时可用
16
+ OPENAI_API_MODEL: xxx
17
+ # 反向代理,可选
18
+ API_REVERSE_PROXY: xxx
19
+ # 访问权限密钥,可选
20
+ AUTH_SECRET_KEY: xxx
21
+ # 每小时最大请求次数,可选,默认无限
22
+ MAX_REQUEST_PER_HOUR: 0
23
+ # 超时,单位毫秒,可选
24
+ TIMEOUT_MS: 60000
25
+ # Socks代理,可选,和 SOCKS_PROXY_PORT 一起时生效
26
+ SOCKS_PROXY_HOST: xxx
27
+ # Socks代理端口,可选,和 SOCKS_PROXY_HOST 一起时生效
28
+ SOCKS_PROXY_PORT: xxx
29
+ # HTTPS_PROXY 代理,可选
30
+ HTTPS_PROXY: http://xxx:7890
31
+ nginx:
32
+ image: nginx:alpine
33
+ ports:
34
+ - '80:80'
35
+ expose:
36
+ - '80'
37
+ volumes:
38
+ - ./nginx/html:/usr/share/nginx/html
39
+ - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
40
+ links:
41
+ - app
docker-compose/nginx/nginx.conf ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ server {
2
+ listen 80;
3
+ server_name localhost;
4
+ charset utf-8;
5
+ error_page 500 502 503 504 /50x.html;
6
+ location / {
7
+ root /usr/share/nginx/html;
8
+ try_files $uri /index.html;
9
+ }
10
+
11
+ location /api {
12
+ proxy_set_header X-Real-IP $remote_addr; #转发用户IP
13
+ proxy_pass http://app:3002;
14
+ }
15
+
16
+ proxy_set_header Host $host;
17
+ proxy_set_header X-Real-IP $remote_addr;
18
+ proxy_set_header REMOTE-HOST $remote_addr;
19
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
20
+ }
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/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/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>小师妹的私人助理</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>
license ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
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,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "chatgpt-web",
3
+ "version": "2.10.8",
4
+ "private": false,
5
+ "description": "aichat",
6
+ "author": "dvc890",
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
+ "highlight.js": "^11.7.0",
29
+ "html2canvas": "^1.4.1",
30
+ "katex": "^0.16.4",
31
+ "markdown-it": "^13.0.1",
32
+ "naive-ui": "^2.34.3",
33
+ "pinia": "^2.0.33",
34
+ "vue": "^3.2.47",
35
+ "vue-i18n": "^9.2.2",
36
+ "vue-router": "^4.1.6"
37
+ },
38
+ "devDependencies": {
39
+ "@antfu/eslint-config": "^0.35.3",
40
+ "@commitlint/cli": "^17.4.4",
41
+ "@commitlint/config-conventional": "^17.4.4",
42
+ "@iconify/vue": "^4.1.0",
43
+ "@types/crypto-js": "^4.1.1",
44
+ "@types/katex": "^0.16.0",
45
+ "@types/markdown-it": "^12.2.3",
46
+ "@types/markdown-it-link-attributes": "^3.0.1",
47
+ "@types/node": "^18.14.6",
48
+ "@vitejs/plugin-vue": "^4.0.0",
49
+ "autoprefixer": "^10.4.13",
50
+ "axios": "^1.3.4",
51
+ "crypto-js": "^4.1.1",
52
+ "eslint": "^8.35.0",
53
+ "husky": "^8.0.3",
54
+ "less": "^4.1.3",
55
+ "lint-staged": "^13.1.2",
56
+ "markdown-it-link-attributes": "^4.0.1",
57
+ "npm-run-all": "^4.1.5",
58
+ "postcss": "^8.4.21",
59
+ "rimraf": "^4.2.0",
60
+ "tailwindcss": "^3.2.7",
61
+ "typescript": "~4.9.5",
62
+ "vite": "^4.2.0",
63
+ "vite-plugin-pwa": "^0.14.4",
64
+ "vue-tsc": "^1.2.0"
65
+ },
66
+ "lint-staged": {
67
+ "*.{ts,tsx,vue}": [
68
+ "pnpm lint:fix"
69
+ ]
70
+ }
71
+ }
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
service/.env.example ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ # OpenAI API Model - https://platform.openai.com/docs/models
11
+ OPENAI_API_MODEL=
12
+
13
+ # Reverse Proxy
14
+ API_REVERSE_PROXY=
15
+
16
+ # timeout
17
+ TIMEOUT_MS=100000
18
+
19
+ # Rate Limit
20
+ MAX_REQUEST_PER_HOUR=
21
+
22
+ # Secret key
23
+ AUTH_SECRET_KEY=
24
+
25
+ # Socks Proxy Host
26
+ SOCKS_PROXY_HOST=
27
+
28
+ # Socks Proxy Port
29
+ SOCKS_PROXY_PORT=
30
+
31
+ # HTTPS PROXY
32
+ HTTPS_PROXY=
33
+
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,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "chatgpt-web-service",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "description": "aichat",
6
+ "author": "dvc890",
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": "node ./build/index.mjs",
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.1.2",
29
+ "dotenv": "^16.0.3",
30
+ "esno": "^0.16.3",
31
+ "express": "^4.18.2",
32
+ "express-rate-limit": "^6.7.0",
33
+ "https-proxy-agent": "^5.0.1",
34
+ "isomorphic-fetch": "^3.0.0",
35
+ "node-fetch": "^3.3.0",
36
+ "socks-proxy-agent": "^7.0.0"
37
+ },
38
+ "devDependencies": {
39
+ "@antfu/eslint-config": "^0.35.3",
40
+ "@types/express": "^4.17.17",
41
+ "@types/node": "^18.14.6",
42
+ "eslint": "^8.35.0",
43
+ "rimraf": "^4.3.0",
44
+ "tsup": "^6.6.3",
45
+ "typescript": "^4.9.5"
46
+ }
47
+ }
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,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 axios from 'axios'
9
+ import { sendResponse } from '../utils'
10
+ import { isNotEmptyString } from '../utils/is'
11
+ import type { ApiModel, ChatContext, ChatGPTUnofficialProxyAPIOptions, ModelConfig } from '../types'
12
+ import type { RequestOptions } from './types'
13
+
14
+ const { HttpsProxyAgent } = httpsProxyAgent
15
+
16
+ dotenv.config()
17
+
18
+ const ErrorCodeMessage: Record<string, string> = {
19
+ 401: '[OpenAI] 提供错误的API密钥 | Incorrect API key provided',
20
+ 403: '[OpenAI] 服务器拒绝访问,请稍后再试 | Server refused to access, please try again later',
21
+ 502: '[OpenAI] 错误的网关 | Bad Gateway',
22
+ 503: '[OpenAI] 服务器繁忙,请稍后再试 | Server is busy, please try again later',
23
+ 504: '[OpenAI] 网关超时 | Gateway Time-out',
24
+ 500: '[OpenAI] 服务器繁忙,请稍后再试 | Internal Server Error',
25
+ }
26
+
27
+ const timeoutMs: number = !isNaN(+process.env.TIMEOUT_MS) ? +process.env.TIMEOUT_MS : 30 * 1000
28
+
29
+ let apiModel: ApiModel
30
+
31
+ if (!isNotEmptyString(process.env.OPENAI_API_KEY) && !isNotEmptyString(process.env.OPENAI_ACCESS_TOKEN))
32
+ throw new Error('Missing OPENAI_API_KEY or OPENAI_ACCESS_TOKEN environment variable')
33
+
34
+ let api: ChatGPTAPI | ChatGPTUnofficialProxyAPI
35
+
36
+ (async () => {
37
+ // More Info: https://github.com/transitive-bullshit/chatgpt-api
38
+
39
+ if (isNotEmptyString(process.env.OPENAI_API_KEY)) {
40
+ const OPENAI_API_BASE_URL = process.env.OPENAI_API_BASE_URL
41
+ const OPENAI_API_MODEL = process.env.OPENAI_API_MODEL
42
+ const model = isNotEmptyString(OPENAI_API_MODEL) ? OPENAI_API_MODEL : 'gpt-3.5-turbo'
43
+
44
+ const options: ChatGPTAPIOptions = {
45
+ apiKey: process.env.OPENAI_API_KEY,
46
+ completionParams: { model },
47
+ debug: true,
48
+ }
49
+
50
+ // increase max token limit if use gpt-4
51
+ if (model.toLowerCase().includes('gpt-4')) {
52
+ // if use 32k model
53
+ if (model.toLowerCase().includes('32k')) {
54
+ options.maxModelTokens = 32768
55
+ options.maxResponseTokens = 8192
56
+ }
57
+ else {
58
+ options.maxModelTokens = 8192
59
+ options.maxResponseTokens = 2048
60
+ }
61
+ }
62
+
63
+ if (isNotEmptyString(OPENAI_API_BASE_URL))
64
+ options.apiBaseUrl = `${OPENAI_API_BASE_URL}/v1`
65
+
66
+ setupProxy(options)
67
+
68
+ api = new ChatGPTAPI({ ...options })
69
+ apiModel = 'ChatGPTAPI'
70
+ }
71
+ else {
72
+ const OPENAI_API_MODEL = process.env.OPENAI_API_MODEL
73
+ const options: ChatGPTUnofficialProxyAPIOptions = {
74
+ accessToken: process.env.OPENAI_ACCESS_TOKEN,
75
+ debug: true,
76
+ }
77
+ if (isNotEmptyString(OPENAI_API_MODEL))
78
+ options.model = OPENAI_API_MODEL
79
+
80
+ if (isNotEmptyString(process.env.API_REVERSE_PROXY))
81
+ options.apiReverseProxyUrl = process.env.API_REVERSE_PROXY
82
+
83
+ setupProxy(options)
84
+
85
+ api = new ChatGPTUnofficialProxyAPI({ ...options })
86
+ apiModel = 'ChatGPTUnofficialProxyAPI'
87
+ }
88
+ })()
89
+
90
+ async function chatReplyProcess(options: RequestOptions) {
91
+ const { message, lastContext, process, systemMessage } = options
92
+ try {
93
+ let options: SendMessageOptions = { timeoutMs }
94
+
95
+ if (apiModel === 'ChatGPTAPI') {
96
+ if (isNotEmptyString(systemMessage))
97
+ options.systemMessage = systemMessage
98
+ }
99
+
100
+ if (lastContext != null) {
101
+ if (apiModel === 'ChatGPTAPI')
102
+ options.parentMessageId = lastContext.parentMessageId
103
+ else
104
+ options = { ...lastContext }
105
+ }
106
+
107
+ const response = await api.sendMessage(message, {
108
+ ...options,
109
+ onProgress: (partialResponse) => {
110
+ process?.(partialResponse)
111
+ },
112
+ })
113
+
114
+ return sendResponse({ type: 'Success', data: response })
115
+ }
116
+ catch (error: any) {
117
+ const code = error.statusCode
118
+ global.console.log(error)
119
+ if (Reflect.has(ErrorCodeMessage, code))
120
+ return sendResponse({ type: 'Fail', message: ErrorCodeMessage[code] })
121
+ return sendResponse({ type: 'Fail', message: error.message ?? 'Please check the back-end console' })
122
+ }
123
+ }
124
+
125
+ async function fetchBalance() {
126
+ const OPENAI_API_KEY = process.env.OPENAI_API_KEY
127
+ const OPENAI_API_BASE_URL = process.env.OPENAI_API_BASE_URL
128
+
129
+ if (!isNotEmptyString(OPENAI_API_KEY))
130
+ return Promise.resolve('-')
131
+
132
+ const API_BASE_URL = isNotEmptyString(OPENAI_API_BASE_URL)
133
+ ? OPENAI_API_BASE_URL
134
+ : 'https://api.openai.com'
135
+
136
+ try {
137
+ const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${OPENAI_API_KEY}` }
138
+ const response = await axios.get(`${API_BASE_URL}/dashboard/billing/credit_grants`, { headers })
139
+ const balance = response.data.total_available ?? 0
140
+ return Promise.resolve(balance.toFixed(3))
141
+ }
142
+ catch {
143
+ return Promise.resolve('-')
144
+ }
145
+ }
146
+
147
+ async function chatConfig() {
148
+ const balance = await fetchBalance()
149
+ const reverseProxy = process.env.API_REVERSE_PROXY ?? '-'
150
+ const httpsProxy = (process.env.HTTPS_PROXY || process.env.ALL_PROXY) ?? '-'
151
+ const socksProxy = (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT)
152
+ ? (`${process.env.SOCKS_PROXY_HOST}:${process.env.SOCKS_PROXY_PORT}`)
153
+ : '-'
154
+ return sendResponse<ModelConfig>({
155
+ type: 'Success',
156
+ data: { apiModel, reverseProxy, timeoutMs, socksProxy, httpsProxy, balance },
157
+ })
158
+ }
159
+
160
+ function setupProxy(options: ChatGPTAPIOptions | ChatGPTUnofficialProxyAPIOptions) {
161
+ if (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT) {
162
+ const agent = new SocksProxyAgent({
163
+ hostname: process.env.SOCKS_PROXY_HOST,
164
+ port: process.env.SOCKS_PROXY_PORT,
165
+ })
166
+ options.fetch = (url, options) => {
167
+ return fetch(url, { agent, ...options })
168
+ }
169
+ }
170
+ else {
171
+ if (process.env.HTTPS_PROXY || process.env.ALL_PROXY) {
172
+ const httpsProxy = process.env.HTTPS_PROXY || process.env.ALL_PROXY
173
+ if (httpsProxy) {
174
+ const agent = new HttpsProxyAgent(httpsProxy)
175
+ options.fetch = (url, options) => {
176
+ return fetch(url, { agent, ...options })
177
+ }
178
+ }
179
+ }
180
+ }
181
+ }
182
+
183
+ function currentModel(): ApiModel {
184
+ return apiModel
185
+ }
186
+
187
+ export type { ChatContext, ChatMessage }
188
+
189
+ export { chatReplyProcess, chatConfig, currentModel }
service/src/chatgpt/types.ts ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import type { ChatMessage } from 'chatgpt'
2
+
3
+ export interface RequestOptions {
4
+ message: string
5
+ lastContext?: { conversationId?: string; parentMessageId?: string }
6
+ process?: (chat: ChatMessage) => void
7
+ systemMessage?: string
8
+ }
service/src/index.ts ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from 'express'
2
+ import type { RequestProps } from './types'
3
+ import type { ChatMessage } from './chatgpt'
4
+ import { chatConfig, chatReplyProcess, currentModel } from './chatgpt'
5
+ import { auth } from './middleware/auth'
6
+ import { limiter } from './middleware/limiter'
7
+ import { isNotEmptyString } from './utils/is'
8
+
9
+ const app = express()
10
+ const router = express.Router()
11
+
12
+ app.use(express.static('public'))
13
+ app.use(express.json())
14
+
15
+ app.all('*', (_, res, next) => {
16
+ res.header('Access-Control-Allow-Origin', '*')
17
+ res.header('Access-Control-Allow-Headers', 'authorization, Content-Type')
18
+ res.header('Access-Control-Allow-Methods', '*')
19
+ next()
20
+ })
21
+
22
+ router.post('/chat-process', [auth, limiter], async (req, res) => {
23
+ res.setHeader('Content-type', 'application/octet-stream')
24
+
25
+ try {
26
+ const { prompt, options = {}, systemMessage } = req.body as RequestProps
27
+ let firstChunk = true
28
+ await chatReplyProcess({
29
+ message: prompt,
30
+ lastContext: options,
31
+ process: (chat: ChatMessage) => {
32
+ res.write(firstChunk ? JSON.stringify(chat) : `\n${JSON.stringify(chat)}`)
33
+ firstChunk = false
34
+ },
35
+ systemMessage,
36
+ })
37
+ }
38
+ catch (error) {
39
+ res.write(JSON.stringify(error))
40
+ }
41
+ finally {
42
+ res.end()
43
+ }
44
+ })
45
+
46
+ router.post('/config', auth, async (req, res) => {
47
+ try {
48
+ const response = await chatConfig()
49
+ res.send(response)
50
+ }
51
+ catch (error) {
52
+ res.send(error)
53
+ }
54
+ })
55
+
56
+ router.post('/session', async (req, res) => {
57
+ try {
58
+ const AUTH_SECRET_KEY = process.env.AUTH_SECRET_KEY
59
+ const hasAuth = isNotEmptyString(AUTH_SECRET_KEY)
60
+ res.send({ status: 'Success', message: '', data: { auth: hasAuth, model: currentModel() } })
61
+ }
62
+ catch (error) {
63
+ res.send({ status: 'Fail', message: error.message, data: null })
64
+ }
65
+ })
66
+
67
+ router.post('/verify', async (req, res) => {
68
+ try {
69
+ const { token } = req.body as { token: string }
70
+ if (!token)
71
+ throw new Error('Secret key is empty')
72
+
73
+ if (process.env.AUTH_SECRET_KEY !== token)
74
+ throw new Error('密码错误 | Password key is invalid')
75
+
76
+ res.send({ status: 'Success', message: 'Verify successfully', data: null })
77
+ }
78
+ catch (error) {
79
+ res.send({ status: 'Fail', message: error.message, data: null })
80
+ }
81
+ })
82
+
83
+ app.use('', router)
84
+ app.use('/api', router)
85
+ app.set('trust proxy', 1)
86
+
87
+ app.listen(3002, () => globalThis.console.log('Server is running on port 3002'))
service/src/middleware/auth.ts ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { isNotEmptyString } from '../utils/is'
2
+
3
+ const auth = async (req, res, next) => {
4
+ const AUTH_SECRET_KEY = process.env.AUTH_SECRET_KEY
5
+ if (isNotEmptyString(AUTH_SECRET_KEY)) {
6
+ try {
7
+ const Authorization = req.header('Authorization')
8
+ if (!Authorization || Authorization.replace('Bearer ', '').trim() !== AUTH_SECRET_KEY.trim())
9
+ throw new Error('Error: 无访问权限 | No access rights')
10
+ next()
11
+ }
12
+ catch (error) {
13
+ res.send({ status: 'Unauthorized', message: error.message ?? 'Please authenticate.', data: null })
14
+ }
15
+ }
16
+ else {
17
+ next()
18
+ }
19
+ }
20
+
21
+ export { auth }
service/src/middleware/limiter.ts ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { rateLimit } from 'express-rate-limit'
2
+ import { isNotEmptyString } from '../utils/is'
3
+
4
+ const MAX_REQUEST_PER_HOUR = process.env.MAX_REQUEST_PER_HOUR
5
+
6
+ const maxCount = (isNotEmptyString(MAX_REQUEST_PER_HOUR) && !isNaN(Number(MAX_REQUEST_PER_HOUR)))
7
+ ? parseInt(MAX_REQUEST_PER_HOUR)
8
+ : 0 // 0 means unlimited
9
+
10
+ const limiter = rateLimit({
11
+ windowMs: 60 * 60 * 1000, // Maximum number of accesses within an hour
12
+ max: maxCount,
13
+ statusCode: 200, // 200 means success,but the message is 'Too many request from this IP in 1 hour'
14
+ message: async (req, res) => {
15
+ res.send({ status: 'Fail', message: 'Too many request from this IP in 1 hour', data: null })
16
+ },
17
+ })
18
+
19
+ export { limiter }
service/src/types.ts ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { FetchFn } from 'chatgpt'
2
+
3
+ export interface RequestProps {
4
+ prompt: string
5
+ options?: ChatContext
6
+ systemMessage: string
7
+ }
8
+
9
+ export interface ChatContext {
10
+ conversationId?: string
11
+ parentMessageId?: string
12
+ }
13
+
14
+ export interface ChatGPTUnofficialProxyAPIOptions {
15
+ accessToken: string
16
+ apiReverseProxyUrl?: string
17
+ model?: string
18
+ debug?: boolean
19
+ headers?: Record<string, string>
20
+ fetch?: FetchFn
21
+ }
22
+
23
+ export interface ModelConfig {
24
+ apiModel?: ApiModel
25
+ reverseProxy?: string
26
+ timeoutMs?: number
27
+ socksProxy?: string
28
+ httpsProxy?: string
29
+ balance?: string
30
+ }
31
+
32
+ export type ApiModel = 'ChatGPTAPI' | 'ChatGPTUnofficialProxyAPI' | undefined
service/src/utils/index.ts ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ interface SendResponseOptions<T = any> {
2
+ type: 'Success' | 'Fail'
3
+ message?: string
4
+ data?: T
5
+ }
6
+
7
+ export function sendResponse<T>(options: SendResponseOptions<T>) {
8
+ if (options.type === 'Success') {
9
+ return Promise.resolve({
10
+ message: options.message ?? null,
11
+ data: options.data ?? null,
12
+ status: options.type,
13
+ })
14
+ }
15
+
16
+ // eslint-disable-next-line prefer-promise-reject-errors
17
+ return Promise.reject({
18
+ message: options.message ?? 'Failed',
19
+ data: options.data ?? null,
20
+ status: options.type,
21
+ })
22
+ }
service/src/utils/is.ts ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export function isNumber<T extends number>(value: T | unknown): value is number {
2
+ return Object.prototype.toString.call(value) === '[object Number]'
3
+ }
4
+
5
+ export function isString<T extends string>(value: T | unknown): value is string {
6
+ return Object.prototype.toString.call(value) === '[object String]'
7
+ }
8
+
9
+ export function isNotEmptyString(value: any): boolean {
10
+ return typeof value === 'string' && value.length > 0
11
+ }
12
+
13
+ export function isBoolean<T extends boolean>(value: T | unknown): value is boolean {
14
+ return Object.prototype.toString.call(value) === '[object Boolean]'
15
+ }
16
+
17
+ export function isFunction<T extends (...args: any[]) => any | void | never>(value: T | unknown): value is T {
18
+ return Object.prototype.toString.call(value) === '[object Function]'
19
+ }
service/tsconfig.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2020",
4
+ "lib": [
5
+ "esnext"
6
+ ],
7
+ "allowJs": true,
8
+ "skipLibCheck": true,
9
+ "strict": false,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "esModuleInterop": true,
12
+ "module": "esnext",
13
+ "moduleResolution": "node",
14
+ "resolveJsonModule": true,
15
+ "isolatedModules": true,
16
+ "baseUrl": ".",
17
+ "outDir": "build",
18
+ "noEmit": true
19
+ },
20
+ "exclude": [
21
+ "node_modules",
22
+ "build"
23
+ ],
24
+ "include": [
25
+ "**/*.ts"
26
+ ]
27
+ }
service/tsup.config.ts ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { defineConfig } from 'tsup'
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ outDir: 'build',
6
+ target: 'es2020',
7
+ format: ['esm'],
8
+ splitting: false,
9
+ sourcemap: true,
10
+ minify: false,
11
+ shims: true,
12
+ dts: false,
13
+ })