157 lines
6.2 KiB
Python
157 lines
6.2 KiB
Python
# AI history and template models
|
||
from sqlalchemy import Column, Integer, String, DateTime, Text, Boolean, Float
|
||
from database.models import Base
|
||
from datetime import datetime
|
||
|
||
class AIGenerationHistory(Base):
|
||
"""
|
||
AI generation history tracking
|
||
"""
|
||
__tablename__ = 'ai_generation_history'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
generation_type = Column(String(50), nullable=False) # product_desc, marketing_copy, etc.
|
||
product_name = Column(String(200))
|
||
input_keywords = Column(Text) # JSON string
|
||
input_trend_topic = Column(String(500))
|
||
output_content = Column(Text)
|
||
generation_duration = Column(Float) # seconds
|
||
is_favorite = Column(Boolean, default=False)
|
||
is_used = Column(Boolean, default=False)
|
||
created_by = Column(String(100))
|
||
created_at = Column(DateTime, default=datetime.now)
|
||
|
||
def to_dict(self):
|
||
return {
|
||
'id': self.id,
|
||
'generation_type': self.generation_type,
|
||
'product_name': self.product_name,
|
||
'input_keywords': self.input_keywords,
|
||
'input_trend_topic': self.input_trend_topic,
|
||
'output_content': self.output_content,
|
||
'generation_duration': self.generation_duration,
|
||
'is_favorite': self.is_favorite,
|
||
'is_used': self.is_used,
|
||
'created_by': self.created_by,
|
||
'created_at': self.created_at.isoformat() if self.created_at else None
|
||
}
|
||
|
||
class AIPromptTemplate(Base):
|
||
"""
|
||
AI prompt templates
|
||
"""
|
||
__tablename__ = 'ai_prompt_templates'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
name = Column(String(200), nullable=False)
|
||
description = Column(Text)
|
||
template_type = Column(String(50), nullable=False) # product_desc, marketing_copy, etc.
|
||
prompt_content = Column(Text, nullable=False)
|
||
variables = Column(Text) # JSON string of variable definitions
|
||
is_active = Column(Boolean, default=True)
|
||
is_system = Column(Boolean, default=False)
|
||
created_by = Column(String(100))
|
||
created_at = Column(DateTime, default=datetime.now)
|
||
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||
|
||
def to_dict(self):
|
||
return {
|
||
'id': self.id,
|
||
'name': self.name,
|
||
'description': self.description,
|
||
'template_type': self.template_type,
|
||
'prompt_content': self.prompt_content,
|
||
'variables': self.variables,
|
||
'is_active': self.is_active,
|
||
'is_system': self.is_system,
|
||
'created_by': self.created_by,
|
||
'created_at': self.created_at.isoformat() if self.created_at else None,
|
||
'updated_at': self.updated_at.isoformat() if self.updated_at else None
|
||
}
|
||
|
||
class AIUsageTracking(Base):
|
||
"""
|
||
AI usage tracking for analytics and billing
|
||
"""
|
||
__tablename__ = 'ai_usage_tracking'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
user_id = Column(String(100))
|
||
session_id = Column(String(100))
|
||
service_type = Column(String(50), nullable=False) # openai, ollama, etc.
|
||
model_name = Column(String(100))
|
||
prompt_tokens = Column(Integer, default=0)
|
||
completion_tokens = Column(Integer, default=0)
|
||
total_tokens = Column(Integer, default=0)
|
||
cost_usd = Column(Float, default=0.0)
|
||
request_type = Column(String(50)) # generation, analysis, etc.
|
||
status = Column(String(20), default='success') # success, failed
|
||
error_message = Column(Text)
|
||
duration_ms = Column(Float)
|
||
created_at = Column(DateTime, default=datetime.now)
|
||
|
||
def to_dict(self):
|
||
return {
|
||
'id': self.id,
|
||
'user_id': self.user_id,
|
||
'session_id': self.session_id,
|
||
'service_type': self.service_type,
|
||
'model_name': self.model_name,
|
||
'prompt_tokens': self.prompt_tokens,
|
||
'completion_tokens': self.completion_tokens,
|
||
'total_tokens': self.total_tokens,
|
||
'cost_usd': self.cost_usd,
|
||
'request_type': self.request_type,
|
||
'status': self.status,
|
||
'error_message': self.error_message,
|
||
'duration_ms': self.duration_ms,
|
||
'created_at': self.created_at.isoformat() if self.created_at else None
|
||
}
|
||
|
||
class AIInsight(Base):
|
||
"""
|
||
AI 洞察知識庫(ai_insights 表)— KM 沉澱核心,支援 RAG 向量化。
|
||
對應 openclaw_learning_service / scheduler 各任務寫入。
|
||
"""
|
||
__tablename__ = 'ai_insights'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
insight_type = Column(String(50), nullable=False) # backup_status / human_review / auto_heal_playbook 等
|
||
period = Column(String(50)) # 分析週期,e.g. "2026-04-20"
|
||
product_sku = Column(String(50))
|
||
content = Column(Text, nullable=False)
|
||
metadata_json = Column(Text) # JSON extra payload
|
||
avg_quality = Column(Float, default=0.5)
|
||
status = Column(String(20), default='approved') # approved / pending / rejected / archived
|
||
decay_exempt = Column(Boolean, default=False)
|
||
ai_model = Column(String(50))
|
||
feedback_up = Column(Integer, default=0)
|
||
feedback_down = Column(Integer, default=0)
|
||
confidence = Column(Float, default=0.5)
|
||
created_by = Column(String(50), default='system')
|
||
created_at = Column(DateTime, default=datetime.now)
|
||
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||
# embedding 欄位為 pgvector 型別,透過 raw SQL 寫入,此處不聲明以避免型別衝突
|
||
|
||
def to_dict(self):
|
||
return {
|
||
'id': self.id,
|
||
'insight_type': self.insight_type,
|
||
'period': self.period,
|
||
'product_sku': self.product_sku,
|
||
'content': self.content,
|
||
'avg_quality': self.avg_quality,
|
||
'status': self.status,
|
||
'ai_model': self.ai_model,
|
||
'feedback_up': self.feedback_up,
|
||
'feedback_down': self.feedback_down,
|
||
'confidence': self.confidence,
|
||
'created_by': self.created_by,
|
||
'created_at': self.created_at.isoformat() if self.created_at else None,
|
||
}
|
||
|
||
|
||
__all__ = [
|
||
"AIGenerationHistory", "AIPromptTemplate", "AIUsageTracking", "AIInsight",
|
||
]
|