├── .dockerignore
├── requirements.txt
├── Dockerfile
├── main.py
├── .github
└── workflows
│ └── docker-image.yml
├── templates
└── chat.html
├── static
├── script.js
└── style.css
└── README.md
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | Dockerfile
3 | README.md
4 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | revChatGPT
2 | flask
3 | gunicorn
4 | gevent
5 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:slim
2 | WORKDIR /chatgpt-html
3 | COPY . .
4 | RUN pip install --no-cache-dir -r requirements.txt
5 |
6 | CMD ["gunicorn", "-b", "0.0.0.0:8088", "main:server", "--timeout", "200", "--worker-class", "gevent"]
7 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import json
2 | from revChatGPT.V1 import Chatbot
3 | from flask import Flask, request, render_template
4 |
5 | server = Flask(__name__)
6 |
7 | # get config
8 | with open("config.json", "r") as f: config = json.load(f)
9 |
10 | # init chatbot
11 | chatbot = Chatbot(config)
12 |
13 | def generate_response(prompt):
14 | try:
15 | for data in chatbot.ask(prompt):
16 | response = data["message"]
17 | return response
18 | except BaseException as e:
19 | return str(e)
20 |
21 | @server.route("/")
22 | def home():
23 | chatbot.reset_chat()
24 | return render_template("chat.html")
25 |
26 | @server.route("/get")
27 | def get_bot_response():
28 | user_text = request.args.get('msg')
29 | return str(generate_response(user_text))
30 |
31 | if __name__ == '__main__':
32 | server.run(debug=False, host='0.0.0.0', port=8088)
33 |
--------------------------------------------------------------------------------
/.github/workflows/docker-image.yml:
--------------------------------------------------------------------------------
1 | name: ci
2 |
3 | on:
4 | push:
5 | branches:
6 | - "main"
7 |
8 | jobs:
9 | docker:
10 | runs-on: ubuntu-latest
11 | steps:
12 | -
13 | name: Checkout
14 | uses: actions/checkout@v3
15 | -
16 | name: Set up QEMU
17 | uses: docker/setup-qemu-action@v2
18 | -
19 | name: Set up Docker Buildx
20 | uses: docker/setup-buildx-action@v2
21 | -
22 | name: Login to Docker Hub
23 | uses: docker/login-action@v2
24 | with:
25 | username: ${{ secrets.DOCKERHUB_USERNAME }}
26 | password: ${{ secrets.DOCKERHUB_TOKEN }}
27 | -
28 | name: Build and push
29 | uses: docker/build-push-action@v4
30 | with:
31 | context: .
32 | platforms: linux/amd64, linux/arm64
33 | push: true
34 | tags: sheepgreen/chatgpt-html:latest
35 |
--------------------------------------------------------------------------------
/templates/chat.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ChatGPT
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/static/script.js:
--------------------------------------------------------------------------------
1 | // 加入回车提交支持,shift+回车换行
2 | var input = document.getElementById("chatinput");
3 | input.addEventListener("keydown", function (event) {
4 | if (event.keyCode === 13 && !event.shiftKey) {
5 | event.preventDefault();
6 | document.getElementById("sendbutton").click();
7 | }
8 | });
9 |
10 | // Add your JavaScript here
11 | document.getElementById("sendbutton").addEventListener("click", function () {
12 | // Get the user's message from the input field
13 | var message = document.getElementById("chatinput").value;
14 | var chatlog = document.getElementById("chatlog");
15 | var response = document.createElement("div");
16 | if (message.length < 1) {
17 | response.innerHTML = "🤔
🤖
Message cannot be null\n问题不能为空";
18 | // 给response添加一个动画类
19 | response.classList.add("animate__animated", "animate__lightSpeedInLeft", "dark");
20 | chatlog.appendChild(response);
21 | response.scrollIntoView({ behavior: 'smooth', block: 'end' });
22 | } else {
23 | // Clear the input field
24 | document.getElementById("chatinput").value = "";
25 | // Send the message to the chatbot
26 | var xhr = new XMLHttpRequest();
27 | xhr.open("GET", "/get?msg=" + message);
28 | xhr.send();
29 | // Display "typing" message while the bot is thinking
30 | var typingMessage = document.createElement("div");
31 | // 新增一个小圆点元素,添加typing类
32 | var dot = document.createElement("div");
33 | dot.classList.add("typing");
34 | typingMessage.appendChild(dot);
35 | chatlog.appendChild(typingMessage);
36 | typingMessage.scrollIntoView({ behavior: 'smooth', block: 'end' });
37 | xhr.onload = function () {
38 | // Append the chatbot's response to the chatlog
39 | chatlog.removeChild(typingMessage);
40 | response.innerHTML = "🤔
" + message + "
🤖" + marked.parse(xhr.responseText);
41 | // 给response添加一个动画类
42 | response.classList.add("animate__animated", "animate__lightSpeedInLeft", "dark");
43 | chatlog.appendChild(response);
44 | response.scrollIntoView({ behavior: 'smooth', block: 'end' });
45 | }
46 | }
47 | });
48 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # chatgpt-html
2 | ### 使用[acheong08](https://github.com/acheong08/ChatGPT)对接官方ChatGPT接口,实现简单HTML网页版在线聊天
3 | > 该版本基于`ChatGPT`网页端代理开发(免费),想使用ChatGPT API KEY(付费)的请访问[chatgpt-web](https://github.com/slippersheepig/chatgpt-web)
4 | ### 注意
5 | > 使用该项目的前提是你的服务器IP没有被BAN,由于我自己的服务器IP已BAN,无法测试项目是否可用,请自行尝试
6 | ## 特性
7 | - 文件结构简单,主要面向小白用户
8 | - 功能不多,但核心的连续对话、多用户会话隔离、markdown格式输出都具备
9 | ## 部署
10 | #### 使用Docker Compose
11 | > 以下所有文件放同一目录
12 | - 新建`config.json`文件,粘贴以下代码并保存
13 | ```bash
14 | {
15 | "__comment01__": "邮箱、session_token和access_token三选一",
16 | "__comment02__": "邮箱认证(暂仅支持普通方式注册的账号,不支持谷歌或微软快捷登录)",
17 | "email": "",
18 | "password": "",
19 | "__comment03__": "session_token认证(不受账号注册方式影响)",
20 | "session_token": "",
21 | "__comment04__": "access_token认证(不受账号注册方式影响)",
22 | "access_token": "",
23 |
24 | "__comment05__": "以下为选填字段",
25 | "__comment06__": "通过代理连接代理端(作者服务器被墙过,代理好像只能用无密码认证的socks5或者http,请自行测试)",
26 | "proxy": "",
27 | "__comment07__": "使用付费openai账号(官方称速度更快,无频率限制,将false改为true)",
28 | "paid": false
29 | }
30 | ```
31 | - session_token获取方法(随时过期)
32 | 1. Go to https://chat.openai.com/chat and open the developer tools by `F12`.
33 | 2. Find the `__Secure-next-auth.session-token` cookie in `Application` > `Storage` > `Cookies` > `https://chat.openai.com`.
34 | 3. Copy the value in the `Cookie Value` field.
35 | - access_token获取方法(据说可以持续2周不过期)
36 |
37 | 登录ChatGPT官方网页版后再打开https://chat.openai.com/api/auth/session
38 |
39 | - 新建`docker-compose.yml`配置文件,粘贴以下内容并保存
40 | ```bash
41 | services:
42 | chatgpt:
43 | image: sheepgreen/chatgpt-html
44 | container_name: htmchat
45 | # environment:
46 | # - CHATGPT_BASE_URL=你的代理服务端地址(不填默认使用作者服务器,目前偶尔会不可用)
47 | volumes:
48 | - ./config.json:/chatgpt-html/config.json
49 | # - ./chat.html:/chatgpt-html/templates/chat.html #默认内置我的UI,如需替换自用网页请取消注释
50 | ports:
51 | - "9999:8088" #8088为容器内端口,不可更换;9999为外部端口,可自行更换
52 | restart: always
53 | ```
54 | - 输入`docker-compose up -d`即启动成功
55 | ## 注意事项
56 | - 访问地址为http://ip:port
57 | - 修改`chat.html`文件后,需要docker restart htmchat才能生效
58 | ## 其他相关
59 | - [ChatGPT电报机器人](https://github.com/slippersheepig/chatgpt-telegram-bot),[ChatGPT企业微信应用机器人](https://github.com/slippersheepig/chatgpt-bizwechat-bot),[ChatGPT的QQ频道机器人DOCKER版](https://github.com/slippersheepig/QQChannelChatGPT),[微软BING电报机器人DOCKER版](https://github.com/slippersheepig/BingChatBot),[谷歌BARD网页版](https://github.com/slippersheepig/bard-web),[谷歌BARD电报机器人](https://github.com/slippersheepig/bard-telegram-bot)
60 | - 出于玩玩bing的chatgpt心态,按[waylaidwanderer](https://github.com/waylaidwanderer/PandoraAI)搞了一套[测试站](https://ai.sheepig.top)(需要先点击聊天框左边的图标切换模型,默认模型是API,我的KEY没额度了),`Bing`就是GPT-4,`Sydney`是“破解”过的Bing(没有每轮对话最多15次和每天对话最多150次的限制,但是智商差一点)。另外此项目代码也有bug需要完善(如果你去体验会发现的),不做详细介绍。
61 | 
62 | 
63 | - 基于[pandora](https://github.com/pengzhile/pandora)制作了官方OPENAI CHATGPT[高仿站](https://v.sheepig.top)
64 |
--------------------------------------------------------------------------------
/static/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | body {
8 | background-color: #edeff2;
9 | font-family: "Calibri", "Roboto", sans-serif;
10 | }
11 |
12 | @media (prefers-color-scheme: dark) {
13 | body {
14 | background: black;
15 | color: white;
16 | }
17 | }
18 |
19 | .chat_window {
20 | position: absolute;
21 | width: calc(100% - 20px);
22 | max-width: 800px;
23 | border-radius: 10px;
24 | background-color: #f8f8f8;
25 | left: 50%;
26 | top: 50%;
27 | transform: translate(-50%, -50%);
28 | box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
29 | overflow: hidden;
30 | }
31 |
32 | .top_menu {
33 | background-color: #fff;
34 | width: 100%;
35 | padding: 20px 0 15px;
36 | box-shadow: 0 1px 30px rgba(0, 0, 0, 0.1);
37 | }
38 |
39 | .top_menu .title {
40 | text-align: center;
41 | color: #bcbdc0;
42 | font-size: 20px;
43 | }
44 |
45 | .messages {
46 | position: relative;
47 | list-style: none;
48 | padding: 20px 10px 0;
49 | overflow-x: hidden;
50 | overflow-y: auto;
51 | }
52 |
53 | .messages div {
54 | text-align: left;
55 | color: green;
56 | }
57 |
58 | .messages pre {
59 | white-space: pre-wrap;
60 | word-wrap: break-word;
61 | }
62 |
63 | .bottom_wrapper {
64 | clear: both;
65 | position: relative;
66 | width: 100%;
67 | background-color: #f6f6f6;
68 | padding: 20px;
69 | border-radius: 0 0 10px 10px;
70 | }
71 |
72 | .bottom_wrapper textarea {
73 | width: calc(100% - 80px);
74 | border: none;
75 | padding: 10px;
76 | border-radius: 3px;
77 | resize: none;
78 | font-size: 16px;
79 | height: 40px; /* 设置输入框的高度 */
80 | vertical-align: middle; /* 垂直居中 */
81 | }
82 |
83 | .bottom_wrapper button {
84 | width: 60px;
85 | height: 40px;
86 | margin-left: 10px; /* 增加左边距 */
87 | font-size: 16px;
88 | border: none;
89 | border-radius: 3px;
90 | background-color: #4CAF50;
91 | color: white;
92 | cursor: pointer;
93 | vertical-align: middle; /* 垂直居中 */
94 | }
95 |
96 | .bottom_wrapper button:hover {
97 | background-color: #3e8e41;
98 | }
99 |
100 | .bottom_wrapper button:focus {
101 | outline: none;
102 | }
103 |
104 | /* 新增一个typing类,用于显示动画效果 */
105 | .typing {
106 | width: 20px;
107 | height: 20px;
108 | border-radius: 50%;
109 | background-color: green;
110 | position: relative;
111 | animation: typing 1.5s infinite;
112 | }
113 |
114 | .dark {
115 | color: #fff;
116 | }
117 |
118 | @media (prefers-color-scheme: dark) {
119 | .chat_window {
120 | background-color: #333;
121 | box-shadow: 0 10px 20px rgba(255, 255, 255, 0.1);
122 | }
123 |
124 | .top_menu {
125 | background-color: #222;
126 | box-shadow: 0 1px 30px rgba(255, 255, 255, 0.1);
127 | }
128 |
129 | .top_menu .title {
130 | color: #ccc;
131 | }
132 |
133 | .bottom_wrapper {
134 | background-color: #222;
135 | box-shadow: 0 1px 30px;
136 | rgba(255, 255, 255, 0.1);
137 | }
138 |
139 | .bottom_wrapper textarea {
140 | background-color: #333;
141 | color: #fff;
142 | }
143 |
144 | .bottom_wrapper button {
145 | background-color: #4CAF50;
146 | }
147 |
148 | .bottom_wrapper button:hover {
149 | background-color: #3e8e41;
150 | }
151 | }
152 |
153 | /* 定义typing动画,让小圆点在水平方向上移动 */
154 | @keyframes typing {
155 | 0% {
156 | left: 0;
157 | }
158 | 50% {
159 | left: calc(100% - 20px);
160 | }
161 | 100% {
162 | left: 0;
163 | }
164 | }
165 |
--------------------------------------------------------------------------------