diff --git a/database.py b/database.py index b6356c5..4893c03 100644 --- a/database.py +++ b/database.py @@ -5951,6 +5951,44 @@ class MessagePin(Base): return f'' +class AIUserMemory(Base): + __tablename__ = 'ai_user_memory' + + id = Column(Integer, primary_key=True) + user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'), nullable=False) + fact = Column(Text, nullable=False) + category = Column(String(50), default='general') + source_conversation_id = Column(Integer, ForeignKey('ai_chat_conversations.id', ondelete='SET NULL'), nullable=True) + confidence = Column(Float, default=1.0) + created_at = Column(DateTime, default=datetime.utcnow) + expires_at = Column(DateTime) + is_active = Column(Boolean, default=True) + + user = relationship('User') + source_conversation = relationship('AIChatConversation') + + def __repr__(self): + return f'' + + +class AIConversationSummary(Base): + __tablename__ = 'ai_conversation_summary' + + id = Column(Integer, primary_key=True) + conversation_id = Column(Integer, ForeignKey('ai_chat_conversations.id', ondelete='CASCADE'), nullable=False, unique=True) + user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'), nullable=False) + summary = Column(Text, nullable=False) + key_topics = Column(JSON, default=list) + created_at = Column(DateTime, default=datetime.utcnow) + updated_at = Column(DateTime, default=datetime.utcnow) + + user = relationship('User') + conversation = relationship('AIChatConversation') + + def __repr__(self): + return f'' + + # ============================================================ # DATABASE INITIALIZATION # ============================================================ diff --git a/database/migrations/092_ai_user_memory.sql b/database/migrations/092_ai_user_memory.sql new file mode 100644 index 0000000..00ef0d6 --- /dev/null +++ b/database/migrations/092_ai_user_memory.sql @@ -0,0 +1,20 @@ +-- 092_ai_user_memory.sql +-- Persistent memory for NordaGPT — per-user facts extracted from conversations + +CREATE TABLE IF NOT EXISTS ai_user_memory ( + id SERIAL PRIMARY KEY, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + fact TEXT NOT NULL, + category VARCHAR(50) DEFAULT 'general', + source_conversation_id INTEGER REFERENCES ai_chat_conversations(id) ON DELETE SET NULL, + confidence FLOAT DEFAULT 1.0, + created_at TIMESTAMP DEFAULT NOW(), + expires_at TIMESTAMP DEFAULT (NOW() + INTERVAL '12 months'), + is_active BOOLEAN DEFAULT TRUE +); + +CREATE INDEX idx_ai_user_memory_user_active ON ai_user_memory(user_id, is_active, confidence DESC); +CREATE INDEX idx_ai_user_memory_expires ON ai_user_memory(expires_at) WHERE is_active = TRUE; + +GRANT ALL ON TABLE ai_user_memory TO nordabiz_app; +GRANT USAGE, SELECT ON SEQUENCE ai_user_memory_id_seq TO nordabiz_app; diff --git a/database/migrations/093_ai_conversation_summary.sql b/database/migrations/093_ai_conversation_summary.sql new file mode 100644 index 0000000..f821481 --- /dev/null +++ b/database/migrations/093_ai_conversation_summary.sql @@ -0,0 +1,17 @@ +-- 093_ai_conversation_summary.sql +-- Auto-generated summaries of AI conversations for memory context + +CREATE TABLE IF NOT EXISTS ai_conversation_summary ( + id SERIAL PRIMARY KEY, + conversation_id INTEGER NOT NULL UNIQUE REFERENCES ai_chat_conversations(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + summary TEXT NOT NULL, + key_topics JSONB DEFAULT '[]', + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW() +); + +CREATE INDEX idx_ai_conv_summary_user ON ai_conversation_summary(user_id, created_at DESC); + +GRANT ALL ON TABLE ai_conversation_summary TO nordabiz_app; +GRANT USAGE, SELECT ON SEQUENCE ai_conversation_summary_id_seq TO nordabiz_app;