221 lines
8.0 KiB
Python
221 lines
8.0 KiB
Python
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),
|
|
}
|