from typing import Any
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from backend.config import PROJECT_ROOT
from backend.label_service import (
get_public_response,
label_one,
read_prompt,
read_samples,
validate_task,
)
from backend.sample_generator import (
generate_sample,
get_generated_sample,
list_generated_samples,
)
app = FastAPI(title="金融文本统一打标系统")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
FRONTEND_DIR = PROJECT_ROOT / "frontend"
app.mount("/static", StaticFiles(directory=FRONTEND_DIR), name="static")
class LabelRequest(BaseModel):
task: str
sample_id: str | None = None
text: str | None = None
text_a: str | None = None
text_b: str | None = None
class GenerateSampleRequest(BaseModel):
task: str
difficulty: str
@app.get("/")
def index() -> FileResponse:
return FileResponse(FRONTEND_DIR / "index.html")
@app.get("/prompt/{task}")
def get_prompt(task: str) -> dict[str, str]:
try:
return {"task": task, "prompt": read_prompt(task)}
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@app.get("/samples/{task}")
def get_samples(task: str, difficulty: str | None = None) -> dict[str, Any]:
try:
file_samples = read_samples(task, difficulty)
generated_samples = list_generated_samples(task, difficulty)
return {
"task": task,
"difficulty": difficulty,
"samples": generated_samples + file_samples,
}
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@app.post("/generate-sample")
def generate_sample_api(request: GenerateSampleRequest) -> dict[str, Any]:
try:
validate_task(request.task)
sample = generate_sample(request.task, request.difficulty)
return {"task": request.task, "sample": sample}
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
except RuntimeError as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
except Exception as exc:
raise HTTPException(
status_code=500,
detail=f"生成测试数据时发生异常:{exc}",
) from exc
@app.post("/label")
def label(request: LabelRequest) -> dict[str, Any]:
try:
validate_task(request.task)
payload = request.model_dump(exclude_none=True)
task = payload.pop("task")
sample_id = payload.pop("sample_id", None)
sample = None
if sample_id:
sample = get_generated_sample(sample_id) or next(
(
item
for item in read_samples(task)
if item.get("id") == sample_id
),
None,
)
if sample is None:
raise ValueError(f"未找到示例数据:{sample_id}")
record = label_one(task, payload, sample=sample)
return get_public_response(record)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
except RuntimeError as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc