"""Scheduled handlers for the insights/dashboard surface. * ``insights.impact_summary_generate`` — every Monday 03:10 Asia/Shanghai (timezone set on the scheduled_jobs row by migration 282). Generates the bilingual AI executive summary for the Platform Impact (平台成果) page from the page's own payload and persists it to ``insights_impact_summaries``. Soft-skips (recorded reason, run stays green) when ``ai_spending.llm.api_key`` isn't configured — that's an expected pre-launch state, not a failure. Every OTHER error raises so the run lands ``failed`` and the failure notifier alarms (a silently stale narrative in front of leadership is exactly the kind of rot this platform exists to prevent). """ from __future__ import annotations import logging import uuid from typing import Any from sqlalchemy.ext.asyncio import AsyncSession from app.core.exceptions import AppException from app.scheduled_jobs.registry import register_scheduled_job logger = logging.getLogger(__name__) @register_scheduled_job( key="insights.impact_summary_generate", display_name="平台成果 · AI 摘要自动生成", description=( "每周生成平台成果页的双语高管摘要(Bailian LLM,复用 " "ai_spending.llm.* 凭据);未配置 api_key 时记录跳过原因后退出。" ), ) async def run_impact_summary_generate( db: AsyncSession, config: dict[str, Any], ) -> dict[str, Any]: from app.dashboard.insights_impact_summary import ( # noqa: PLC0415 generate_impact_summary, ) trace_id = str(uuid.uuid4()) try: result = await generate_impact_summary( db, actor_id=None, trace_id=trace_id, enforce_quota=False, ) except AppException as exc: if exc.code == "BAILIAN_LLM_NO_KEY": return { "generated": False, "skipped_reason": ( "ai_spending.llm.api_key not configured; the impact " "summary reuses the platform Bailian credentials — " "set them in /admin/ai-spending settings." ), } raise await db.commit() return { "generated": True, "period": result.get("period"), "model": result.get("model_used"), }