add choose skills function
This commit is contained in:
53
app/main.py
53
app/main.py
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user