136 lines
5.0 KiB
Python
136 lines
5.0 KiB
Python
"""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
|