| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- from __future__ import annotations
- from abc import ABC, abstractmethod
- from dataclasses import dataclass, field
- from typing import Any
- @dataclass(frozen=True)
- class GenerateContext:
- """策略产出上下文。"""
- batch_date: str
- params: dict[str, Any]
- strategy_id: str
- strategy_name: str
- window_start: str | None = None
- window_end: str | None = None
- @dataclass(frozen=True)
- class StrategySkipDecision:
- """策略跳过决策,由各策略在 should_skip() 中自行返回。"""
- skip: bool
- reason: str = ""
- detail: dict[str, Any] = field(default_factory=dict)
- @dataclass
- class DemandCandidate:
- """
- 策略产出的候选需求。
- generate() 返回此结构;写入 strategy_staging 时映射为:
- - content -> demand_name
- - priority_score -> weight
- - extra -> extend
- """
- content: str
- confidence: float | None = None
- priority_score: float | None = None
- demand_id: str | None = None
- demand_type: str | None = None
- video_count: int | None = None
- video_list: list[Any] | None = None
- extra: dict[str, Any] = field(default_factory=dict)
- class BaseStrategy(ABC):
- """所有策略实现的统一接口。"""
- strategy_id: str
- name: str
- version: str
- @abstractmethod
- def validate_config(self, config: dict[str, Any]) -> bool:
- """校验策略参数,注册或热更新时调用。"""
- @abstractmethod
- def generate(self, context: GenerateContext) -> list[DemandCandidate]:
- """产出候选需求列表。"""
- def should_skip(self, context: GenerateContext) -> StrategySkipDecision:
- """各策略自行决定是否跳过本次产出,默认不跳过。"""
- return StrategySkipDecision(skip=False)
- def write_staging(
- self,
- *,
- context: GenerateContext,
- candidates: list[DemandCandidate],
- ) -> dict[str, Any]:
- """写入 strategy_staging,默认按 context.batch_date 整批替换。"""
- from app.strategies.staging_store import replace_staging_batch
- written = replace_staging_batch(
- strategy_config_id=self.strategy_id,
- strategy_name=self.name,
- batch_date=context.batch_date,
- candidates=candidates,
- )
- return {"written": written, "skipped_duplicates": 0}
|