跳到主要内容

Share-plus-chatgpt 搭建及使用

· 阅读需 6 分钟

Share-plus-chatgpt项目部署

1、创建应用目录并创建配置文件

cd ~
mkdir cws && cd cws
mkdir -p data/config

export MONGODB_PASSWORD=your_pass # MongoDB 密码
export INITIAL_ADMIN_PASSWORD=your_pass # 初始管理员密码

# 运行一次 Docker 容器,创建配置文件:
docker run -it --rm \
-v $PWD/data/config:/tmp/config \
ghcr.io/moeakwak/chatgpt-web-share:latest \
python /app/backend/manage.py create_config -O /tmp/config --generate-secrets --mongodb-url "mongodb://cws:${MONGODB_PASSWORD}@mongo:27017" --initial-admin-password "${INITIAL_ADMIN_PASSWORD}" --chatgpt-base-url http://ninja:7999/backend-api/

2、编辑 docker-compose 文件

echo "TZ=Asia/Shanghai" > .env
echo "MONGO_INITDB_DATABASE=cws" >> .env
echo "MONGO_INITDB_ROOT_USERNAME=cws" >> .env
echo "MONGO_INITDB_ROOT_PASSWORD=your_pass" >> .env

docker-compose.yml

version: "3"

services:
chatgpt-web-share:
image: ghcr.io/chatpire/chatgpt-web-share:latest
container_name: cws
restart: unless-stopped
ports:
- 5000:80
volumes:
- ./data:/app/backend/data
environment:
- TZ=${TZ}
- CWS_CONFIG_DIR=/app/backend/data/config
depends_on:
- mongo

mongo:
container_name: mongo
image: mongo:6.0
restart: always
# ports:
# - 27017:27017
volumes:
- ./mongo_data:/data/db
environment:
MONGO_INITDB_DATABASE: ${MONGO_INITDB_DATABASE}
MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}

ninja:
image: ghcr.io/gngpp/ninja:latest
container_name: ninja
restart: unless-stopped
command: run --disable-webui
ports:
- "7999:7999"
environment:
- TZ=Asia/Shanghai
volumes:
- "./har/gpt3:/root/.gpt3"
- "./har/gpt4:/root/.gpt4"

启动服务

docker-compose up -d 

3、配置 ChatGPT 代理

Ninja 文档:https://github.com/gngpp/ninja/blob/main/doc/readme_zh.md


简单来说,你需要:

  1. 在 CWS 的配置中将 ChatGPT 代理地址设置为 http://ninja:7999/backend-api/。(这应当在上一步已经完成了)
  2. 参考 ninja 的文档获取 HAR 文件,将 HAR 文件放在 cws/har/gpt3(假如 GPT 3.5 模型出现验证码) 和 cws/har/gpt4 下。你可以直接上传文件到相应目录,也可以使用 Ninja 提供的网页上传(访问 http://<你的服务器 IP>:7999/har/upload)。
  3. 访问 https://chat.openai.com/api/auth/session 并复制其中的 access token 项内容,在 CWS 的后台设置中的 credentials 中填入。
ArkoseLabs

发送GPT-4/GPT-3.5/创建API-Key对话需要Arkose Token作为参数发送,支持的解决方案暂时只有两种

1、使用HAR 支持HAR特征池化,可同时上传多个HAR,使用轮训策略 ChatGPT 官网发送一次 GPT-4 会话消息,浏览器 F12 下载 https://tcr9i.chat.openai.com/fc/gt2/public_key/35536E1E-65B4-4D96-9D97-6ADB7EFF8147 接口的HAR日志记录文件,使用启动参数 --arkose-gpt4-har-dir 指定HAR目录路径使用(不指定路径则使用默认路径~/.gpt4,可直接上传更新HAR),同理GPT-3.5和其他类型也是一样方法。支持WebUI上传更新HAR,请求路径:/har/upload,可选上传身份验证参数:--arkose-har-upload-key

2、使用YesCaptcha / CapSolver 平台进行验证码解析,启动参数--arkose-solver选择平台(默认使用YesCaptcha),--arkose-solver-key 填写Client Key

两种方案都使用,优先级是:HAR > YesCaptcha / CapSolver YesCaptcha / CapSolver推荐搭配HAR使用,出验证码则调用解析器处理,验证后HAR使用更持久 目前OpenAI已经更新登录需要验证Arkose Token,解决方式同GPT-4,填写启动参数指定HAR文件--arkose-auth-har-dir。创建API-Key需要上传Platform相关的HAR特征文件,获取方式同上。

OpenAI取消对GPT-3.5进行Arkose验证,可以不上传HAR特征文件使用(已上传的不影响),兼容后续可能会再次开启Arkose验证,需要加上启动参数--arkose-gpt3-experiment进行开启GPT-3.5模型Arkose验证处理,WebUI不受影响。如果遇到418 I'm a teapot,可以开启--arkose-gpt3-experiment,同时需要上传HAR特征,如果没有GPT-3.5的特征,GPT-4的特征也可以使用,如果还不行,则尝试开启--arkose-gpt3-experiment-solver,可能会使用第三方平台解决验证码。

4、接下来要做的事

到这里,CWS 已经部署完成。要继续使用,你可能需要:

  • 在服务器上配置反向代理,配置域名和 https 加密
  • 关闭 Ninja 对外的 7999 端口,比如在 docker compose 配置中注释掉它,或者使用防火墙限制访问

5、升级及维护

docker-compose pull && docker-compose up -d
# 在更新前,建议备份数据,并且确保设置中已经打开 run_migration 选项,以便在更新后自动执行数据库迁移。

6、反向代理

提供三种方式

6.1 设置反向代理和 SSL

为了向外公开站点,你应当使用 https 协议。我们推荐使用 Caddy 作为反向代理,它可以自动申请证书并配置 https。

下面是一个使用 Cloudflare 的 API 自动进行证书验证的 Caddyfile 例子:

{
email `<YOUR_EMAIL>`
storage file_system {
root /root/caddy/certs/
}
log error {
output file /root/caddy/logs/error.log {
roll_size 20MB
roll_keep 5
roll_keep_for 240h
}
level ERROR
}
acme_dns cloudflare API_TOKEN
}

your-cws-site.com {
reverse_proxy :5000
}
6.2 使用 Cloudflare

推荐使用 Cloudflare 加速站点,从而隐藏服务器 IP。如果你将域名 DNS 托管在 Cloudflare,在开启 Proxy 之后,你有如下方式使用 https:

  • 在 Cloudflare 中设置站点 https 跳转,并在 SSL/TLS 选项中设置加密类型为 flexible;服务器中反向代理对外使用 http 协议。如果你想更安全,可以将其配置为只允许 Cloudflare 服务器访问。这样的好处是开启 https 较为简单,不用续证书。
  • 在 SSL/TLS 选项中设置加密类型为 Full,服务器反向代理配置有效的 SSL 证书,对外使用 https。
6.3 使用 nginx
http {
...
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
...
}

server {
listen 443 ssl;
server_name plus.domain.com;

ssl_certificate /etc/nginx/ssl/plus.doamin.com.pem;
ssl_certificate_key /etc/nginx/ssl/plus.domain.com.key;

location / { # 目前已经实现的子系统
proxy_http_version 1.1; #WebSocket
proxy_set_header Upgrade $http_upgrade; #WebSocket
proxy_set_header Connection $connection_upgrade; #WebSocket

proxy_pass http://127.0.0.1:5000;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;

proxy_buffering off;
chunked_transfer_encoding on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 60;

}
}

server {
listen 80;
server_name plus.domain.com;

location = / {
rewrite ^(.+)$ https://plus.domain.com$1 redirect;
}
}

结合阿里云DNS实现动态DNS

· 阅读需 3 分钟

动态DNS 实现

项目已放Github,欢迎Star。 https://github.com/MasonSRE/ddns

编写脚本获取公网IP地址,实时更新DNS记录

编写 get_ip_dns.py

import time
import logging
import requests
import json
from aliyunsdkcore.client import AcsClient
from aliyunsdkalidns.request.v20150109 import UpdateDomainRecordRequest
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkalidns.request.v20150109 import DescribeDomainRecordsRequest, DescribeDomainRecordInfoRequest


# 阿里云API凭证
access_key_id = 'your_access_key_id'
access_key_secret = 'your_access_key_secret'
region_id = 'cn-hangzhou' # 你的阿里云区域ID (可以不做修改)

# 域名和记录信息
domain_name = 'example.com' # 你的域名
sub_domain = 'www' # 子域名,例如www

# 设置日志记录
logging.basicConfig(level=logging.INFO)

def get_public_ip():
try:
response = requests.get('https://api.ipify.org?format=json')
response.raise_for_status() # 抛出HTTP错误
ip = response.json()['ip']
logging.info(f'Public IP retrieved: {ip}')
return ip
except requests.exceptions.RequestException as e:
logging.error(f'Failed to retrieve public IP: {e}')
return None

def get_current_dns_record(client, domain_name, sub_domain):
request = DescribeDomainRecordsRequest.DescribeDomainRecordsRequest()
request.set_DomainName(domain_name)
try:
response = client.do_action_with_exception(request)
records = json.loads(response)['DomainRecords']['Record']
for record in records:
if record['RR'] == sub_domain and record['Type'] == 'A':
return record['RecordId'], record['Value']
return None, None
except ServerException as e:
logging.error(f'Failed to get the current DNS record: {e}')
return None, None

def update_dns_record(client, record_id, sub_domain, ip):
request = UpdateDomainRecordRequest.UpdateDomainRecordRequest()
request.set_RecordId(record_id)
request.set_RR(sub_domain)
request.set_Type('A')
request.set_Value(ip)
try:
client.do_action_with_exception(request)
logging.info(f'Updated DNS record to {ip}')
except ServerException as e:
logging.error(f'Failed to update DNS record: {e}')

def add_dns_record(client, domain_name, sub_domain, ip):
request = AddDomainRecordRequest.AddDomainRecordRequest()
request.set_DomainName(domain_name)
request.set_RR(sub_domain)
request.set_Type('A')
request.set_Value(ip)
try:
client.do_action_with_exception(request)
logging.info(f'Added DNS record: {sub_domain}.{domain_name} -> {ip}')
except ServerException as e:
logging.error(f'Failed to add DNS record: {e}')

def update_dns_record_if_needed(client, domain_name, sub_domain, new_ip):
record_id, current_ip = get_current_dns_record(client, domain_name, sub_domain)
if record_id is None:
logging.warning(f'No existing DNS record found for {sub_domain}.{domain_name}, adding a new record.')
add_dns_record(client, domain_name, sub_domain, new_ip)
return
if current_ip != new_ip:
update_dns_record(client, record_id, sub_domain, new_ip)

def main():
client = AcsClient(access_key_id, access_key_secret, region_id)

while True:
new_ip = get_public_ip()
if new_ip is not None:
update_dns_record_if_needed(client, domain_name, sub_domain, new_ip)
time.sleep(10) # 等待10秒再检查

if __name__ == '__main__':
main()

检查公网IP并更新 DNS 纪录

此脚本将获取该服务器的公网IP,并且修改阿里云对应的DNS解析的A纪录。

  • 非常适用于家用网络,公网IP改变时也会同步修改至Aliyun dns解析
  • 手动误修改此DNS解析时,也会进行操作IP对比,同时进行修改 dns 解析

1、下载依赖包

pip3 install requests
pip3 install aliyun-python-sdk-core
pip3 install aliyun-python-sdk-alidns

2、修改配置

# 阿里云API凭证
access_key_id = 'your_access_key_id'
access_key_secret = 'your_access_key_secret'
region_id = 'cn-hangzhou' # 你的阿里云区域ID(可以不做修改)

# 域名和记录信息
domain_name = 'example.com' # 你的域名
sub_domain = 'www' # 子域名,例如www

3、运行脚本

python3 get_ip_dns.py

Locust 部署压测

· 阅读需 2 分钟

Locust 部署压测

Python环境安装

要求 python 3.7+ 此处安装3.9版本测试

1、安装 Python 3.9

# 安装必要的开发工具和库
yum groupinstall -y "Development Tools"
yum install -y openssl-devel bzip2-devel libffi-devel zlib-devel

# 下载源码
curl -O https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz
tar -xf Python-3.9.0.tgz
cd Python-3.9.0

# 配置并编译源代码
./configure --enable-optimizations
make -j$(nproc)
make altinstall # 使用 make altinstall 而不是 make install 来避免替换系统自带的 Python 版本

# 验证
python3.9 --version

2、安装 pip3

# 安装 pip3
curl -O https://bootstrap.pypa.io/get-pip.py
python3.9 get-pip.py

# 验证
pip3.9 --version

3、软连接替换

# 替换 pip3
which pip3.9
ln -s /usr/local/bin/pip3.9 /usr/local/bin/pip3
pip3 --version

# 替换 python
which python3.9
ln -s /usr/local/bin/python3.9 /usr/local/bin/python3
python3 --version

安装 Locust

1、安装 Locust

pip3 install locust

报错:

ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'OpenSSL 1.0.2k-fips 26 Jan 2017'. See: https://github.com/urllib3/urllib3/issues/2168

解决方案(两种都可以):

1、yum update openssl

2、pip3 install 'urllib3<2.0' # 降级 urllib3 的版本

2、创建一个 Locustfile

# 创建一个名为 locustfile.py 的文件,并在其中定义你的用户行为和任务。下面是一个简单的示例,该示例对一个网站进行 GET 请求:

from locust import HttpUser, task, between

class WebsiteUser(HttpUser):
wait_time = between(1, 2.5)

@task(1)
def load_main(self):
self.client.get("/")
# 定义了一个 WebsiteUser 类,它从 HttpUser 继承而来,并定义了一个 task 来模拟用户访问网站的主页。

3、运行 Locust

locust -f locustfile.py

4、访问 Locust web 界面

打开你的 web 浏览器,访问 http://127.0.0.1:8089 来访问 Locust 的 web 界面。

5、开始测试

在 Locust web 界面中,可以输入想要模拟的用户数量和用户启动速率,然后点击“开始测试”来开始测试。

这里看到一个实时更新的仪表板,显示了各种有用的性能指标,包括请求的数量、失败的数量、最小/最大/平均响应时间等。

如果需要更复杂的可以看这里:https://docs.locust.io/en/stable/