"""Skill Service""" import uuid from typing import List from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import Session from app.repositories.skill_repository import SkillRepository from app.schemas.skill_schema import SkillCreate, SkillUpdate from app.models.skill_model import Skill from app.core.exceptions import BusinessException from app.core.error_codes import BizCode from app.services.tool_service import ToolService class SkillService: """Skill 业务逻辑层""" @staticmethod def create_skill(db: Session, data: SkillCreate, tenant_id: uuid.UUID) -> Skill: """创建技能""" # 检查同名技能 existing = db.query(Skill).filter( Skill.tenant_id == tenant_id, Skill.name == data.name ).first() if existing: raise BusinessException(f"技能名称'{data.name}'已存在", BizCode.DUPLICATE_NAME) skill = SkillRepository.create(db, data, tenant_id) db.commit() db.refresh(skill) return skill @staticmethod def get_skill(db: Session, skill_id: uuid.UUID, tenant_id: uuid.UUID) -> Skill: """获取技能""" try: skill = SkillRepository.get_by_id(db, skill_id, tenant_id) if not skill: raise BusinessException(f"技能{skill_id}不存在", BizCode.NOT_FOUND) # 填充工具详情 tool_service = ToolService(db) enriched_tools = [] for tool_config in skill.tools: tool_id = tool_config.get("tool_id") if tool_id: tool_info = tool_service.get_tool_info(tool_id, tenant_id) if tool_info: enriched_tool = { "tool_id": tool_id, "tool_info": tool_info } if "operation" in tool_config: enriched_tool["operation"] = tool_config["operation"] enriched_tools.append(enriched_tool) skill.tools = enriched_tools return skill except (BusinessException, SQLAlchemyError) as e: db.rollback() raise e @staticmethod def list_skills( db: Session, tenant_id: uuid.UUID, search: str = None, is_active: bool = None, is_public: bool = None, page: int = 1, pagesize: int = 10 ) -> tuple[list[type[Skill]], int]: """列出技能""" return SkillRepository.list_skills( db, tenant_id, search, is_active, is_public, page, pagesize ) @staticmethod def update_skill(db: Session, skill_id: uuid.UUID, data: SkillUpdate, tenant_id: uuid.UUID) -> Skill: """更新技能""" try: skill = SkillRepository.update(db, skill_id, data, tenant_id) if not skill: raise BusinessException(f"技能{skill_id}不存在或无权限", BizCode.NOT_FOUND) db.commit() db.refresh(skill) return skill except (BusinessException, SQLAlchemyError) as e: db.rollback() raise e @staticmethod def delete_skill(db: Session, skill_id: uuid.UUID, tenant_id: uuid.UUID) -> bool: """删除技能""" try: success = SkillRepository.delete(db, skill_id, tenant_id) if not success: raise BusinessException("技能不存在或无权限", BizCode.NOT_FOUND) db.commit() return True except (BusinessException, SQLAlchemyError) as e: db.rollback() raise e @staticmethod def load_skill_tools(db: Session, skill_ids: List[str], tenant_id: uuid.UUID) -> tuple[List, dict[str, str]]: """加载技能关联的工具 Returns: (tools, tool_to_skill_map) - 工具列表和工具到技能的映射 """ tools = [] tool_to_skill_map = {} # {tool_name: skill_id} tool_service = ToolService(db) for skill_id in skill_ids: try: skill = SkillRepository.get_by_id(db, uuid.UUID(skill_id), tenant_id) if skill and skill.is_active: # 加载技能关联的工具 for tool_config in skill.tools: tool = tool_service.get_tool_instance(tool_config.get("tool_id", ""), tenant_id) if tool: langchain_tool = tool.to_langchain_tool(tool_config.get("operation", None)) tools.append(langchain_tool) # 建立工具到技能的映射 tool_name = getattr(langchain_tool, 'name', str(id(langchain_tool))) tool_to_skill_map[tool_name] = skill_id except Exception as e: print(f"加载技能 {skill_id} 的工具时出错: {e}") continue return tools, tool_to_skill_map