""" 知识点分析 API 使用 Python 原生 AI 服务实现 """ import logging from typing import Dict, Any from fastapi import APIRouter, Depends, HTTPException, status, BackgroundTasks from sqlalchemy.ext.asyncio import AsyncSession from app.core.deps import get_db, get_current_user from app.schemas.base import ResponseModel from app.models.user import User from app.services.course_service import course_service from app.services.ai.knowledge_analysis_v2 import knowledge_analysis_service_v2 logger = logging.getLogger(__name__) router = APIRouter() @router.post("/courses/{course_id}/materials/{material_id}/analyze", response_model=ResponseModel[Dict[str, Any]]) async def analyze_material_knowledge_points( course_id: int, material_id: int, background_tasks: BackgroundTasks, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """ 分析单个资料的知识点 - **course_id**: 课程ID - **material_id**: 资料ID 使用 Python 原生 AI 服务: - 本地 AI 服务调用(4sapi.com 首选,OpenRouter 备选) - 多层 JSON 解析兜底 - 无外部平台依赖,更稳定 """ try: # 验证课程是否存在 course = await course_service.get_by_id(db, course_id) if not course: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"课程 {course_id} 不存在" ) # 获取资料信息 materials = await course_service.get_course_materials(db, course_id=course_id) material = next((m for m in materials if m.id == material_id), None) if not material: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"资料 {material_id} 不存在" ) logger.info( f"准备启动知识点分析 - course_id: {course_id}, material_id: {material_id}, " f"file_url: {material.file_url}, user_id: {current_user.id}" ) # 调用 Python 原生知识点分析服务 result = await knowledge_analysis_service_v2.analyze_course_material( db=db, course_id=course_id, material_id=material_id, file_url=material.file_url, course_title=course.name, user_id=current_user.id ) logger.info( f"知识点分析完成 - course_id: {course_id}, material_id: {material_id}, " f"knowledge_points: {result.get('knowledge_points_count', 0)}, " f"provider: {result.get('ai_provider')}" ) # 构建响应 response_data = { "message": "知识点分析完成", "course_id": course_id, "material_id": material_id, "status": result.get("status", "completed"), "knowledge_points_count": result.get("knowledge_points_count", 0), "ai_provider": result.get("ai_provider"), "ai_model": result.get("ai_model"), "ai_tokens": result.get("ai_tokens"), "ai_latency_ms": result.get("ai_latency_ms"), } return ResponseModel( data=response_data, message="知识点分析完成" ) except HTTPException: raise except Exception as e: logger.error( f"知识点分析失败 - course_id: {course_id}, material_id: {material_id}, error: {e}", exc_info=True ) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"知识点分析失败: {str(e)}" ) @router.post("/courses/{course_id}/reanalyze", response_model=ResponseModel[Dict[str, Any]]) async def reanalyze_course_materials( course_id: int, background_tasks: BackgroundTasks, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """ 重新分析课程的所有资料 - **course_id**: 课程ID 该接口会重新分析课程下的所有资料,提取知识点 """ try: # 验证课程是否存在 course = await course_service.get_by_id(db, course_id) if not course: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"课程 {course_id} 不存在" ) # 获取课程资料信息 materials = await course_service.get_course_materials(db, course_id=course_id) if not materials: return ResponseModel( data={ "message": "该课程暂无资料需要分析", "course_id": course_id, "status": "stopped", "materials_count": 0 }, message="无资料需要分析" ) # 调用 Python 原生知识点分析服务 result = await knowledge_analysis_service_v2.reanalyze_course_materials( db=db, course_id=course_id, course_title=course.name, user_id=current_user.id ) return ResponseModel( data={ "message": "课程资料重新分析完成", "course_id": course_id, "status": "completed", "materials_count": result.get("materials_count", 0), "success_count": result.get("success_count", 0), "knowledge_points_count": result.get("knowledge_points_count", 0), "analysis_results": result.get("analysis_results", []) }, message="重新分析完成" ) except HTTPException: raise except Exception as e: logger.error( f"启动课程资料重新分析失败 - course_id: {course_id}, error: {e}", exc_info=True ) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="启动重新分析失败" ) @router.get("/engines", response_model=ResponseModel[Dict[str, Any]]) async def list_analysis_engines(): """ 获取可用的分析引擎列表 """ return ResponseModel( data={ "engines": [ { "id": "native", "name": "Python 原生实现", "description": "使用本地 AI 服务(4sapi.com + OpenRouter),稳定可靠", "default": True } ], "default_engine": "native" }, message="获取分析引擎列表成功" )