- **文件管理**: - 支持文件上传、解析和删除。 - 限制支持格式(txt, md, docx, pdf),最大 10MB。 - 提供前端上传区、文件列表及后端解析服务。 - **技能管理**: - 新增技能的创建、更新及删除功能。 - 支持分配自定义提示词和工具权限。 - 提供技能列表及分组工具选择交互界面。 同时调整相关 API 和前端组件,优化协作体验。
This commit is contained in:
111
backend/app/routers/skills.py
Normal file
111
backend/app/routers/skills.py
Normal file
@@ -0,0 +1,111 @@
|
||||
"""Skill 插件管理路由"""
|
||||
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from sqlmodel import Session, select, or_
|
||||
|
||||
from ..database import engine
|
||||
from ..models import Skill
|
||||
from ..schemas import SkillCreate, SkillUpdate, SkillRead, SkillList, ToolInfo
|
||||
from ..services.tools import TOOL_DEFINITIONS
|
||||
|
||||
router = APIRouter(prefix="/api/skills", tags=["skills"])
|
||||
|
||||
|
||||
def _skill_to_read(skill: Skill) -> SkillRead:
|
||||
"""将 Skill ORM 对象转为 SkillRead,反序列化 allowed_tools"""
|
||||
try:
|
||||
tools = json.loads(skill.allowed_tools) if skill.allowed_tools else []
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
tools = []
|
||||
return SkillRead(
|
||||
id=skill.id, # type: ignore
|
||||
name=skill.name,
|
||||
description=skill.description,
|
||||
system_prompt=skill.system_prompt,
|
||||
allowed_tools=tools,
|
||||
is_builtin=skill.is_builtin,
|
||||
novel_id=skill.novel_id,
|
||||
created_at=skill.created_at,
|
||||
updated_at=skill.updated_at,
|
||||
)
|
||||
|
||||
|
||||
@router.get("", response_model=SkillList)
|
||||
def list_skills(novel_id: int | None = None):
|
||||
"""列出 Skill,返回全局 + 指定小说的"""
|
||||
with Session(engine) as session:
|
||||
if novel_id is not None:
|
||||
stmt = (
|
||||
select(Skill)
|
||||
.where(or_(Skill.novel_id.is_(None), Skill.novel_id == novel_id)) # type: ignore
|
||||
.order_by(Skill.is_builtin.desc(), Skill.created_at) # type: ignore
|
||||
)
|
||||
else:
|
||||
stmt = select(Skill).order_by(Skill.is_builtin.desc(), Skill.created_at) # type: ignore
|
||||
skills = session.exec(stmt).all()
|
||||
items = [_skill_to_read(s) for s in skills]
|
||||
return SkillList(items=items, total=len(items))
|
||||
|
||||
|
||||
@router.post("", response_model=SkillRead, status_code=201)
|
||||
def create_skill(data: SkillCreate):
|
||||
"""创建 Skill"""
|
||||
with Session(engine) as session:
|
||||
skill = Skill(
|
||||
name=data.name,
|
||||
description=data.description,
|
||||
system_prompt=data.system_prompt,
|
||||
allowed_tools=json.dumps(data.allowed_tools, ensure_ascii=False),
|
||||
is_builtin=False,
|
||||
novel_id=data.novel_id,
|
||||
)
|
||||
session.add(skill)
|
||||
session.commit()
|
||||
session.refresh(skill)
|
||||
return _skill_to_read(skill)
|
||||
|
||||
|
||||
@router.get("/tools", response_model=list[ToolInfo])
|
||||
def get_available_tools():
|
||||
"""返回所有可用工具名和描述(供前端工具 checkbox 使用)"""
|
||||
return [
|
||||
ToolInfo(name=t["name"], description=t["description"])
|
||||
for t in TOOL_DEFINITIONS
|
||||
]
|
||||
|
||||
|
||||
@router.patch("/{skill_id}", response_model=SkillRead)
|
||||
def update_skill(skill_id: int, data: SkillUpdate):
|
||||
"""更新 Skill"""
|
||||
with Session(engine) as session:
|
||||
skill = session.get(Skill, skill_id)
|
||||
if not skill:
|
||||
raise HTTPException(status_code=404, detail="Skill 不存在")
|
||||
|
||||
if data.name is not None:
|
||||
skill.name = data.name
|
||||
if data.description is not None:
|
||||
skill.description = data.description
|
||||
if data.system_prompt is not None:
|
||||
skill.system_prompt = data.system_prompt
|
||||
if data.allowed_tools is not None:
|
||||
skill.allowed_tools = json.dumps(data.allowed_tools, ensure_ascii=False)
|
||||
skill.updated_at = datetime.now(timezone.utc)
|
||||
session.add(skill)
|
||||
session.commit()
|
||||
session.refresh(skill)
|
||||
return _skill_to_read(skill)
|
||||
|
||||
|
||||
@router.delete("/{skill_id}", status_code=204)
|
||||
def delete_skill(skill_id: int):
|
||||
"""删除 Skill"""
|
||||
with Session(engine) as session:
|
||||
skill = session.get(Skill, skill_id)
|
||||
if not skill:
|
||||
raise HTTPException(status_code=404, detail="Skill 不存在")
|
||||
session.delete(skill)
|
||||
session.commit()
|
||||
Reference in New Issue
Block a user