""" Bot 服务层 实现 Bot 的 CRUD、权限控制、Token 管理、Agent 绑定等功能 """ import secrets import hashlib from datetime import datetime from typing import Optional, List, Dict, Any, Tuple from app.extensions import db from app.models import Bot, User, Agent class BotService: """Bot 服务类""" @staticmethod def generate_token() -> str: """生成 Bot API Token""" return f"bot_{secrets.token_urlsafe(32)}" @staticmethod def hash_token(token: str) -> str: """Hash Token 用于存储""" return hashlib.sha256(token.encode()).hexdigest() @staticmethod def verify_token(bot: Bot, token: str) -> bool: """验证 Token""" if not bot.token_hash: return False return bot.token_hash == BotService.hash_token(token) @staticmethod def check_permission(user: User, bot: Bot, action: str) -> bool: """ 检查用户对 Bot 的权限 Args: user: 当前用户 bot: Bot 对象 action: 操作类型 ('view', 'use', 'edit', 'delete', 'bind') Returns: 是否有权限 """ # 管理员拥有所有权限 if user.role == 'admin': return True # 查看/使用权限 if action in ['view', 'use']: # 系统级 Bot 所有用户可用 if bot.is_system: return True # 自己的 Bot return bot.owner_id == user.id # 编辑/删除/绑定权限 if action in ['edit', 'delete', 'bind']: # 只有所有者可以编辑/删除/绑定 return bot.owner_id == user.id return False @staticmethod def create_bot( name: str, owner_id: str, display_name: Optional[str] = None, avatar: Optional[str] = None, description: Optional[str] = None, is_system: bool = False, agent_id: Optional[str] = None, capabilities: Optional[List[str]] = None, config: Optional[Dict[str, Any]] = None ) -> Tuple[Bot, str]: """ 创建 Bot Returns: (Bot 对象, 明文 Token) """ # 生成 Token token = BotService.generate_token() token_hash = BotService.hash_token(token) bot = Bot( name=name, display_name=display_name or name, avatar=avatar, description=description, owner_id=owner_id, agent_id=agent_id, token_hash=token_hash, is_system=is_system, capabilities=capabilities or ['chat'], config=config or BotService.get_default_config(), status='offline', created_at=datetime.utcnow() ) db.session.add(bot) db.session.commit() return bot, token @staticmethod def get_default_config() -> Dict[str, Any]: """获取默认 Bot 配置""" return { "model": "gpt-4o", "temperature": 0.7, "max_tokens": 4096, "system_prompt": "", "rate_limit": { "requests_per_minute": 60, "tokens_per_day": 100000 }, "features": { "streaming": True, "markdown": True, "code_highlight": True, "file_upload": False }, "context": { "max_history": 20, "summary_threshold": 10 } } @staticmethod def get_bot_by_id(bot_id: str) -> Optional[Bot]: """根据 ID 获取 Bot""" return Bot.query.get(bot_id) @staticmethod def get_bot_by_name(name: str) -> Optional[Bot]: """根据名称获取 Bot""" return Bot.query.filter_by(name=name).first() @staticmethod def get_bots_by_owner(owner_id: str) -> List[Bot]: """获取用户的所有 Bot""" return Bot.query.filter_by(owner_id=owner_id).order_by(Bot.created_at.desc()).all() @staticmethod def get_system_bots() -> List[Bot]: """获取所有系统级 Bot""" return Bot.query.filter_by(is_system=True).order_by(Bot.created_at.desc()).all() @staticmethod def get_available_bots(user: User) -> List[Bot]: """ 获取用户可用的所有 Bot - 自己的 Bot - 系统级 Bot """ if user.role == 'admin': return Bot.query.order_by(Bot.created_at.desc()).all() return Bot.query.filter( (Bot.owner_id == user.id) | (Bot.is_system == True) ).order_by(Bot.created_at.desc()).all() @staticmethod def update_bot( bot: Bot, display_name: Optional[str] = None, avatar: Optional[str] = None, description: Optional[str] = None, capabilities: Optional[List[str]] = None, config: Optional[Dict[str, Any]] = None ) -> Bot: """更新 Bot 信息""" if display_name is not None: bot.display_name = display_name if avatar is not None: bot.avatar = avatar if description is not None: bot.description = description if capabilities is not None: bot.capabilities = capabilities if config is not None: bot.config = {**bot.config, **config} if bot.config else config db.session.commit() return bot @staticmethod def bind_agent(bot: Bot, agent_id: Optional[str]) -> Bot: """ 绑定/解绑 Agent Args: bot: Bot 对象 agent_id: Agent ID,None 表示解绑 """ bot.agent_id = agent_id # 更新状态 if agent_id: agent = Agent.query.get(agent_id) if agent and agent.status == 'online': bot.status = 'online' else: bot.status = 'offline' else: bot.status = 'offline' db.session.commit() return bot @staticmethod def regenerate_token(bot: Bot) -> str: """重新生成 Token""" token = BotService.generate_token() bot.token_hash = BotService.hash_token(token) db.session.commit() return token @staticmethod def delete_bot(bot: Bot) -> bool: """删除 Bot""" try: db.session.delete(bot) db.session.commit() return True except Exception as e: db.session.rollback() return False @staticmethod def update_status(bot: Bot, status: str) -> Bot: """更新 Bot 状态""" bot.status = status bot.last_active_at = datetime.utcnow() db.session.commit() return bot @staticmethod def sync_agent_status(bot: Bot) -> Bot: """ 同步 Agent 状态到 Bot 当 Agent 状态变化时调用 """ if bot.agent_id: agent = Agent.query.get(bot.agent_id) if agent: bot.status = agent.status else: bot.status = 'offline' else: bot.status = 'offline' bot.last_active_at = datetime.utcnow() db.session.commit() return bot @staticmethod def get_bot_stats(bot: Bot) -> Dict[str, Any]: """获取 Bot 统计信息""" from app.models import Session, Message session_count = Session.query.filter_by(bot_id=bot.id).count() message_count = Message.query.filter_by(bot_id=bot.id).count() return { 'bot_id': bot.id, 'name': bot.name, 'status': bot.status, 'session_count': session_count, 'message_count': message_count, 'is_system': bot.is_system, 'created_at': bot.created_at.isoformat() if bot.created_at else None, 'last_active_at': bot.last_active_at.isoformat() if bot.last_active_at else None, }