唠唠闲话

GitHub 项目地址:https://github.com/Chanzhaoyu/chatgpt-web.git

前言

由于 OpenAI 限制了访问 IP,如果在服务器上部署网站,除了设置代理 ,还有两种简单的方案:

  • 使用 Railway 部署,由于托管平台本身就在国外
  • 使用 Azure 服务器部署,虚拟机的创建地址推荐选韩国

概述

OpenAI 提供了 gpt-3.5-turbo-0301 模型的 API,GitHub 上有很多基于这个 API 的开源项目,本篇博客介绍的 chatgpt-web 项目,包括两种部署方式:在个人服务器上部署,以及项目推荐使用的 Railway 网站托管。

优缺点:

  • 使用 Railway 部署,过程简单,只需要填写几个参数就可以搞定,缺点是免费资源有限,用户每月有 500 小时的使用额度(大约21天,每月1号更新)。
  • 使用服务器部署,灵活性强,但设置过程相对复杂一些,而且需要申请或购买服务器。

聊天记录仅保存在本地浏览器中:F12 开发者模式 ⇒ Application ⇒ LocalStorage ⇒ 网站链接 ⇒ chatStorage

通过 Railway 部署

  1. 将项目仓库 fork 到个人账号

  2. 进入 RailWay 的模板地址,使用 GitHub 进行登录
    20230316104647

    并授权应用权限
    20230316104741

  3. 重新点击模板地址,点击配置
    20230316104741

    授权部分仓库访问权限,选择第一步 fork 的仓库

  4. 填写 APIAccessToken 和网站名称
    20230316104942

    附:API 的获取地址和 AccessToken 的获取地址二选一即可

  5. 相关参数

  • PORT 必填,默认填写 3002
  • OPENAI_API_KEY 官方 API 密钥
  • OPENAI_ACCESS_TOKEN chatGPT 网页端的访问 Token
  • API_REVERSE_PROXY 可选,设置反向代理,配合上一步的 Access Token
  • AUTH_SECRET_KEY 访客密码,可选,推荐设置
  • TIMEOUT_MS 超时时间,可选,如果 API 响应慢可以设置为 0

关于 OPENAI_ACCESS_TOKEN
ACCESS_TOKEN 访问的是 ChatGPT 的网页版,但存在 Cloudflare 的反爬虫机制,需越过 Cloudflare 才能使用,目前默认的反向代理链接不太靠谱,待进一步摸索后补充,相关链接

通过服务器部署

部署适用于一般服务器,但 Azure 服务器在境外,能直接访问 OpenAI 而无需代理

  1. 注册 Azure 账户,参考链接 如何白嫖微软Azure12个月及避坑指南,或直接访问 Azure 学生申请页面

    按教程构建 Linux 虚拟机,其中登录方式选 ssh 密钥,地区推荐选韩国,地理位置较近,速度快

  2. 通过 ssh 链接虚拟机后,安装 pnpm 和 nodejs

    1
    2
    3
    4
    5
    # 安装 nodejs@18
    curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - # 再次执行第一行代码
    sudo apt-get install -y nodejs
    # 安装 pnpm
    sudo npm install pnpm -g
  3. 下载 GitHub 项目,并安装相关依赖

    1
    2
    3
    4
    5
    6
    # 将项目放在 ~/workspace/chatgpt-web
    mkdir -p ~/workspace
    git clone https://github.com/Chanzhaoyu/chatgpt-web.git ~/workspace/chatgpt-web
    # 安装前后端文件
    cd ~/workspace/chatgpt-web && pnpm bootstrap
    cd service && pnpm install && cd ..
  4. 修改前端默认端口

    1
    2
    cd ~/workspace/chatgpt-web
    vim vite.config.ts

    找到 port: 1002 并修改为访问端口。建议改为 > 1024 的数值,由于非 sudo 用户默认不能用 ≤ 1024 的端口,但可以执行下边命令来修改这一限制

    1
    2
    sudo apt-get install libcap2-bin 
    sudo setcap cap_net_bind_service=+ep `which node`
  5. 设置环境变量,编辑项目文件下的 .env 文件,或者直接修改 shell 的变量,比如 vim ~/.bashrc

    1
    2
    3
    4
    # 修改 shell 变量
    export OPENAI_API_KEY= # 官方 API 密钥
    export AUTH_SECRET_KEY= # 访客密码
    export OPENAI_API_BASE_URL= # API 代理地址(可选)
  6. 运行项目

    1
    2
    cd ~/workspace/chatgpt-web && pnpm dev
    cd service && pnpm start

    建议用 tmux 命令,将前后端分别放在后台运行

  7. 配置域名

其他

  1. 编写 API 调用脚本,并命名为 quickask。调用方式: quickask [message] [API_token],两个参数均可选

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    msg=$1
    OPENAI_AIP_KEY=$2

    if ! test $msg ; then
    # 没有指定消息时,使用默认消息
    msg=hello
    fi;
    if ! test $OPENAI_API_KEY ; then
    # 没有指定 API 时,使用默认 API
    OPENAI_API_KEY=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
    fi;

    resp=$(curl https://api.openai.com/v1/chat/completions \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $OPENAI_API_KEY" \
    -d "{
    \"model\": \"gpt-3.5-turbo\",
    \"messages\": [
    {\"role\": \"user\", \"content\": \"$msg\"}
    ]
    }")

    # 返回
    echo "\n"$resp
  2. AccessToken 和 APIKey 的区别

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    用 AccessToken 发送的信息比 APIKey 多了字段 conversationId,用于标记会话
    下边是两种模式分别抓包的数据:
    {"prompt":"我上一句话问了什么",
    "options":
    {"conversationId":"9ecac01e-9d12-46bc-9c20-b90ddba92c67",
    "parentMessageId":"da5d30c5-439f-4f21-bdee-be2e9ac5ff31"}
    }
    {"prompt":"你会聊什么",
    "options":
    {"parentMessageId":"chatcmpl-6rt15uZzzXnBXWxCm3DPmMLfkWuOX"}}

    AccessToken 支持长对话,而用 APIKey 聊天长度有限
  3. APIKey 调用文档 及官方示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import openai
    openai.api_key="" # 填入密钥
    response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Who won the world series in 2020?"},
    {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
    {"role": "user", "content": "Where was it played?"}
    ]
    )
    print("会话消耗的 token 数目:", response['usage']['total_tokens'])
    print("返回消息:", response['choices'][0]['message']['content'])

    返回数据的格式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {
    'id': 'chatcmpl-6p9XYPYSTTRi0xEviKjjilqrWU2Ve',
    'object': 'chat.completion',
    'created': 1677649420,
    'model': 'gpt-3.5-turbo',
    'usage': {'prompt_tokens': 56, 'completion_tokens': 31, 'total_tokens': 87},
    'choices': [{
    'message': {
    'role': 'assistant',
    'content': 'The 2020 World Series was played in Arlington, Texas at the Globe Life Field, which was the new home stadium for the Texas Rangers.'},
    'finish_reason': 'stop',
    'index': 0}]}

    输入的 messages 支持三种角色:

    • system有助于设置 AI 助手的行为
    • user 用于指导 AI,由用户或者开发者直接设置
    • assisant 存储之前的回复内容,也可以由开发者编写,帮助指导 AI

    会话通常以 system开头,然后是交替的 userassistant 消息。

  4. APIKey 可以直接在终端使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    OPENAI_API_KEY="" # 这里写入 API_KEY
    curl https://api.openai.com/v1/chat/completions \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $OPENAI_API_KEY" \
    -d '{
    "model": "gpt-3.5-turbo",
    "messages": [
    {"role": "user", "content": "Hello!"}
    ]
    }'

    messages 的填写规则与前边一致。