OpenAI API尝鲜
chat.openai.com这个网页是相当的难伺候,即使你是美帝IP也得看在哪个机房,比如注明的某瓦工就进了微软爸爸的ban list,所以想尝试一下通过API的方式稳定聊天。
0x00 WSL中搭环境
这两年微软爸爸干了很多人事,包括但不限于azure、vscode、wsl、OpenAI等,我虽然跟苹果十几年老夫老妻,但还是毅然决然的横跳回微软爸爸的怀抱。
Windows 10自带的WSL2,可以说是相当好用的虚拟机了,因为习惯了POSIX式的命令行环境,就像继续在WSL2里搭环境访问OpenAI。这当然就绕不开那些需要通过修改iptables进行透明代理的软件。
这一上来就是个下马威,这些软件在执行iptables ... -m string ...
命令的时候直接会报”
iptables Couldn’t load match `string’:No such file or directory”,搜了一下这个报错可能是iptables确实string匹配模块,继续搜发现这个模块需要内核支持,而非常不巧的是微软爸爸的WSL2默认不支持这个功能。想用?自己加参数CONFIG_NETFILTER_XT_MATCH_STRING=y
编译内核吧。
软爸倒是早就把WSL2内核准备好了,用WSL2就可以编译,编译前改一下Microsoft/config-wsl
,把选项CONFIG_NETFILTER_XT_MATCH_STRING=y
打开即可,桌面CPU编译很快的,指定-j
选项100%负载几分钟就能搞定。
1 | sudo apt install build-essential flex bison dwarves libssl-dev libelf-dev make bc |
完成后内核默认在arch/x86/boot/bzImage
,参考软爸关于WSL2全局配置的官方文档,首先在虚拟机里建个/etc/wsl.conf
,加两行配置把systemd
打开,让它更像个Linux:
1 | [boot] |
然后在Windows用户文件夹根目录中建个.wslconfi
文件,加几行配置加载自定义内核:
1 | # Settings apply across all Linux distros running on WSL 2 |
此时wsl --shutdown
关闭WSL2,等一小会再打开,uname -a
看内核时间编译时间就能发现已经用上咱新鲜出炉还冒着热气的内核了。再用iptables -m string --help
试一下发现不报错了,这些软件正常工作之后,jupyter里面用OpenAI的API示例测试取一下模型列表就能正常返回了。
1 | import os |
0x01 策划
chatgpt用我手里现有的工具真的不好访问,经常就是access denied,即使用某瓦工在洛杉矶的VPS依然是黑名单,所以就想用API访问。大概的流程就是:
- 浏览器访问云服务器上的某个前端网页
- 云服务器上的前端网页穿透倒家里的rock5b,OpenAI的API服务端就放在rock5b上,十来瓦的功率24小时开机也不肉疼
- rock5b服务端负责拿着API key去OpenAI的API上去聊天结果,再返回给前端
0x02 魔改
我直接在Github上搜OpenAI、ChatBot这些关键词,挑了一个长得顺眼的OpenAIChatBot,作者应该是在API发布早期写了这个项目就去玩别的了,三月初OpenAI更新了专门聊天的API,我就fork这个项目魔改了一下,现在可以用createChatCompletion
了。
我直接用这个API替换了原项目里的createCompletion
,因为官方建议用聊天模型gpt-3.5-turbo
代替原项目里的问答模型text-davinci-003
,理由是效果好还便宜。
需要注意的是,对于前端网页,问答模型只需要一问一答,也就是发一个prompt收一个replay并显示即可。而聊天模型需要记录聊天双方的历史对话,并将所有内容发给API,再拿到一个新的聊天回复。
0x03 部署
- 项目是用nodejs的express写的,前端写好了
npm build
放在云服务器上就好了,如果有需要可以调一下/assets
的绝对/相对路径。 - 前端访问后端的地址为
http://cloud-server/url/to/chat/api/
,在NGINX配置里加一个location
,url匹配到/url/to/chat/api/
,在里面加上proxy_pass http://localhost:<lan-server-port>/;
(代理设置参考NGINX入门教程,一个/
都不能错-_-
)。此时NGINX就能将API转发到云服务器本地的your-lan-server-port
端口上了。记得防火墙要把这个端口要打开,但为了安全源可以只写云服务器的公网IP。 - 用内网穿透(我用的
nps
,frp之类的工具也完全可以)把云服务器上<lan-server-port>
口收到的数据发给家里的rock5b服务端,rock5b的服务端监听0.0.0.0:<lan-server-port>
,启动npc
连接到云服务器的nps
就大功告成。 - 因为中间的网络有点乱,可以在客户端和服务端加
console.log
打印看看请求和响应,测试没问题再去掉。
0x04 后记
其实这个fork项目极度简单,就是一收一发两端就完了。如果后期继续开发的话,还可以加上:
- 显示方面的优化,比如用markdown渲染OpenAI的回复,起码能把代码块弄好看一点
- 对chat completion回复,目前就是拿到内容贴在网页上,其实可以加上更多细节:
- 显示回复是否因字数限制而中断
- 对token计数,帮助我这种抠门人士精打细算的措辞
- 自定义系统角色,目前的聊天角色是我写死的
{"role": "system", "content": "You are a helpful programming assistant"}
其他资料:
这两天稚晖君又发视频了,这次是双足机器人,还能变形成轮式,过于酷炫。立于皓月之边,不弱星光之势。