分享 Rei on Rails #6:用 Rails 开发 ChatGPT 聊天应用

Rei · 2023年03月24日 · 最后由 zhugexinxin 回复于 2023年05月12日 · 2144 次阅读
本帖已被管理员设置为精华贴

这一期 Rei on Rails 展示如何用 Rails 开发 ChatGPT 聊天应用。

着重讲了 Turbo Stream Broadcast 的用法,这个功能似乎很少被提及,但我觉得是一个杀手级功能。

BiliBili | YouTube

我有一个 idea

厉害了,我的哥

hooopo 回复

缺程序员吗?😏

Rei 回复

我的两个 idea 没了,都被 openai 做掉了

plugin 一出,创业公司没得玩了

😍 好有趣的 demo. 借鉴一下模型层换掉感觉我就可以不用控制台了... 😆

@Rei @hooopo 我们互相加加聊聊?我数了一下,近期有 30 多家 ai 公司融资, 就不具体透露是做什么行业的了,加了具体聊?

xiaoronglv 将本帖设为了精华贴。 03月24日 15:52

效率真厉害👍

前些天在老产品上面也添加了一个给老用户体验的, https://www.vcooline.com

主要加了返回 stream 的处理(一个字一个字蹦出来)

def perform_openai_request(prompt:)
  completion_content = ""
  start_chunk_message
  OpenaiApiProxy::ChatClient.new(api_key: ‘’, organization_id: ‘’).create(
    model: "gpt-3.5-turbo",
    messages: generate_chat_messages(prompt),
    max_tokens:1234
    user: user.to_gid.to_s,
    stream: true
  ) do |reqt|
    reqt.options.on_data = Proc.new do |chunk, overall_received_bytes, env|
      chunk_contents = handle_openai_chunk_data(chunk, overall_received_bytes, env)
      chunk_contents.compact_blank.map { |chunk_content| completion_content.concat(chunk_content) }
    end 
  end 

  completion_content.presence
    &.tap { |content| decrease_usage_quota(content:) }
    &.tap { |content| save_bot_message(content:) }
rescue OpenaiApiProxy::Client::ServerError, OpenaiApiProxy::Client::InternalError => e
  Rails.logger.error "#{self.class.name} perform #{e.class.name}: #{e.message}"
  send_chunk_message(content: "系统繁忙,请稍候再试。")
end 

def handle_openai_chunk_data(chunk, _overall_received_bytes, _env)
  chunk.force_encoding("UTF-8").encode("UTF-8", invalid: :replace, undef: :replace, replace: "") 
    .split("\n\n")
    .map { |line| line.sub(/^data:\ */, "") }
    .compact_blank
    .map.each_with_object([]) do |chunk_line, chunk_contents|
      break chunk_contents if chunk_line == "[DONE]"

      chunk_info = JSON.parse chunk_line
      # start_chunk_message if chunk_info.dig("choices", 0, "delta", "role").eql?("assistant")
      chunk_info.dig("choices", 0, "delta", "content").presence
        &.tap { |chunk_content| chunk_contents.push(chunk_content) }
        &.tap { |chunk_content| send_chunk_message(content: chunk_content) }
    end 
end 

def send_chunk_message(content:)
  start_chunk_input
  message.broadcast_append_to \
    ActionView::RecordIdentifier.dom_id(message.conversation, :namespace_example),
    target: reply_message_dom_id,
    html: content
end 

as181920 回复

666,OpenaiApiProxy::ChatClient 是啥么?没看到,是自己封装的库么?

femto 回复

ChatClient 就是一个 Faraday.new,太简单了所以没贴。细节在这里: https://github.com/as181920/openai_api_proxy/blob/main/lib/openai_api_proxy/chat_client.rb

标题略 general

rennyallen 在 Rails 中使用 SSE 来实现一个 ChatGPT 应用 提及了此话题。 05月05日 20:09

如果是流式,这样会不会数据库更新太频繁? 还有如果使用队列,并发情况下不是单线程,是不是也不稳定。

zhugexinxin 回复

我就做了个 demo 没有深入,后面没找到产品思路没有继续。用在现实环境还是有很多要考虑的,但可以先搞起来再优化。

Rei 回复

嗯,我尝试了 4 种方式,感谢你提供的思路

需要 登录 后方可回复, 如果你还没有账号请 注册新账号