"""最终用户画像路由:仅员工/管理员可查询三源整合画像。 权限约定: - 客户(CUSTOMER):**无权访问本接口**,整合画像属于内部经营数据; - 员工/管理员(EMPLOYEE/ADMIN):必须显式指定 customer_id,可查任意客户。 整合逻辑在 ComposedProfileService(LLM 整合 + Redis 缓存 + 降级), 本路由只做鉴权与编排;画像仅供参考,不用于适当性校验。 """ from fastapi import APIRouter, Depends, Query from sqlalchemy.ext.asyncio import AsyncSession from api.deps import get_current_user from config.deps import get_db from model.sys_user import SysUser from service.memory.composed_profile import ComposedProfileService from utils.exceptions import ForbiddenError from utils.response import success router = APIRouter() async def require_profile_viewer(user: SysUser = Depends(get_current_user)) -> SysUser: """仅员工或管理员可查询最终用户画像,客户一律拒绝。""" if user.user_type == "ADMIN": return user if user.user_type != "EMPLOYEE": raise ForbiddenError("仅员工可查询用户画像") return user @router.get("/profile/composed", summary="查询最终用户画像(画像+记忆+持仓三源整合,仅员工)") async def get_composed_profile( customer_id: int = Query(..., description="目标客户 ID"), user: SysUser = Depends(require_profile_viewer), db: AsyncSession = Depends(get_db), ): """返回整合后的最终用户画像 JSON 及降级 warnings。""" service = ComposedProfileService() # 完整响应体先查 Redis(20 分钟过期),重复请求直接命中缓存 data, _warnings = await service.compose_response(db, customer_id=customer_id) return success(data)