import uuid from sqlalchemy import Column, String, Integer, Float, DateTime, Text, JSON, Boolean from sqlalchemy.sql import func from database import Base def _iso(dt): return dt.isoformat() if dt else None class Avatar(Base): __tablename__ = "avatars" id = Column(String, primary_key=True, default=lambda: uuid.uuid4().hex) owner_id = Column(String, default="", index=True) # 归属用户(会会 huihui_user_id);空=未归属/种子数据 name = Column(String, nullable=False) display_name = Column(String, default="") description = Column(Text, default="") photo_url = Column(String, default="") emoji = Column(String, default="🤖") status = Column(String, default="active") # active | inactive | training token_balance = Column(Integer, default=0) config = Column(JSON, default=dict) created_at = Column(DateTime, server_default=func.now()) updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now()) def to_dict(self): return { "id": self.id, "ownerId": self.owner_id, "name": self.name, "displayName": self.display_name, "description": self.description, "photoUrl": self.photo_url, "emoji": self.emoji, "status": self.status, "tokenBalance": self.token_balance, "config": self.config or {}, "createdAt": _iso(self.created_at), "updatedAt": _iso(self.updated_at), } class Authorization(Base): __tablename__ = "authorizations" id = Column(String, primary_key=True, default=lambda: uuid.uuid4().hex) avatar_id = Column(String, nullable=False, default="") target_type = Column(String, default="user") # user | organization | application target_id = Column(String, default="") target_name = Column(String, default="") permissions = Column(JSON, default=list) status = Column(String, default="active") # active | inactive created_at = Column(DateTime, server_default=func.now()) def to_dict(self): return { "id": self.id, "avatarId": self.avatar_id, "targetType": self.target_type, "targetId": self.target_id, "targetName": self.target_name, "permissions": self.permissions or [], "status": self.status, "createdAt": _iso(self.created_at), } class Organization(Base): __tablename__ = "organizations" id = Column(String, primary_key=True, default=lambda: uuid.uuid4().hex) name = Column(String, nullable=False) description = Column(Text, default="") emoji = Column(String, default="🏢") org_type = Column(String, default="team") # team | company | community role = Column(String, default="admin") # admin | member | viewer member_count = Column(Integer, default=1) created_at = Column(DateTime, server_default=func.now()) def to_dict(self): return { "id": self.id, "name": self.name, "description": self.description, "emoji": self.emoji, "type": self.org_type, "role": self.role, "memberCount": self.member_count, "createdAt": _iso(self.created_at), } class KnowledgeDoc(Base): __tablename__ = "knowledge_docs" id = Column(String, primary_key=True, default=lambda: uuid.uuid4().hex) avatar_id = Column(String, nullable=False, default="") filename = Column(String, default="") file_type = Column(String, default="") # pdf | doc | docx | xlsx file_size = Column(Integer, default=0) file_url = Column(String, default="") status = Column(String, default="uploaded") # uploaded | parsing | ready vectorized = Column(Boolean, default=False) # 是否已向量化 embedding_model = Column(String, default="") # 向量模型标识 chunk_count = Column(Integer, default=0) # 切片数量 vectorized_at = Column(DateTime) # 向量化时间 created_at = Column(DateTime, server_default=func.now()) def to_dict(self): return { "id": self.id, "avatarId": self.avatar_id, "filename": self.filename, "fileType": self.file_type, "fileSize": self.file_size, "fileUrl": self.file_url, "status": self.status, "vectorized": bool(self.vectorized), "embeddingModel": self.embedding_model, "chunkCount": self.chunk_count, "vectorizedAt": _iso(self.vectorized_at), "createdAt": _iso(self.created_at), } class QAPair(Base): __tablename__ = "qa_pairs" id = Column(String, primary_key=True, default=lambda: uuid.uuid4().hex) avatar_id = Column(String, nullable=False, default="") question = Column(Text, default="") answer = Column(Text, default="") enabled = Column(Boolean, default=True) # 是否启用(关闭后不参与作答) created_at = Column(DateTime, server_default=func.now()) updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now()) def to_dict(self): return { "id": self.id, "avatarId": self.avatar_id, "question": self.question, "answer": self.answer, "enabled": bool(self.enabled), "createdAt": _iso(self.created_at), "updatedAt": _iso(self.updated_at), } class KnowledgeChunk(Base): __tablename__ = "knowledge_chunks" id = Column(String, primary_key=True, default=lambda: uuid.uuid4().hex) doc_id = Column(String, default="") # 关联 KnowledgeDoc.id avatar_id = Column(String, default="") content = Column(Text, default="") # 切片文本 vector = Column(Text, default="") # JSON 编码的向量 chunk_index = Column(Integer, default=0) embedding_model = Column(String, default="") created_at = Column(DateTime, server_default=func.now()) def to_dict(self): return { "id": self.id, "docId": self.doc_id, "avatarId": self.avatar_id, "content": self.content, "chunkIndex": self.chunk_index, "embeddingModel": self.embedding_model, "createdAt": _iso(self.created_at), } class TokenAccount(Base): __tablename__ = "token_account" id = Column(Integer, primary_key=True) balance = Column(Integer, default=1250) class TokenPlan(Base): __tablename__ = "token_plans" id = Column(String, primary_key=True) name = Column(String, default="") amount = Column(Integer, default=0) price = Column(Float, default=0) badge = Column(String, default="") desc = Column(String, default="") def to_dict(self): return { "id": self.id, "name": self.name, "amount": self.amount, "price": self.price, "badge": self.badge, "desc": self.desc, } class User(Base): """会会用户 ↔ 本地用户体系映射(短信验证码登录落库)""" __tablename__ = "users" id = Column(String, primary_key=True, default=lambda: uuid.uuid4().hex) huihui_user_id = Column(String, default="", index=True) # 会会 userId(唯一标识) phone = Column(String, default="", index=True) nickname = Column(String, default="") avatar_url = Column(String, default="") huihui_token = Column(String, default="") # 会会 access_token app_token = Column(String, default="") # 本系统会话 token last_login_at = Column(DateTime) created_at = Column(DateTime, server_default=func.now()) updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now()) def to_dict(self): return { "id": self.id, "huihuiUserId": self.huihui_user_id, "phone": self.phone, "nickname": self.nickname, "avatarUrl": self.avatar_url, "createdAt": _iso(self.created_at), "lastLoginAt": _iso(self.last_login_at), }