43 lines
1.7 KiB
Python
43 lines
1.7 KiB
Python
"""最终用户画像路由:仅员工/管理员可查询三源整合画像。
|
||
|
||
权限约定:
|
||
- 客户(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)
|