小站有个页面叫 /codex,是我自己做的 AI 工作台。
它长得很普通:左边一个输入框,右边是对话,可以贴图,可以选模型,回答一个字一个字蹦出来。做它的原因也很简单——我不想为了问一句话开三个标签页,还要在几个网站之间复制粘贴。
做的时候我以为最难的是接 API,结果接 API 是最简单的一步。真正花时间的是后面那些“没想到”。
第一个问题:中文丢字。
流式返回的时候,服务端是一块一块往回推数据的。我一开始直接把每一块解码成字符串往页面上拼,结果中文偶尔会少一个字,或者出现一个问号。
查了才知道,一个汉字在 UTF-8 里占三个字节,服务端切块的时候可能正好把一个字劈成两半。前一块是半个字,后一块是另外半个,各自解码都是乱码。
解决办法是用 TextDecoder 的流式模式,{ stream: true },让它把不完整的字节留着,等下一块来了再拼。改完以后再也不丢字了。这个 bug 找了我两个晚上,因为它是偶发的,十次里错一次。
第二个问题:key 不能放在前端。
这个不用多说,前端代码谁都能看。所以请求统一走服务端的接口,key 存在环境变量里,浏览器只跟我的服务器说话。顺便还能做限流——不然别人拿我的页面当免费 API 用,账单是我的。
第三个问题:超时。
有一次我让它写一段比较长的代码,页面转了很久,最后报错。原因是中间某一层代理有超时限制,等太久就断了。后来我把超时调大,并且在页面上加了“正在生成”的提示,至少让人知道它还在干活,不是死了。
第四个问题:手机。
我在手机上用自己做的页面,发现输入框被键盘顶上去以后就再也点不到了。这个问题在电脑上永远测不出来。改了半天 CSS,最后是给容器加了一段处理可视区域的逻辑。
还有一些小的:图片上传要限制大小,不然一张十兆的图传上去要等很久;模型下拉框的选项太多会超出屏幕;对话记录存在本地,刷新以后还在,但换设备就没了。
后台统计里有个数字挺有意思:这个页面被打开过六百次,但真正发出去的请求只有七十次。
也就是说,大部分人点进来,看了看,就走了。
我不觉得这是失败。可能他们只是想看看这是个什么东西。我自己去别人的站也经常这样,点开一个工具页,摸两下,关掉。
但我会继续改它。下次想加的是对话历史导出,还有把常用的提示词存起来。慢慢来。
