精简后端功能模块并补充教学互动

This commit is contained in:
刘金宝
2026-06-08 16:49:45 +08:00
parent 11b1712b01
commit f0cdc454b3
18 changed files with 1120 additions and 1194 deletions
-24
View File
@@ -1,24 +0,0 @@
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from app.core.response import ApiResponse, ok
from app.core.user_context import UserContext, get_user_context
from app.db.session import get_db
from app.schemas.knowledge import KnowledgeSearchResponse
from app.services.knowledge_service import KnowledgeService
router = APIRouter()
@router.get("/search", response_model=ApiResponse[KnowledgeSearchResponse])
def search_knowledge(
_: UserContext = Depends(get_user_context),
db: Session = Depends(get_db),
department_id: int = Query(...),
training_type: str = Query(...),
q: str = Query(default=""),
):
"""知识检索:按科室、训练类别和关键词检索评分参考指南。"""
keywords = [item.strip() for item in q.split(",") if item.strip()]
result = KnowledgeService(db).search_guidelines(department_id, training_type, keywords)
return ok(KnowledgeSearchResponse(**result))
-108
View File
@@ -1,108 +0,0 @@
import time
from fastapi import APIRouter, Depends
from app.agents.llm_adapter import OpenAICompatibleLLMClient
from app.core.config import settings
from app.core.exceptions import AppError
from app.core.response import ApiResponse, ok
from app.core.user_context import UserContext, get_user_context
from app.schemas.llm import LLMTestRequest, LLMTestResponse
router = APIRouter()
@router.post("/deepseek-fast", response_model=ApiResponse[LLMTestResponse])
async def test_deepseek_fast(
payload: LLMTestRequest,
_: UserContext = Depends(get_user_context),
):
"""Fast 模型测试:验证快速模型的非流式响应耗时。"""
client = OpenAICompatibleLLMClient()
response = await client.chat(
[{"role": "user", "content": payload.message}],
settings.llm_fast_model,
thinking_enabled=settings.llm_fast_thinking_enabled,
max_tokens=min(settings.llm_fast_max_tokens, 256),
)
return ok(
LLMTestResponse(
model=response.model,
total_latency_ms=response.latency_ms,
stream=False,
mock_mode=client.is_mock_mode,
fallback_used=response.model.startswith("mock-fallback"),
thinking_enabled=settings.llm_fast_thinking_enabled,
)
)
@router.post("/deepseek-reason", response_model=ApiResponse[LLMTestResponse])
async def test_deepseek_reason(
payload: LLMTestRequest,
_: UserContext = Depends(get_user_context),
):
"""Reason 模型测试:优先验证流式耗时,流式不兼容时降级为真实非流式测试。"""
client = OpenAICompatibleLLMClient()
messages = [{"role": "user", "content": payload.message}]
first_token_ms = None
start = time.perf_counter()
try:
async for chunk in client.stream_chat(
messages,
settings.llm_reason_model,
thinking_enabled=settings.llm_reason_thinking_enabled,
reasoning_effort=settings.llm_reasoning_effort if settings.llm_reason_thinking_enabled else None,
max_tokens=min(settings.llm_fast_max_tokens, 256),
):
if first_token_ms is None and chunk.first_token_ms is not None:
first_token_ms = chunk.first_token_ms
if chunk.done:
return ok(
LLMTestResponse(
model=chunk.model or (settings.llm_reason_model if not client.is_mock_mode else f"mock-{settings.llm_reason_model}"),
first_token_ms=first_token_ms,
total_latency_ms=chunk.total_latency_ms or int((time.perf_counter() - start) * 1000),
stream=True,
mock_mode=client.is_mock_mode,
fallback_used=chunk.fallback_used,
thinking_enabled=settings.llm_reason_thinking_enabled,
reasoning_effort=settings.llm_reasoning_effort if settings.llm_reason_thinking_enabled else None,
)
)
except AppError as exc:
if exc.code != "LLM_STREAM_FAILED":
raise
response = await client.chat(
messages,
settings.llm_reason_model,
thinking_enabled=settings.llm_reason_thinking_enabled,
reasoning_effort=settings.llm_reasoning_effort if settings.llm_reason_thinking_enabled else None,
max_tokens=min(settings.llm_fast_max_tokens, 256),
)
return ok(
LLMTestResponse(
model=response.model,
first_token_ms=None,
total_latency_ms=response.latency_ms,
stream=False,
mock_mode=client.is_mock_mode,
fallback_used=response.model.startswith("mock-fallback"),
thinking_enabled=settings.llm_reason_thinking_enabled,
reasoning_effort=settings.llm_reasoning_effort if settings.llm_reason_thinking_enabled else None,
)
)
return ok(
LLMTestResponse(
model=settings.llm_reason_model,
first_token_ms=first_token_ms,
total_latency_ms=int((time.perf_counter() - start) * 1000),
stream=True,
mock_mode=client.is_mock_mode,
fallback_used=False,
thinking_enabled=settings.llm_reason_thinking_enabled,
reasoning_effort=settings.llm_reasoning_effort if settings.llm_reason_thinking_enabled else None,
)
)
+2 -3
View File
@@ -1,6 +1,6 @@
from fastapi import APIRouter
from app.api import agent, auth, cases, evaluations, knowledge, llm_test, sessions, training_config
from app.api import agent, auth, cases, evaluations, sessions, teaching, training_config
api_router = APIRouter()
api_router.include_router(agent.router, tags=["agent"])
@@ -8,6 +8,5 @@ api_router.include_router(auth.router, prefix="/auth", tags=["auth"])
api_router.include_router(cases.router, prefix="/cases", tags=["cases"])
api_router.include_router(training_config.router, prefix="/training-config", tags=["training-config"])
api_router.include_router(sessions.router, prefix="/sessions", tags=["sessions"])
api_router.include_router(teaching.router, prefix="/teaching", tags=["teaching"])
api_router.include_router(evaluations.router, prefix="/evaluations", tags=["evaluations"])
api_router.include_router(knowledge.router, prefix="/knowledge", tags=["knowledge"])
api_router.include_router(llm_test.router, prefix="/llm/test", tags=["llm-test"])
+32
View File
@@ -0,0 +1,32 @@
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from app.core.response import ApiResponse, ok
from app.core.user_context import UserContext, get_user_context
from app.db.session import get_db
from app.schemas.teaching import CreateTeachingEvaluationRequest, TeachingEvaluationResponse, TeachingItemsResponse
from app.services.teaching_service import TeachingService
router = APIRouter()
@router.get("/cases/{case_id}/items", response_model=ApiResponse[TeachingItemsResponse])
def get_teaching_items(
case_id: int,
ctx: UserContext = Depends(get_user_context),
db: Session = Depends(get_db),
):
"""教学列表:返回病例、题目、选项、答案、解析文本和教学视频。"""
return ok(TeachingService(db).list_items(ctx, case_id))
@router.post("/evaluation", response_model=ApiResponse[TeachingEvaluationResponse])
async def create_teaching_evaluation(
payload: CreateTeachingEvaluationRequest,
ctx: UserContext = Depends(get_user_context),
db: Session = Depends(get_db),
):
"""教学评价:根据教学互动作答生成 AI 评价并写入训练记录。"""
result = await TeachingService(db).create_evaluation(ctx, payload)
db.commit()
return ok(result)