first commit

This commit is contained in:
2026-07-17 17:45:56 +08:00
commit 04c487823b
5873 changed files with 12227228 additions and 0 deletions
+151
View File
@@ -0,0 +1,151 @@
from __future__ import annotations
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from .config import settings
from .extractor import SolidWorksExtractor
from .grader import FeatureGrader
from .knowledge import KnowledgeRepository
from .models import (
AuditPartRequest,
ObservationRequest,
SessionMode,
StandardKind,
StartSessionRequest,
SubmitTestRequest,
)
from .sessions import LearningService, SessionStore
from .skillflow import normalize_steps
app = FastAPI(title=settings.app_name)
app.add_middleware(
CORSMiddleware,
allow_origins=[
"http://localhost:5173",
"http://127.0.0.1:5173",
"http://localhost:5174",
"http://127.0.0.1:5174",
"http://localhost:5175",
"http://127.0.0.1:5175",
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
knowledge = KnowledgeRepository()
store = SessionStore()
grader = FeatureGrader()
learning = LearningService(store, grader)
extractor = SolidWorksExtractor()
@app.get("/health")
async def health() -> dict[str, object]:
return {
"ok": True,
"service": settings.app_name,
"standards": len(knowledge.list_standards()),
"software_paths": settings.software_paths(),
}
@app.post("/api/knowledge/reload")
async def reload_knowledge() -> dict[str, object]:
knowledge.reload()
return {"ok": True, "standards": len(knowledge.list_standards())}
@app.get("/api/standards")
async def list_standards(query: str = "", kind: StandardKind | None = None) -> dict[str, object]:
items = knowledge.list_standards(query=query, kind=kind)
return {"items": [item.model_dump(mode="json", exclude={"raw"}) for item in items]}
@app.get("/api/standards/{standard_id}")
async def get_standard(standard_id: str) -> dict[str, object]:
try:
return knowledge.require(standard_id).model_dump(mode="json")
except KeyError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@app.post("/api/teaching/sessions")
async def start_teaching(request: StartSessionRequest) -> dict[str, object]:
try:
standard = knowledge.require(request.standard_id)
except KeyError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
return store.start(SessionMode.teaching, standard).model_dump(mode="json")
@app.post("/api/testing/sessions")
async def start_testing(request: StartSessionRequest) -> dict[str, object]:
try:
standard = knowledge.require(request.standard_id)
except KeyError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
return store.start(SessionMode.testing, standard).model_dump(mode="json")
@app.get("/api/sessions/{session_id}")
async def get_session(session_id: str) -> dict[str, object]:
try:
return store.require(session_id).model_dump(mode="json")
except KeyError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@app.post("/api/teaching/sessions/{session_id}/observations")
async def submit_teaching_observation(session_id: str, request: ObservationRequest) -> dict[str, object]:
observed = normalize_steps({"steps": request.steps})
try:
result = learning.submit_teaching_observation(session_id, observed)
return result.model_dump(mode="json")
except KeyError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@app.post("/api/teaching/sessions/{session_id}/audit-part")
async def audit_part_for_teaching(session_id: str, request: AuditPartRequest) -> dict[str, object]:
try:
observed = extractor.audit_part(request.part_path)
result = learning.submit_teaching_observation(session_id, observed[-1:] if observed else [])
return {"observed_steps": [item.model_dump(mode="json") for item in observed], "result": result.model_dump(mode="json")}
except KeyError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
@app.post("/api/teaching/sessions/{session_id}/audit-active-part")
async def audit_active_part_for_teaching(session_id: str) -> dict[str, object]:
try:
session = store.require(session_id)
observed = extractor.audit_active_part()
current_index = session.current_step_index
current_step = observed[current_index : current_index + 1] if current_index < len(observed) else []
result = learning.submit_teaching_observation(session_id, current_step)
return {
"observed_steps": [item.model_dump(mode="json") for item in observed],
"submitted_steps": [item.model_dump(mode="json") for item in current_step],
"result": result.model_dump(mode="json"),
}
except KeyError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
@app.post("/api/testing/sessions/{session_id}/submit")
async def submit_test(session_id: str, request: SubmitTestRequest) -> dict[str, object]:
try:
observed = extractor.audit_part(request.part_path) if request.part_path else normalize_steps({"steps": request.steps})
report = learning.submit_test(session_id, observed)
return report.model_dump(mode="json")
except KeyError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc