"""诊断API端点 - 提供SEO和GEO诊断功能""" import logging import uuid from typing import Annotated from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_current_user from app.database import get_db from app.models.user import User from app.models.brand import Brand from app.services.seo_diagnosis import SEODiagnosisService from app.services.geo_diagnosis import GEODiagnosisService, GEODiagnosisInput logger = logging.getLogger(__name__) router = APIRouter() @router.get("/seo/{brand_id}") async def get_seo_diagnosis( brand_id: uuid.UUID, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """ 获取品牌的SEO诊断结果 返回5维度SEO诊断: - 技术SEO (25分) - 页面SEO (20分) - 内容质量 (20分) - 外链分析 (15分) - 用户体验 (20分) """ brand = await _get_brand_or_404(brand_id, current_user, db) try: service = SEODiagnosisService() result = service.diagnose() logger.info(f"SEO诊断完成: brand_id={brand_id}, brand={brand.name}, score={result.overall_score}") return result.to_dict() except Exception as e: logger.error(f"SEO诊断失败: brand_id={brand_id}, error={str(e)}", exc_info=True) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="SEO诊断服务异常,请稍后重试", ) @router.get("/geo/{brand_id}") async def get_geo_diagnosis( brand_id: uuid.UUID, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """ 获取品牌的GEO诊断结果 返回6维度GEO诊断: - 内容可提取性 (20分) - 实体清晰度 (15分) - E-E-A-T信号 (20分) - Schema标记 (15分) - 主题权威 (15分) - 引用就绪度 (15分) """ brand = await _get_brand_or_404(brand_id, current_user, db) try: input_data = GEODiagnosisInput() service = GEODiagnosisService() result = service.diagnose(input_data) logger.info(f"GEO诊断完成: brand_id={brand_id}, brand={brand.name}, score={result.overall_score}") return result.to_dict() except Exception as e: logger.error(f"GEO诊断失败: brand_id={brand_id}, error={str(e)}", exc_info=True) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="GEO诊断服务异常,请稍后重试", ) @router.get("/combined/{brand_id}") async def get_combined_diagnosis( brand_id: uuid.UUID, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """ 获取品牌的综合诊断结果 结合SEO和GEO诊断,返回综合评分和详细诊断结果 """ brand = await _get_brand_or_404(brand_id, current_user, db) try: seo_service = SEODiagnosisService() seo_result = seo_service.diagnose() geo_service = GEODiagnosisService() geo_result = geo_service.diagnose(GEODiagnosisInput()) combined_score = round((seo_result.overall_score + geo_result.overall_score) / 2, 2) logger.info( f"综合诊断完成: brand_id={brand_id}, brand={brand.name}, " f"seo_score={seo_result.overall_score}, " f"geo_score={geo_result.overall_score}, " f"combined_score={combined_score}" ) return { "seo_score": seo_result.overall_score, "geo_score": geo_result.overall_score, "combined_score": combined_score, "seo_diagnosis": seo_result.to_dict(), "geo_diagnosis": geo_result.to_dict(), } except Exception as e: logger.error(f"综合诊断失败: brand_id={brand_id}, error={str(e)}", exc_info=True) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="综合诊断服务异常,请稍后重试", ) async def _get_brand_or_404( brand_id: uuid.UUID, current_user: User, db: AsyncSession, ) -> Brand: """获取品牌或抛出404异常""" stmt = select(Brand).where(Brand.id == brand_id, Brand.user_id == current_user.id) result = await db.execute(stmt) brand = result.scalar_one_or_none() if not brand: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="品牌不存在", ) return brand