Flask框架Stream为True的时候,计算token的问题

背景

现在有很多的短视频博主发布视频,说 openai 在封翻墙使用 chatgpt 的用户。力度之大,乃至付费的用户也被大批的封。我试了一下自己的,chat.openai.com 是被禁止访问了,但是API还是可以正常访问的,为了正常使用chatgpt,我试着使用 openai 的 api 自己撸一个服务端,对外提供的 chat/completions API 完全模拟 https://api.openai.com/v1/chat/completions ,这样有一个好处,在 github 上开源的 chatgpt 的商户端就可以正常使用了。

项目的名称: chatgpt-mirror (暂时未在github开源,看官可以关注我的博客,随时有可能会开源)

大概的思路是,chatgpt-mirror 提供一个接口 /v1/chat/completions 会验证自己提供的一个 Fake api key, 在 chatgpt-mirror 上做验证,验证通过后,使用服务端配置的openai的api key 调用 openai 的 api 请求 chatgpt,再把返回结果返回给用户。

花了几天的时间撸完了 chatgpt-mirror ,有很多朋友得知,期望可以共享使用一下。 为了共享使用,我为chatgpt增加了一个功能,为每一个用户配置一个 Fake API key,并在每次请求的时候计算token的消耗量(毕竟token是花钱的)

为了解决token计算问题,分享两点经验

  • 在SSE(stream == True)的时候如何获取 response。在openai提供的api中当 stream == True的时候,返回的是一个迭代器,是获取不到token的数量等字段,此时需要单独计算
  • 如何计算 token

Flask 框架中如何获取stream api的reponse内容

flask 框架内置了很多事件(事件驱动),但是并没有on_response_close事件,查看文档发现,在response对象中提供了一个hook的方法

1response = Response()
2response.call_on_close()

通过注册call_one_close()的回调方法来实现获取response的内容,以及处理response的内容

如何计算token

在 openai 的官方文档中已经有token计算的方法,我看了一下,计算方法太复杂了,所以直接使用他们提供的 tiktoken 的包。

使用方法也很简单

通过 model 获取 encoding

1encoding = tiktoken.encoding_for_model("gpt-3.5-turbo")

通过 encoding 得到tokens

1num_tokens = len(encoding.encode(string))

写成一个方法:

1def num_tokens_from_string(string: str, model: str) -> int:
2    """Returns the number of tokens in a text string."""
3    encoding = tiktoken.encoding_for_model(model)
4    num_tokens = len(encoding.encode(string))
5    return num_tokens
1num_tokens_from_string("Count tokens by tiktoken!", "gpt-3.5-turbo")