Skip to content
This repository was archived by the owner on Feb 10, 2025. It is now read-only.

Commit f40048f

Browse files
authored
feat: 支持 accessToken 请求 web api 调用 (#80)
* feat: 支持 markdown 格式和图片 * perf: 重载的时候滚动条保持 * chore: version 2.5.2 * feat: 添加文字换行 * chore: 添加新封面 * chore: 更新 cover * feat: 支持 web api 的形式 * feat: 支持新模型和调整超时 * feat: 添加反向代理 * chore: 更新 README.md * feat: 添加超时和反向代理显示 * chore: version 2.6.0 * chore: update README
1 parent ac9536a commit f40048f

File tree

18 files changed

+236
-35
lines changed

18 files changed

+236
-35
lines changed

.env

+2
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
VITE_GLOB_API_URL=/api
33

44
VITE_APP_API_BASE_URL=http://localhost:3002/
5+
6+
VITE_GLOB_API_TIMEOUT=100000

.vscode/settings.json

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"chatgpt",
2626
"chenzhaoyu",
2727
"commitlint",
28+
"davinci",
2829
"dockerhub",
2930
"esno",
3031
"GPTAPI",

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## v2.6.0
2+
3+
`2023-02-21`
4+
### Feature
5+
- 新增对 `网页 accessToken` 调用 `ChatGPT`,更智能不过不太稳定 [#51](https://github.com/Chanzhaoyu/chatgpt-web/issues/51)
6+
- 前端页面设置按钮显示查看当前后端服务配置
7+
8+
### Enhancement
9+
- 新增 `TIMEOUT_MS` 环境变量设定后端超时时常(单位:毫秒)[#62](https://github.com/Chanzhaoyu/chatgpt-web/issues/62)
10+
111
## v2.5.2
212

313
`2023-02-21`

README.md

+60-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,43 @@
11
# ChatGPT Web
22

3-
使用 express 和 vue3 搭建的 ChartGPT 演示网页
3+
使用 `express``vue3` 搭建的支持 `ChatGPT` 双模型演示网页
44

55
![cover](./docs/cover.png)
66
![cover2](./docs/cover2.png)
77

8-
> 提示:目前 `OpenAI` 开放的模型最高只有 `GPT-3`,和现在网页所使用的 `GPT-3.5``GPT-4` 有很大差距,需要等官方开放最新的模型接口。
8+
## 介绍
9+
10+
支持双模型,提供了两种非官方 `ChatGPT API` 方法
11+
12+
| 方式 | 免费? | 可靠性 | 质量 |
13+
| ---- | ---- | ---- | ---- |
14+
| `ChatGPTAPI(GPT-3)` || 可靠 | 较笨 |
15+
| `ChatGPTUnofficialProxyAPI(网页 accessToken)` || 不可靠 | 聪明 |
16+
17+
***Note:*** 网页 `accessToken` 存在大约 8 小时,而且国内地区网络问题更推荐使用 `GPT-3` 的方式
18+
19+
对比:
20+
1. `ChatGPTAPI` 使用 `text-davinci-003` 通过官方`OpenAI`补全`API`模拟`ChatGPT`(最稳健的方法,但它不是免费的,并且没有使用针对聊天进行微调的模型)
21+
2. `ChatGPTUnofficialProxyAPI` 使用非官方代理服务器访问 `ChatGPT` 的后端`API`,绕过`Cloudflare`(使用真实的的`ChatGPT`,非常轻量级,但依赖于第三方服务器,并且有速率限制)
22+
23+
切换方式:
24+
1. 进入 `service/.env` 文件
25+
2. 使用 `OpenAI API Key` 请填写 `OPENAI_API_KEY` 字段 [(获取 apiKey)](https://platform.openai.com/overview)
26+
3. 使用 `Web API` 请填写 `OPENAI_ACCESS_TOKEN` 字段 [(获取 accessToken)](https://chat.openai.com/api/auth/session)
27+
4. 同时存在时以 `OpenAI API Key` 优先
28+
29+
反向代理:
30+
31+
`ChatGPTUnofficialProxyAPI`时可用 [详情](https://github.com/transitive-bullshit/chatgpt-api#reverse-proxy)
32+
33+
```shell
34+
# service/.env
35+
API_REVERSE_PROXY=
36+
```
937

1038
## 待实现路线
39+
[] 双模型
40+
1141
[] 多会话储存和上下文逻辑
1242

1343
[] 对代码等消息类型的格式化美化处理
@@ -34,12 +64,17 @@ node -v
3464
npm install pnpm -g
3565
```
3666

37-
### OpenAI API Key
38-
注册并获取 [OpenAI API key](https://platform.openai.com/overview) 并填写到本地环境变量
67+
### 填写密钥
68+
获取 `Openai Api Key``accessToken` 并填写本地环境变量 [跳转](#介绍)
69+
3970
```
4071
# service/.env 文件
4172
42-
OPENAI_API_KEY='Your key'
73+
# OpenAI API Key - https://platform.openai.com/overview
74+
OPENAI_API_KEY=
75+
76+
# change this to an `accessToken` extracted from the ChatGPT site's `https://chat.openai.com/api/auth/session` response
77+
OPENAI_ACCESS_TOKEN=
4378
```
4479

4580
## 安装依赖
@@ -60,7 +95,7 @@ pnpm install
6095
pnpm bootstrap
6196
```
6297

63-
## 运行
98+
## 测试环境运行
6499
### 后端服务
65100

66101
进入文件夹 `/service` 运行以下命令
@@ -69,7 +104,7 @@ pnpm bootstrap
69104
pnpm start
70105
```
71106

72-
### 网页
107+
### 前端网页
73108
根目录下运行以下命令
74109
```shell
75110
pnpm dev
@@ -78,6 +113,16 @@ pnpm dev
78113
## 打包
79114

80115
### 使用 Docker
116+
117+
### Docker 参数示例
118+
119+
- `OPENAI_API_KEY` 二选一
120+
- `OPENAI_ACCESS_TOKEN` 二选一,同时存在时,`OPENAI_API_KEY` 优先
121+
- `API_REVERSE_PROXY` 可选,设置 `OPENAI_ACCESS_TOKEN` 时可用 [参考](#介绍)
122+
- `TIMEOUT_MS` 超时,单位毫秒,可选
123+
124+
![docker](./docs/docker.png)
125+
81126
### Docker build & Run
82127

83128
```bash
@@ -106,7 +151,14 @@ services:
106151
ports:
107152
- 3002:3002
108153
environment:
154+
# 二选一
109155
OPENAI_API_KEY: xxxxxx
156+
# 二选一
157+
OPENAI_ACCESS_TOKEN: xxxxxx
158+
# 反向代理,可选
159+
API_REVERSE_PROXY: xxx
160+
# 超时,单位毫秒,可选
161+
TIMEOUT_MS: 60000
110162
```
111163
112164
@@ -129,7 +181,7 @@ pnpm prod
129181

130182
PS: 不进行打包,直接在服务器上运行 `pnpm start` 也可
131183

132-
### 前端打包
184+
### 前端网页
133185

134186
1、修改根目录下 `.env` 内 `VITE_APP_API_BASE_URL` 为你的实际后端接口地址
135187

docs/docker.png

108 KB
Loading

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "chatgpt-web",
3-
"version": "2.5.2",
3+
"version": "2.6.0",
44
"private": false,
55
"description": "ChatGPT Web",
66
"author": "ChenZhaoYu <[email protected]>",

service/.env

+9
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,11 @@
11
# OpenAI API Key - https://platform.openai.com/overview
22
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+
# Reverse Proxy
8+
API_REVERSE_PROXY=
9+
10+
# timeout
11+
TIMEOUT_MS=60000

service/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"common:cleanup": "rimraf node_modules && rimraf pnpm-lock.yaml"
2424
},
2525
"dependencies": {
26-
"chatgpt": "^4.7.1",
26+
"chatgpt": "^4.7.2",
2727
"dotenv": "^16.0.3",
2828
"esno": "^0.16.3",
2929
"express": "^4.18.2",

service/pnpm-lock.yaml

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

service/src/chatgpt.ts

+39-9
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,46 @@
11
import * as dotenv from 'dotenv'
22
import 'isomorphic-fetch'
33
import type { ChatGPTAPI, SendMessageOptions } from 'chatgpt'
4+
import { ChatGPTUnofficialProxyAPI } from 'chatgpt'
45
import { sendResponse } from './utils'
56

7+
dotenv.config()
8+
9+
let apiModel: 'ChatGPTAPI' | 'ChatGPTUnofficialProxyAPI' | undefined
10+
611
export interface ChatContext {
712
conversationId?: string
813
parentMessageId?: string
914
}
1015

11-
dotenv.config()
12-
13-
const apiKey = process.env.OPENAI_API_KEY
16+
const timeoutMs: number = !isNaN(+process.env.TIMEOUT_MS) ? +process.env.TIMEOUT_MS : 30 * 1000
1417

15-
if (apiKey === undefined)
16-
throw new Error('OPENAI_API_KEY is not defined')
18+
if (!process.env.OPENAI_API_KEY && !process.env.OPENAI_ACCESS_TOKEN)
19+
throw new Error('Missing OPENAI_API_KEY or OPENAI_ACCESS_TOKEN environment variable')
1720

18-
let api: ChatGPTAPI
21+
let api: ChatGPTAPI | ChatGPTUnofficialProxyAPI
1922

2023
// To use ESM in CommonJS, you can use a dynamic import
2124
(async () => {
2225
// More Info: https://github.com/transitive-bullshit/chatgpt-api
2326
const { ChatGPTAPI } = await import('chatgpt')
24-
api = new ChatGPTAPI({ apiKey: process.env.OPENAI_API_KEY })
27+
28+
if (process.env.OPENAI_API_KEY) {
29+
api = new ChatGPTAPI({ apiKey: process.env.OPENAI_API_KEY })
30+
apiModel = 'ChatGPTAPI'
31+
}
32+
else {
33+
let options = {}
34+
35+
if (process.env.API_REVERSE_PROXY)
36+
options = { apiReverseProxyUrl: process.env.API_REVERSE_PROXY }
37+
38+
api = new ChatGPTUnofficialProxyAPI({
39+
accessToken: process.env.OPENAI_ACCESS_TOKEN,
40+
...options,
41+
})
42+
apiModel = 'ChatGPTUnofficialProxyAPI'
43+
}
2544
})()
2645

2746
async function chatReply(
@@ -32,7 +51,7 @@ async function chatReply(
3251
return sendResponse({ type: 'Fail', message: 'Message is empty' })
3352

3453
try {
35-
let options: SendMessageOptions = { timeoutMs: 30 * 1000 }
54+
let options: SendMessageOptions = { timeoutMs }
3655

3756
if (lastContext)
3857
options = { ...lastContext }
@@ -46,4 +65,15 @@ async function chatReply(
4665
}
4766
}
4867

49-
export { chatReply }
68+
async function chatConfig() {
69+
return sendResponse({
70+
type: 'Success',
71+
data: {
72+
apiModel,
73+
reverseProxy: process.env.API_REVERSE_PROXY,
74+
timeoutMs,
75+
},
76+
})
77+
}
78+
79+
export { chatReply, chatConfig }

service/src/index.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import express from 'express'
22
import type { ChatContext } from './chatgpt'
3-
import { chatReply } from './chatgpt'
3+
import { chatConfig, chatReply } from './chatgpt'
44

55
const app = express()
66
const router = express.Router()
@@ -26,6 +26,16 @@ router.post('/chat', async (req, res) => {
2626
}
2727
})
2828

29+
router.post('/config', async (req, res) => {
30+
try {
31+
const response = await chatConfig()
32+
res.send(response)
33+
}
34+
catch (error) {
35+
res.send(error)
36+
}
37+
})
38+
2939
app.use('', router)
3040
app.use('/api', router)
3141

src/api/index.ts

+6
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,9 @@ export function fetchChatAPI<T = any>(
1212
signal,
1313
})
1414
}
15+
16+
export function fetchChatConfig<T = any>() {
17+
return post<T>({
18+
url: '/config',
19+
})
20+
}
+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<script setup lang='ts'>
2+
import { computed, ref, watch } from 'vue'
3+
import { NCard, NModal } from 'naive-ui'
4+
import { fetchChatConfig } from '@/api'
5+
6+
interface Props {
7+
visible: boolean
8+
}
9+
10+
interface Emit {
11+
(e: 'update:visible', visible: boolean): void
12+
}
13+
14+
interface ConfigState {
15+
timeoutMs?: number
16+
reverseProxy?: string
17+
apiModel?: string
18+
}
19+
20+
const props = defineProps<Props>()
21+
22+
const emit = defineEmits<Emit>()
23+
24+
const show = computed({
25+
get() {
26+
return props.visible
27+
},
28+
set(visible: boolean) {
29+
emit('update:visible', visible)
30+
},
31+
})
32+
33+
const config = ref<ConfigState>()
34+
35+
async function fetchConfig() {
36+
try {
37+
const { data } = await fetchChatConfig<ConfigState>()
38+
config.value = data
39+
}
40+
catch (error) {
41+
// ...
42+
}
43+
}
44+
45+
watch(
46+
() => props.visible,
47+
(val) => {
48+
if (val)
49+
fetchConfig()
50+
},
51+
)
52+
</script>
53+
54+
<template>
55+
<NModal v-model:show="show" style="width: 80%; max-width: 460px;">
56+
<NCard>
57+
<div class="space-y-4">
58+
<h1 class="text-xl font-bold">
59+
当前后台设置
60+
</h1>
61+
<p>API方式:{{ config?.apiModel ?? '-' }}</p>
62+
<p>反向代理:{{ config?.reverseProxy ?? '-' }}</p>
63+
<p>超时时间:{{ config?.timeoutMs ?? '-' }}</p>
64+
</div>
65+
</NCard>
66+
</NModal>
67+
</template>

0 commit comments

Comments
 (0)