add choose skills function

This commit is contained in:
kuangji
2026-05-19 13:22:25 +08:00
parent 1e20f84257
commit 6661f3e361
6 changed files with 118 additions and 10 deletions

View File

@@ -9,7 +9,7 @@ from uuid import uuid4
from typing import Callable
from fastapi import FastAPI, File, Form, HTTPException, Request, UploadFile
from fastapi.responses import FileResponse, HTMLResponse
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
@@ -29,12 +29,41 @@ from app.skill_loader import load_skill_catalog
ROOT_DIR = Path(__file__).resolve().parent.parent
UPLOAD_DIR = ROOT_DIR / "uploads"
OUTPUT_DIR = ROOT_DIR / "outputs"
SKILL_DIR = ROOT_DIR / "GJB438C-2021_prd_skills"
SKILL_ROOT = ROOT_DIR / "skills"
DEFAULT_SKILL_COLLECTION = "GJB438C-2021_prd_skills"
SKILL_COLLECTIONS = [
"GJB438B-2009_prd_skills",
"GJB438C-2021_prd_skills",
]
CONFIG_PATH = ROOT_DIR / "configs" / "api_config.yaml"
MAX_UPLOAD_BYTES = 30 * 1024 * 1024
ProgressCallback = Callable[[int, str], None]
def _skill_collection_path(collection_slug: str) -> Path:
path = SKILL_ROOT / collection_slug
if not path.exists() or not path.is_dir() or not (path / "index.md").exists():
raise HTTPException(status_code=400, detail="技能集合不存在")
return path
def _skill_collection_options() -> list[dict[str, object]]:
options: list[dict[str, object]] = []
for collection_slug in SKILL_COLLECTIONS:
path = SKILL_ROOT / collection_slug
if not path.exists() or not path.is_dir() or not (path / "index.md").exists():
continue
skills = load_skill_catalog(path)
options.append(
{
"slug": collection_slug,
"label": collection_slug.replace("_prd_skills", ""),
"skill_count": len(skills),
}
)
return options
@dataclass
class AnalysisTask:
task_id: str
@@ -124,6 +153,7 @@ def analyze_saved_docx(
provider: str | None = None,
use_model: bool = True,
display_filename: str | None = None,
skill_collection: str = DEFAULT_SKILL_COLLECTION,
progress_callback: ProgressCallback | None = None,
) -> dict[str, object]:
def progress(percent: int, message: str) -> None:
@@ -133,7 +163,7 @@ def analyze_saved_docx(
progress(5, "正在解析 DOCX 文档")
parsed = parse_docx(upload_path, display_filename=display_filename)
progress(20, "DOCX 解析完成,正在加载技能规范")
skills = load_skill_catalog(SKILL_DIR)
skills = load_skill_catalog(_skill_collection_path(skill_collection))
progress(35, "技能规范已加载,正在匹配候选技能")
selected_skills = select_relevant_skills(parsed, skills)
progress(50, f"已匹配 {len(selected_skills)} 项技能,正在读取模型配置")
@@ -186,6 +216,7 @@ def _run_analysis_task(
provider: str | None,
use_model: bool,
display_filename: str,
skill_collection: str = DEFAULT_SKILL_COLLECTION,
) -> None:
def on_progress(progress: int, message: str) -> None:
TASK_STORE.update(task_id, status="running", progress=progress, message=message)
@@ -197,6 +228,7 @@ def _run_analysis_task(
provider=provider,
use_model=use_model,
display_filename=display_filename,
skill_collection=skill_collection,
progress_callback=on_progress,
)
TASK_STORE.update(
@@ -215,13 +247,14 @@ def _run_analysis_task(
@app.get("/", response_class=HTMLResponse)
def index(request: Request) -> HTMLResponse:
settings = load_api_config(CONFIG_PATH)
skills = load_skill_catalog(SKILL_DIR)
return templates.TemplateResponse(
request,
"index.html",
{
"default_provider": settings.provider_name,
"skill_count": len(skills),
"skill_collection_count": len(SKILL_COLLECTIONS),
"skill_collections": _skill_collection_options(),
"default_skill_collection": DEFAULT_SKILL_COLLECTION,
},
)
@@ -231,6 +264,7 @@ async def analyze_docx(
file: UploadFile = File(...),
provider: str | None = Form(None),
use_model: str = Form("true"),
skill_collection: str = Form(DEFAULT_SKILL_COLLECTION),
):
if not file.filename or not file.filename.lower().endswith(".docx"):
raise HTTPException(status_code=400, detail="仅支持上传 .docx 文件")
@@ -248,7 +282,14 @@ async def analyze_docx(
task = TASK_STORE.create(Path(file.filename).name)
threading.Thread(
target=_run_analysis_task,
args=(task.task_id, upload_path, provider, should_use_model, Path(file.filename).name),
args=(
task.task_id,
upload_path,
provider,
should_use_model,
Path(file.filename).name,
skill_collection,
),
daemon=True,
).start()
return {