Files
meida_backend/packages/report/pipeline.py
T
xsl d974526904 chore(prep): shared groundwork for batch-4 (report pipeline)
第四批(T15 编排/T16 视觉诊断/T17 文案校验)协调提交:
- 迁移 0006:rp_report(result JSONB 按阶段键承载中间态)/rp_input
 (derived_features 视觉中间态)/rp_share(V1 只建结构)
- ORM 三模型;错误码 40420/40920(文案无价格字样)
- 配置:report_pipeline_stages(dotted path 动态装配)+ vision/tier
- packages/report/pipeline.py:Stage Protocol + ReportContext(三任务共同契约,
  动态 import 的动机与代价写在 docstring)
- 路由桩 reports.py 已注册
2026-08-14 21:51:05 +08:00

73 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""报告流水线的阶段契约(第四批 T15/T16/T17 的共同接口)。
本文件由协调提交只定 **接口**;编排实现(assemble_stages / run_pipeline)
归 T15。T16 提供 vision_stage / diagnosis_stage,T17 提供 copy_stage /
validation_stage——三个任务互不改对方文件,靠 Settings.report_pipeline_stages
里的 dotted path 动态装配。
设计动机(为什么动态 import):三个阶段模块由三个并行分支各自创建,
静态 import 会在任一分支缺文件时炸掉编排;按配置动态装配让每个分支
独立可测,合并后自动咬合。代价是 import-linter 看不到这条边——阶段模块
自身的依赖仍受契约约束,编排层注入的 session/gateway 都是既有合法依赖。
"""
from __future__ import annotations
from typing import Any, Protocol, runtime_checkable
from sqlalchemy.ext.asyncio import AsyncSession
from packages.llm.gateway import LLMGateway
from packages.shared.config import Settings
from packages.shared.models import RpInput, RpReport
class ReportContext:
"""一个阶段的执行上下文。
不是 frozen:阶段要写 ``ctx.report.result[stage.name]`` 与
``ctx.rp_input.derived_features``(中间态落库由编排层 flush)。
"""
def __init__(
self,
*,
report: RpReport,
report_input: RpInput,
session: AsyncSession,
settings: Settings,
gateway: LLMGateway | None = None,
) -> None:
self.report = report
self.report_input = report_input
self.session = session
self.settings = settings
self.gateway = gateway
@runtime_checkable
class Stage(Protocol):
"""流水线阶段。name 同时是 result JSONB 里的产物键。
约定:阶段把自己的全部产物写进 ``ctx.report.result[self.name]``;
抛异常即整条流水线失败(编排层负责 tk_task→failed + refund)。
"""
name: str
async def run(self, ctx: ReportContext) -> None: ...
#: T15 的 assemble_stages 按此清单 importlib 动态导入;缺失即 CONFIG_ERROR。
DEFAULT_STAGE_PATHS: tuple[str, ...] = (
"packages.report.vision_stage:VisionStage",
"packages.report.diagnosis_stage:DiagnosisStage",
"packages.report.copy_stage:CopyStage",
"packages.report.validation_stage:ValidationStage",
)
def stage_names(result: dict[str, Any]) -> list[str]:
"""result JSONB 里已出现的阶段键(诊断/调试用的小工具)。"""
return [k for k in result if isinstance(result[k], dict)]