程序员再“整活”,在 Dos 上也能玩 ChatGPT 客户端!
如果撇开科技大厂的业务线不谈,我们还可以用 ChatGPT、GPT-4 来干什么?除了逗趣、生成代码、聊天之外,这届网友已经尝试雇佣了 GPT-4 当老板,开启从零的创业之旅......当然,还有一些极客、编程爱好者势必不会错过这次机会。
这不,一名新加坡的创客、程序员 Yeo Kheng Meng 再次“整活”,用 ChatGPT 打开时空之门,为 MS-DOS 平台开发了一个 ChatGPT 客户端,让老式的计算机系统也可以运行当前最为先进的大模型,开启一场独特的对话方式。
以下是在 MS-DOS 上运行 ChatGPT 的新体验过程:
同时,作者将相关代码在 GitHub 上开源出来:https://github.com/yeokm1/doschgpt,也希望通过本文为玩转 ChatGPT 的不同方式带来一些借鉴与思考。
应用程序的屏幕截图
定目标硬件
Dos 是很多老程序员的青春记忆。之所以选择 Dos 平台开发,Yeo Kheng Meng 表示,“2019 年,我曾为 Windows 3.1 创建了一个 Slack 客户端(https://yeokhengmeng.com/2019/12/building-a-new-win-3-1-app-in-2019-part-1-slack-client/)。这次我想尝试一些不同的东西,也想要开启为更旧的平台开发的挑战。”
值得注意的是,DOS 没有原生联网的能力,而且系统的处理能力也较弱,所以选择它为目标平台,包括编码之类的所有处理任务处理都会有额外的困难和挑战。
在硬件选择上,Yeo Kheng Meng 使用的 MS-DOS 电脑是 1984 年的 IBM 5155 便携式电脑,它拥有 Intel 8088 4.77Mhz CPU、640KB 常规内存(使用升级套件)、CGA ISA 图形、NE2000 兼容的 ISA 以太网适配器、XT-IDE ISA 驱动器控制器和 MS-DOS 6.22 系统等配置。
“如果我的应用程序可以在这台 IBM 机器上运行,它应该可以在几乎所有其他 DOS 机器上运行”,Yeo Kheng Meng 说道。
开干!
编译器
为了创建客户端,Yeo 使用了 Open Watcom C/C++,这是一种在 Windows 11 上运行的现代编译器,可以应用在 16 位 DOS 平台上。
不过,16 位 DOS 程序的问题是,现代 64 位版本的 Windows 默认不能执行它们。在开发过程中,Yeo 仍然需要一种方法来测试编译后的二进制文件。虽然把二进制文件传送到 IBM DOS PC 上是有可能的,但这会大大增加开发过程中的复杂性。
测试环境搭建
从技术上来讲,已有现成的第三方解决方案,如 winevdm(https://github.com/otya128/winevdm),但它在这种使用情况下是行不通的,后面会解释。
因此,出于测试目的,Yeo 通过搜索,找到了运行 DOS 6.22 的 VirtualBox 虚拟机来简化开发过程,然后将编译后的二进制文件传输到目标 IBM DOS PC 上进行测试。
完整的 VM 配置信息详见:https://github.com/yeokm1/retro-configs/tree/master/vms/vbox-dos622
Yeo 把它设置成与主机在一个桥接网络上,这样两者之间就可以很容易地进行通信,而且虚拟机可以访问 Yeo 个人的互联网连接。
在带有已编译好的二进制文件的主机上,Yeo 用 Python 启动了一个简单的网络服务器,为二进制文件服务。代码为:
python3 -m http.server 8000
在虚拟机上,Yeo 使用 MTCP 的一个程序来下载二进制文件进行测试:
htget -o doschgpt.exe http://X.X.X.X:8000/doschgpt.exe
编码
正如文章伊始所述,与现代 Windows/Mac/Linux 相比,MS-DOS 平台的编码提出了一些额外的挑战。最大的问题是网络 API,因为 DOS 本身并不附带这些 API。
然而,具有 TCP/IP 网络功能的 DOS 程序以前已经编写过,所以这绝对是可能的。
应用架构
为了在 IBM PC 上处理网络问题,Yeo 也穿梭于多个层级之间。在做了一些研究之后,Yeo 使用了 1983 年发明的“ Packet Driver API ”标准。
如果要使用低级别的 Packet Driver API,网卡制造商通常会发布一个实现该 API 的驱动程序。然后,应用程序开发人员使用该 API 与网卡通信。
最初,Yeo 认为要掌握这个低级别的 API 是一个巨大的挑战,但幸运的是,有一个现有的开源网络库可以帮助完成这个任务。这个库是由 Michael B. Brutman 编写的 MTCP(http://brutmanlabs.org/mTCP/)。
MTCP 库必须被集成到应用程序中。然后,它将与制造商提供的数据包驱动程序进行通信,该驱动程序作为一个常驻程序(TSR)运行。TSR 在后台保持休眠状态,直到被一个应用程序调用。然后,数据包驱动程序直接与网卡进行通信。
不过,Yeo 没有找到可以安装在现代 64 位 Windows 操作系统上的数据包驱动程序。因此,即使 16 位 DOS 二进制文件可以使用 winevdm 等工具执行,它也不会连接到网络,所以这也是为什么不直接用第三方解决方案的原因。
另一方面,对于较旧的网卡,比如在 IBM5155 中使用的 NE2000 兼容网卡,数据包驱动程序相对常见。
开始联网
在尝试开始联网的过程中,要注意在 DOS 中没有多线程的概念,所以没有任何东西在后台运行来为服务于网络堆栈,所以,网络堆栈主要由应用程序控制,因此这种服务也必须在内部完成。
为驱动较低的网络层,这组函数必须定期被调用:
PACKET_PROCESS_SINGLE;
Arp::driveArp();
Tcp::drivePackets();
MTCP 提供的原始套接字 API,具有基本的 send() 和 recv() 函数,足以让人使用。
ChatGPT API
不久之前,OpenAI 宣布开放 API。在这里,Yeo 只选择了 Chat Completion API(https://platform.openai.com/docs/api-reference/making-requests)。
官方也提供了一个很好的使用示例供参考:
curl https://api.openai.com/v1/chat/completions -H "Content-Type: application/json" -H "Authorization: Bearer sk-XXX" -d '{ "model": "gpt-3.5-turbo", "messages": [{"role": "user", "content": "What is MS-DOS?"}], "temperature": 0.7 }'
使用这个 API,Yeo 将需要构建整个 POST 请求。与现代开发平台不同,这里没有可以使用的辅助函数,所以 Yeo 选择用 C 语言手动构建整个 POST 请求,如下所示:
#define API_CHAT_COMPLETION "POST /v1/chat/completions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer %s\r\nHost: api.openai.com\r\nContent-Length: %d\r\nConnection: close\r\n\r\n%s"
#define API_BODY "{ \"model\": \"%s\", \"messages\": [{\"role\": \"user\", \"content\": \"%s\"}], \"temperature\": %.1f }"
JSON 解析
ChatGPT API 将返回以下 JSON 输出:
{"id":"chatcmpl-XXXXX","object":"chat.completion","created":1679326062,"model":"gpt-3.5-turbo-0301","usage":{"prompt_tokens":13,"completion_tokens":114,"total_tokens":127},"choices":[{"message":{"role":"assistant","content":"\n\nMS-DOS (Microsoft Disk Operating System) is a command-line operating system....."},"finish_reason":"stop","index":0}]}
在这个过程中,Yeo 遇到了一个重大障碍:ChatGPT API 需要加密的 HTTPS 连接。由于 MS-DOS 没有本地 HTTPS 库,Yeo 创建了一个 HTTP-to-HTTPS 代理(https://github.com/yeokm1/http-to-https-proxy),可以在现代计算机上运行,并在 MS-DOS 客户端和 ChatGPT 的安全 API 之间转换请求和响应,充当透明的中间人在沟通过程中。
Yeo 表示,由于 DOS 应用程序的单线程特性,向控制台读取和写入输入带来了另一个挑战。为此,他使用 MTCP 页面(http://brutmanlabs.org/Adventures_In_Code/Adventures_In_Code.html)和在线示例(https://jmagic.tistory.com/982)作为参考,设计了一种无需暂停程序即可检查和接收按键的方法:
int currentMessagePos = 0;
char * messageToSend = (char *) calloc (SIZE_MESSAGE_TO_SEND, sizeof(char));
while(true){
if ( _bios_keybrd(_KEYBRD_READY) ) {
char character = _bios_keybrd(_KEYBRD_READ);
...
messageToSend[currentMessagePos] = character;
currentMessagePos++;
printf("%c", character);
fflush(stdout);
}
}
_bios_keybrd 是一个通向 INT 16h BIOS 键盘中断的通道。
如果检测到一个按键,该按键将被存储到一个本地缓冲区并打印到控制台。现在 Yeo 可以在不暂停程序的情况下检查和接收按键。
最后
最终,这款程序的运行的效果,远超 Yeo 的预期。他表示,“编写这个聊天客户端是一种有趣的体验。让编译器能够在现代 Windows 操作系统上运行肯定会让事情变得更容易。事实上,这一次比我以前做的 Windows 3.1 Slack 应用程序更容易。考虑到这是我第一次在 DOS 平台上编写代码,我对这样的旧机器的性能印象深刻。经历了这一切,我以后肯定会写更多复古软件。”
那么要问 ChatGPT 是否能够直接解决自己在旧的平台上运行的问题,其回答道:
请记住,创建 DOS ChatGPT 客户端可能具有挑战性,因为 DOS 是一个过时的操作系统,可能没有开发现代应用程序所需的工具和资源。
不过,人类工程师还是用实现了 ChatGPT 感觉不可能的事情。反过来看,或许只需一点创造力,人工智能语言模型的最新技术就不必局限于前沿的硬件,它可以打通过去、现在和未来。
来源:
https://yeokhengmeng.com/2023/03/building-a-dos-chatgpt-client-in-2023/
GitHub 地址:https://github.com/yeokm1/doschgpt