Files
assist/src/core/models.py
Jeason c07cbf47c8 feat: 飞书消息记录完善 记录发送者ID、姓名、群信息
- FeishuService 新增 get_user_info() 根据 user_id 获取飞书用户姓名
- feishu_bot.py 处理消息时获取发送者姓名,日志格式改为:发送者=姓名(ID), 群=chat_id, 类型=群聊/私聊, 租户=xxx
- feishu_longconn_service.py 同样获取发送者姓名并记录
- Conversation.ip_address 存储 feishu:user_id:sender_name(扩大字段到200字符)
- Conversation.invocation_method 存储 feishu_bot(group) / feishu_longconn(p2p) 等详细来源
- ChatSession.source 同步记录详细来源信息
2026-04-02 15:40:26 +08:00

313 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from sqlalchemy import Column, Integer, String, Text, DateTime, Float, Boolean, ForeignKey, Index
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from datetime import datetime
import hashlib
Base = declarative_base()
# 默认租户ID单租户部署时使用
DEFAULT_TENANT = "default"
class Tenant(Base):
"""租户模型 — 管理多租户(市场)"""
__tablename__ = "tenants"
id = Column(Integer, primary_key=True)
tenant_id = Column(String(50), unique=True, nullable=False) # 唯一标识,如 market_a
name = Column(String(100), nullable=False) # 显示名称,如 "市场A"
description = Column(Text, nullable=True)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.now)
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
# 租户级配置:飞书 app 凭证、LLM 参数等JSON 格式)
config = Column(Text, nullable=True)
def to_dict(self):
import json
return {
'id': self.id,
'tenant_id': self.tenant_id,
'name': self.name,
'description': self.description,
'is_active': self.is_active,
'config': json.loads(self.config) if self.config else {},
'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 WorkOrder(Base):
"""工单模型"""
__tablename__ = "work_orders"
id = Column(Integer, primary_key=True)
tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True)
order_id = Column(String(50), unique=True, nullable=False)
title = Column(String(200), nullable=False)
description = Column(Text, nullable=False)
category = Column(String(100), nullable=False)
priority = Column(String(20), nullable=False)
status = Column(String(20), nullable=False)
created_at = Column(DateTime, default=datetime.now)
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
resolution = Column(Text)
satisfaction_score = Column(Float)
# 飞书集成字段
feishu_record_id = Column(String(100), unique=True, nullable=True) # 飞书记录ID
assignee = Column(String(100), nullable=True) # 负责人
solution = Column(Text, nullable=True) # 解决方案
ai_suggestion = Column(Text, nullable=True) # AI建议
# 扩展飞书字段
source = Column(String(50), nullable=True) # 来源Mail, Telegram bot等
module = Column(String(100), nullable=True) # 模块local O&M, OTA等
created_by = Column(String(100), nullable=True) # 创建人
wilfulness = Column(String(100), nullable=True) # 责任人
date_of_close = Column(DateTime, nullable=True) # 关闭日期
vehicle_type = Column(String(100), nullable=True) # 车型
vin_sim = Column(String(50), nullable=True) # 车架号/SIM
app_remote_control_version = Column(String(100), nullable=True) # 应用远程控制版本
hmi_sw = Column(String(100), nullable=True) # HMI软件版本
parent_record = Column(String(100), nullable=True) # 父记录
has_updated_same_day = Column(String(50), nullable=True) # 是否同日更新
operating_time = Column(String(100), nullable=True) # 操作时间
# 工单分发和权限管理字段
assigned_module = Column(String(50), nullable=True) # 分配的模块TBOX、OTA等
module_owner = Column(String(100), nullable=True) # 业务接口人/模块负责人
dispatcher = Column(String(100), nullable=True) # 分发人(运维人员)
dispatch_time = Column(DateTime, nullable=True) # 分发时间
region = Column(String(50), nullable=True) # 区域overseas/domestic- 用于区分海外/国内
# 系统优化字段
processing_efficiency = Column(Float) # 处理效率
resource_usage = Column(Text) # 资源使用情况
# 关联对话记录
conversations = relationship("Conversation", back_populates="work_order")
# 关联处理过程记录
process_history = relationship("WorkOrderProcessHistory", back_populates="work_order", order_by="WorkOrderProcessHistory.process_time")
class ChatSession(Base):
"""对话会话模型 — 将多轮对话组织为一个会话"""
__tablename__ = "chat_sessions"
id = Column(Integer, primary_key=True)
tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True)
session_id = Column(String(100), unique=True, nullable=False) # 唯一会话标识
user_id = Column(String(100), nullable=True) # 用户标识
work_order_id = Column(Integer, ForeignKey("work_orders.id"), nullable=True)
title = Column(String(200), nullable=True) # 会话标题(取首条消息摘要)
status = Column(String(20), default="active") # active, ended
message_count = Column(Integer, default=0) # 消息轮数
source = Column(String(100), nullable=True) # 来源websocket, api, feishu_bot(group) 等
ip_address = Column(String(200), nullable=True) # IP地址或来源标识
created_at = Column(DateTime, default=datetime.now)
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
ended_at = Column(DateTime, nullable=True)
# 关联消息
messages = relationship("Conversation", back_populates="chat_session", order_by="Conversation.timestamp")
def to_dict(self):
return {
'id': self.id,
'session_id': self.session_id,
'user_id': self.user_id,
'work_order_id': self.work_order_id,
'title': self.title,
'status': self.status,
'message_count': self.message_count,
'source': self.source,
'ip_address': self.ip_address,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
'ended_at': self.ended_at.isoformat() if self.ended_at else None,
}
class Conversation(Base):
"""对话记录模型"""
__tablename__ = "conversations"
id = Column(Integer, primary_key=True)
tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True)
session_id = Column(String(100), ForeignKey("chat_sessions.session_id"), nullable=True) # 关联会话
work_order_id = Column(Integer, ForeignKey("work_orders.id"))
user_message = Column(Text, nullable=False)
assistant_response = Column(Text, nullable=False)
timestamp = Column(DateTime, default=datetime.now)
confidence_score = Column(Float)
knowledge_used = Column(Text) # 使用的知识库条目
response_time = Column(Float) # 响应时间(秒)
ip_address = Column(String(200), nullable=True) # IP地址或来源标识如 feishu:uid:name
invocation_method = Column(String(100), nullable=True) # 调用方式websocket, api, feishu_bot(group) 等)
# 系统优化字段
processing_time = Column(Float) # 处理时间
memory_usage = Column(Float) # 内存使用量
cpu_usage = Column(Float) # CPU使用率
work_order = relationship("WorkOrder", back_populates="conversations")
chat_session = relationship("ChatSession", back_populates="messages")
class KnowledgeEntry(Base):
"""知识库条目模型"""
__tablename__ = "knowledge_entries"
id = Column(Integer, primary_key=True)
tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True)
question = Column(Text, nullable=False)
answer = Column(Text, nullable=False)
category = Column(String(100), nullable=False)
confidence_score = Column(Float, default=0.0)
usage_count = Column(Integer, default=0)
created_at = Column(DateTime, default=datetime.now)
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
is_active = Column(Boolean, default=True)
is_verified = Column(Boolean, default=False) # 是否已验证
verified_by = Column(String(100)) # 验证人
verified_at = Column(DateTime) # 验证时间
vector_embedding = Column(Text) # 向量嵌入的JSON字符串
# 系统优化字段
search_frequency = Column(Integer, default=0) # 搜索频率
last_accessed = Column(DateTime) # 最后访问时间
relevance_score = Column(Float) # 相关性评分
class VehicleData(Base):
"""车辆实时数据模型"""
__tablename__ = "vehicle_data"
id = Column(Integer, primary_key=True)
vehicle_id = Column(String(50), nullable=False) # 车辆ID
vehicle_vin = Column(String(17)) # 车架号
data_type = Column(String(50), nullable=False) # 数据类型(位置、状态、故障等)
data_value = Column(Text, nullable=False) # 数据值JSON格式
timestamp = Column(DateTime, default=datetime.now) # 数据时间戳
is_active = Column(Boolean, default=True) # 是否有效
# 索引
__table_args__ = (
{'extend_existing': True}
)
class Analytics(Base):
"""分析统计模型"""
__tablename__ = "analytics"
id = Column(Integer, primary_key=True)
tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True)
date = Column(DateTime, nullable=False)
total_orders = Column(Integer, default=0)
resolved_orders = Column(Integer, default=0)
avg_resolution_time = Column(Float, default=0.0)
satisfaction_avg = Column(Float, default=0.0)
knowledge_hit_rate = Column(Float, default=0.0)
category_distribution = Column(Text) # JSON格式的类别分布
created_at = Column(DateTime, default=datetime.now)
# 分析增强字段
performance_score = Column(Float) # 性能评分
quality_metrics = Column(Text) # 质量指标JSON格式
cost_analysis = Column(Text) # 成本分析JSON格式
optimization_suggestions = Column(Text) # 优化建议JSON格式
class Alert(Base):
"""预警模型"""
__tablename__ = "alerts"
id = Column(Integer, primary_key=True)
tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True)
rule_name = Column(String(100), nullable=False)
alert_type = Column(String(50), nullable=False)
level = Column(String(20), nullable=False) # info, warning, error, critical
severity = Column(String(20), nullable=False, default="medium") # low, medium, high, critical
message = Column(Text, nullable=False)
data = Column(Text) # JSON格式的预警数据
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.now)
resolved_at = Column(DateTime)
class WorkOrderSuggestion(Base):
"""工单AI建议与人工描述表"""
__tablename__ = "work_order_suggestions"
id = Column(Integer, primary_key=True)
work_order_id = Column(Integer, ForeignKey("work_orders.id"), nullable=False)
ai_suggestion = Column(Text)
human_resolution = Column(Text)
ai_similarity = Column(Float)
approved = Column(Boolean, default=False)
use_human_resolution = Column(Boolean, default=False) # 是否使用人工描述入库
created_at = Column(DateTime, default=datetime.now)
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
class WorkOrderProcessHistory(Base):
"""工单处理过程记录表"""
__tablename__ = "work_order_process_history"
id = Column(Integer, primary_key=True)
work_order_id = Column(Integer, ForeignKey("work_orders.id"), nullable=False)
# 处理人员信息
processor_name = Column(String(100), nullable=False) # 处理人员姓名
processor_role = Column(String(50), nullable=True) # 处理人员角色(运维、业务方等)
processor_region = Column(String(50), nullable=True) # 处理人员区域overseas/domestic
# 处理内容
process_content = Column(Text, nullable=False) # 处理内容/操作描述
action_type = Column(String(50), nullable=False) # 操作类型dispatch、process、close、reassign等
# 处理结果
previous_status = Column(String(50), nullable=True) # 处理前的状态
new_status = Column(String(50), nullable=True) # 处理后的状态
assigned_module = Column(String(50), nullable=True) # 分配的模块(如果是分发操作)
# 时间戳
process_time = Column(DateTime, default=datetime.now, nullable=False) # 处理时间
created_at = Column(DateTime, default=datetime.now)
# 关联工单
work_order = relationship("WorkOrder", back_populates="process_history")
class User(Base):
"""用户模型"""
__tablename__ = "users"
id = Column(Integer, primary_key=True)
tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True)
username = Column(String(50), unique=True, nullable=False)
password_hash = Column(String(128), nullable=False)
email = Column(String(120), unique=True, nullable=True)
name = Column(String(100), nullable=True)
role = Column(String(20), default='user') # admin, user, operator
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.now)
last_login = Column(DateTime)
def set_password(self, password):
"""设置密码哈希"""
self.password_hash = hashlib.sha256(password.encode()).hexdigest()
def check_password(self, password):
"""验证密码"""
return self.password_hash == hashlib.sha256(password.encode()).hexdigest()
def to_dict(self):
"""转换为字典格式用于API响应"""
return {
'id': self.id,
'username': self.username,
'email': self.email,
'name': self.name,
'role': self.role,
'is_active': self.is_active,
'created_at': self.created_at.isoformat() if self.created_at else None,
'last_login': self.last_login.isoformat() if self.last_login else None
}