mirror of
https://github.com/discourse/discourse-ai.git
synced 2025-02-17 17:04:48 +00:00
The custom field "discourse_ai_bypass_ai_reply" was added so we can signal the post created hook to bypass replying even if it thinks it should. Otherwise there are cases where we double answer user questions leading to much confusion. This also slightly refactors code making the controller smaller
106 lines
3.3 KiB
Ruby
106 lines
3.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module DiscourseAi
|
|
module AiBot
|
|
class ResponseHttpStreamer
|
|
CRLF = "\r\n"
|
|
POOL_SIZE = 10
|
|
|
|
class << self
|
|
def thread_pool
|
|
@thread_pool ||=
|
|
Concurrent::CachedThreadPool.new(min_threads: 0, max_threads: POOL_SIZE, idletime: 30)
|
|
end
|
|
|
|
def schedule_block(&block)
|
|
# think about a better way to handle cross thread connections
|
|
if Rails.env.test?
|
|
block.call
|
|
return
|
|
end
|
|
|
|
db = RailsMultisite::ConnectionManagement.current_db
|
|
thread_pool.post do
|
|
begin
|
|
RailsMultisite::ConnectionManagement.with_connection(db) { block.call }
|
|
rescue StandardError => e
|
|
Discourse.warn_exception(e, message: "Discourse AI: Unable to stream reply")
|
|
end
|
|
end
|
|
end
|
|
|
|
# keeping this in a static method so we don't capture ENV and other bits
|
|
# this allows us to release memory earlier
|
|
def queue_streamed_reply(io, persona, user, topic, post)
|
|
schedule_block do
|
|
begin
|
|
io.write "HTTP/1.1 200 OK"
|
|
io.write CRLF
|
|
io.write "Content-Type: text/plain; charset=utf-8"
|
|
io.write CRLF
|
|
io.write "Transfer-Encoding: chunked"
|
|
io.write CRLF
|
|
io.write "Cache-Control: no-cache, no-store, must-revalidate"
|
|
io.write CRLF
|
|
io.write "Connection: close"
|
|
io.write CRLF
|
|
io.write "X-Accel-Buffering: no"
|
|
io.write CRLF
|
|
io.write "X-Content-Type-Options: nosniff"
|
|
io.write CRLF
|
|
io.write CRLF
|
|
io.flush
|
|
|
|
persona_class =
|
|
DiscourseAi::AiBot::Personas::Persona.find_by(id: persona.id, user: user)
|
|
bot = DiscourseAi::AiBot::Bot.as(persona.user, persona: persona_class.new)
|
|
|
|
data =
|
|
{
|
|
topic_id: topic.id,
|
|
bot_user_id: persona.user.id,
|
|
persona_id: persona.id,
|
|
}.to_json + "\n\n"
|
|
|
|
io.write data.bytesize.to_s(16)
|
|
io.write CRLF
|
|
io.write data
|
|
io.write CRLF
|
|
|
|
DiscourseAi::AiBot::Playground
|
|
.new(bot)
|
|
.reply_to(post) do |partial|
|
|
next if partial.length == 0
|
|
|
|
data = { partial: partial }.to_json + "\n\n"
|
|
|
|
data.force_encoding("UTF-8")
|
|
|
|
io.write data.bytesize.to_s(16)
|
|
io.write CRLF
|
|
io.write data
|
|
io.write CRLF
|
|
io.flush
|
|
end
|
|
|
|
io.write "0"
|
|
io.write CRLF
|
|
io.write CRLF
|
|
|
|
io.flush
|
|
io.done
|
|
rescue StandardError => e
|
|
# make it a tiny bit easier to debug in dev, this is tricky
|
|
# multi-threaded code that exhibits various limitations in rails
|
|
p e if Rails.env.development?
|
|
Discourse.warn_exception(e, message: "Discourse AI: Unable to stream reply")
|
|
ensure
|
|
io.close
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|