mirror of
https://ghfast.top/https://github.com/discourse/discourse-ai.git
synced 2026-07-16 11:36:23 +08:00
This commit introduces a new Forum Researcher persona specialized in deep forum content analysis along with comprehensive improvements to our AI infrastructure.
Key additions:
New Forum Researcher persona with advanced filtering and analysis capabilities
Robust filtering system supporting tags, categories, dates, users, and keywords
LLM formatter to efficiently process and chunk research results
Infrastructure improvements:
Implemented CancelManager class to centrally manage AI completion cancellations
Replaced callback-based cancellation with a more robust pattern
Added systematic cancellation monitoring with callbacks
Other improvements:
Added configurable default_enabled flag to control which personas are enabled by default
Updated translation strings for the new researcher functionality
Added comprehensive specs for the new components
Renames Researcher -> Web Researcher
This change makes our AI platform more stable while adding powerful research capabilities that can analyze forum trends and surface relevant content.
109 lines
3 KiB
Ruby
109 lines
3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# special object that can be used to cancel completions and http requests
|
|
module DiscourseAi
|
|
module Completions
|
|
class CancelManager
|
|
attr_reader :cancelled
|
|
attr_reader :callbacks
|
|
|
|
def initialize
|
|
@cancelled = false
|
|
@callbacks = Concurrent::Array.new
|
|
@mutex = Mutex.new
|
|
@monitor_thread = nil
|
|
end
|
|
|
|
def monitor_thread
|
|
@mutex.synchronize { @monitor_thread }
|
|
end
|
|
|
|
def start_monitor(delay: 0.5, &block)
|
|
@mutex.synchronize do
|
|
raise "Already monitoring" if @monitor_thread
|
|
raise "Expected a block" if !block
|
|
|
|
db = RailsMultisite::ConnectionManagement.current_db
|
|
@stop_monitor = false
|
|
|
|
@monitor_thread =
|
|
Thread.new do
|
|
begin
|
|
loop do
|
|
done = false
|
|
@mutex.synchronize { done = true if @stop_monitor }
|
|
break if done
|
|
sleep delay
|
|
@mutex.synchronize { done = true if @stop_monitor }
|
|
@mutex.synchronize { done = true if cancelled? }
|
|
break if done
|
|
|
|
should_cancel = false
|
|
RailsMultisite::ConnectionManagement.with_connection(db) do
|
|
should_cancel = block.call
|
|
end
|
|
|
|
@mutex.synchronize { cancel! if should_cancel }
|
|
|
|
break if cancelled?
|
|
end
|
|
ensure
|
|
@mutex.synchronize { @monitor_thread = nil }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def stop_monitor
|
|
monitor_thread = nil
|
|
|
|
@mutex.synchronize { monitor_thread = @monitor_thread }
|
|
|
|
if monitor_thread
|
|
@mutex.synchronize { @stop_monitor = true }
|
|
# so we do not deadlock
|
|
monitor_thread.wakeup
|
|
monitor_thread.join(2)
|
|
# should not happen
|
|
if monitor_thread.alive?
|
|
Rails.logger.warn("DiscourseAI: CancelManager monitor thread did not stop in time")
|
|
monitor_thread.kill if monitor_thread.alive?
|
|
end
|
|
@monitor_thread = nil
|
|
end
|
|
end
|
|
|
|
def cancelled?
|
|
@cancelled
|
|
end
|
|
|
|
def add_callback(cb)
|
|
@callbacks << cb
|
|
end
|
|
|
|
def remove_callback(cb)
|
|
@callbacks.delete(cb)
|
|
end
|
|
|
|
def cancel!
|
|
@cancelled = true
|
|
monitor_thread = @monitor_thread
|
|
if monitor_thread && monitor_thread != Thread.current
|
|
monitor_thread.wakeup
|
|
monitor_thread.join(2)
|
|
if monitor_thread.alive?
|
|
Rails.logger.warn("DiscourseAI: CancelManager monitor thread did not stop in time")
|
|
monitor_thread.kill if monitor_thread.alive?
|
|
end
|
|
end
|
|
@callbacks.each do |cb|
|
|
begin
|
|
cb.call
|
|
rescue StandardError
|
|
# ignore cause this may have already been cancelled
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|