Files
moreminimore-chat/db/migrate/20260820000000_create_knowledge_base_faqs.rb
Moreminimore 2495239187 feat(chatbot): OSS self-contained guardrail + knowledge-base chatbot
Built-in AI chatbot (no EE, uses Llm::Resolver) that answers in-scope chats
from a knowledge base and hands off to a human when needed. Selected per
inbox via an Integrations::Hook with app_id 'chatbot'.

- Integrations::Chatbot::ProcessorService (mirrors Dialogflow/Captain)
  wired via HookListener + HookJob + apps.yml(chatbot, inbox)
- Chatbot::DecisionService: 1-call default ({in_scope/refuse/handoff}),
  2-call option; thread-safe prompt threading
- Chatbot::KnowledgeRetriever: keyword top-k over KB (+ embedding reserved)
- KnowledgeBaseFaq + import service (md per-heading + front-matter tags)
- Chatbot::ConfigService + admin chatbot_config endpoint
- refs off-topic (e.g. fortune-telling); handoff = bot_handoff! (pending->open)
2026-08-25 16:09:47 +07:00

29 lines
1.7 KiB
Ruby

# KnowledgeBaseFaq — OSS-level markdown FAQ knowledge entries for the self-contained
# chatbot. Account-scoped. Supports keyword retrieval via pg_trgm index on title and
# an optional pgvector embedding column (populated by a later embedding step).
#
# This is intentionally SEPARATE from Enterprise-only Captain tables
# (captain_assistant_responses / captain_assistants) so it works without EE.
class CreateKnowledgeBaseFaqs < ActiveRecord::Migration[7.1]
def change
create_table :knowledge_base_faqs do |t|
t.bigint :account_id, null: false
t.string :title, null: false # short topic/question label
t.text :content, null: false # markdown body / answer
t.jsonb :topic_tags, default: [], null: false # e.g. ["shipping", "refund"]
t.string :source_filename # original md filename (optional)
t.vector :embedding, limit: 1536 # pgvector embedding (nullable; set later)
t.timestamps
end
add_index :knowledge_base_faqs, :account_id
add_index :knowledge_base_faqs, [:account_id, :title]
# pg_trgm GIN index for fuzzy keyword search on title + content
# (matches repo convention: gin + gin_trgm_ops, e.g. index_messages_on_content)
add_index :knowledge_base_faqs, :title, using: :gin, opclass: :gin_trgm_ops, name: 'index_kbf_on_title_trgm'
add_index :knowledge_base_faqs, :content, using: :gin, opclass: :gin_trgm_ops, name: 'index_kbf_on_content_trgm'
# pgvector ivfflat index for embedding similarity search (only when embeddings exist)
add_index :knowledge_base_faqs, :embedding, using: :ivfflat, opclass: :vector_cosine_ops, name: 'index_kbf_on_embedding'
end
end