主要更新: - 更新代理商端文档,明确项目由品牌方分配流程 - 新增Brief配置详情页(已配置)设计稿 - 完善工作台紧急待办中品牌新任务功能 - 整理Pencil设计文件中代理商端页面顺序 - 新增后端FastAPI框架及核心API - 新增前端Next.js页面和组件库 - 添加.gitignore排除构建和缓存文件 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
88 lines
2.7 KiB
Python
88 lines
2.7 KiB
Python
"""
|
||
一致性指标 API
|
||
按达人、规则类型、时间窗口查询
|
||
"""
|
||
from datetime import datetime, timedelta, timezone
|
||
from fastapi import APIRouter, HTTPException, Query, status
|
||
|
||
from app.schemas.review import (
|
||
ConsistencyMetricsResponse,
|
||
ConsistencyWindow,
|
||
RuleConsistencyMetric,
|
||
ViolationType,
|
||
)
|
||
|
||
router = APIRouter(prefix="/metrics", tags=["metrics"])
|
||
|
||
|
||
@router.get("/consistency", response_model=ConsistencyMetricsResponse)
|
||
async def get_consistency_metrics(
|
||
influencer_id: str = Query(None, description="达人 ID(必填)"),
|
||
window: ConsistencyWindow = Query(ConsistencyWindow.ROLLING_30D, description="计算周期"),
|
||
rule_type: ViolationType = Query(None, description="规则类型筛选"),
|
||
) -> ConsistencyMetricsResponse:
|
||
"""
|
||
查询一致性指标
|
||
|
||
- 按达人 ID 查询
|
||
- 支持 Rolling 30 天、周度快照、月度快照
|
||
- 可按规则类型筛选
|
||
"""
|
||
# 验证必填参数
|
||
if not influencer_id:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||
detail="缺少必填参数: influencer_id",
|
||
)
|
||
|
||
# 计算时间范围
|
||
now = datetime.now(timezone.utc)
|
||
if window == ConsistencyWindow.ROLLING_30D:
|
||
period_start = now - timedelta(days=30)
|
||
period_end = now
|
||
elif window == ConsistencyWindow.SNAPSHOT_WEEK:
|
||
# 本周一到现在
|
||
days_since_monday = now.weekday()
|
||
period_start = (now - timedelta(days=days_since_monday)).replace(
|
||
hour=0, minute=0, second=0, microsecond=0
|
||
)
|
||
period_end = now
|
||
else: # SNAPSHOT_MONTH
|
||
# 本月1号到现在
|
||
period_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||
period_end = now
|
||
|
||
# 生成模拟数据(实际应从数据库查询)
|
||
all_metrics = [
|
||
RuleConsistencyMetric(
|
||
rule_type=ViolationType.FORBIDDEN_WORD,
|
||
total_reviews=100,
|
||
violation_count=5,
|
||
violation_rate=0.05,
|
||
),
|
||
RuleConsistencyMetric(
|
||
rule_type=ViolationType.COMPETITOR_LOGO,
|
||
total_reviews=100,
|
||
violation_count=2,
|
||
violation_rate=0.02,
|
||
),
|
||
RuleConsistencyMetric(
|
||
rule_type=ViolationType.DURATION_SHORT,
|
||
total_reviews=100,
|
||
violation_count=8,
|
||
violation_rate=0.08,
|
||
),
|
||
]
|
||
|
||
# 按规则类型筛选
|
||
if rule_type:
|
||
all_metrics = [m for m in all_metrics if m.rule_type == rule_type]
|
||
|
||
return ConsistencyMetricsResponse(
|
||
influencer_id=influencer_id,
|
||
window=window,
|
||
period_start=period_start,
|
||
period_end=period_end,
|
||
metrics=all_metrics,
|
||
)
|