feat(nordagpt): add memory tables and ORM models

- Migration 092: ai_user_memory (per-user facts with expiry)
- Migration 093: ai_conversation_summary (auto-generated summaries)
- SQLAlchemy models: AIUserMemory, AIConversationSummary

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-03-28 05:44:30 +01:00
parent 0640ffbb9d
commit f953648c7d
3 changed files with 75 additions and 0 deletions

View File

@ -5951,6 +5951,44 @@ class MessagePin(Base):
return f'<MessagePin msg={self.message_id} conv={self.conversation_id}>'
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'<AIUserMemory id={self.id} user={self.user_id} fact="{self.fact[:30]}">'
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'<AIConversationSummary conv={self.conversation_id}>'
# ============================================================
# DATABASE INITIALIZATION
# ============================================================

View File

@ -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;

View File

@ -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;