| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- """按需求数量自动划分分级计划组(替代统筹 Agent 的默认定时任务路径)。"""
- from __future__ import annotations
- import logging
- from typing import Any
- from agents.demand_grade_orchestrator_agent.common.assignment import (
- resolve_planning_state,
- )
- from agents.demand_grade_orchestrator_agent.common.plan_persist import persist_groups_one_by_one
- from agents.demand_grade_orchestrator_agent.common.plan_record import prepare_grade_groups
- from agents.demand_grade_orchestrator_agent.common.tree_state import load_tree_state
- from supply_infra.scheduler.plan_group_batch import (
- MAX_DEMANDS_PER_BATCH,
- pack_category_units,
- resolve_demands_for_category_ids,
- )
- logger = logging.getLogger(__name__)
- _DEFAULT_GROUPING_STRATEGY = "同分类与同父分类优先,每组约30个需求"
- _DEFAULT_REASON = "代码自动分配"
- _DEFAULT_TRAITS = _DEFAULT_GROUPING_STRATEGY
- def _parent_id(category_id: int, by_id: dict[int, Any]) -> int | None:
- row = by_id.get(category_id)
- if row is None:
- return None
- parent = getattr(row, "parent_id", None)
- if parent in (None, 0):
- return None
- return int(parent)
- def build_auto_assign_groups(
- biz_dt: str,
- *,
- unassigned_category_ids: list[int] | None = None,
- max_demands_per_group: int = MAX_DEMANDS_PER_BATCH,
- ) -> list[dict[str, Any]]:
- """为未分批分类节点生成自动分配批次(仅 category_ids,供 prepare_grade_groups 使用)。"""
- planning_state = resolve_planning_state(biz_dt)
- category_ids = list(unassigned_category_ids or planning_state["unassigned_category_ids"])
- if not category_ids:
- return []
- by_id, _children, _weights = load_tree_state(biz_dt)
- units: list[tuple[int, int | None, list[dict[str, Any]]]] = []
- for category_id in category_ids:
- demands = resolve_demands_for_category_ids(biz_dt, [category_id])
- if not demands:
- continue
- units.append((category_id, _parent_id(category_id, by_id), demands))
- packed = pack_category_units(units, max_demands_per_group=max_demands_per_group)
- return [
- {
- "category_ids": group_category_ids,
- "planning_reason": _DEFAULT_REASON,
- "shared_traits": _DEFAULT_TRAITS,
- }
- for group_category_ids in packed
- ]
- def auto_assign_daily_grade_plan(
- *,
- biz_dt: str,
- max_demands_per_group: int = MAX_DEMANDS_PER_BATCH,
- ) -> dict[str, Any]:
- """自动划分并落库当天分级计划组(每组约 30 个需求,同分类/同父分类优先)。"""
- planning_state = resolve_planning_state(biz_dt)
- if not planning_state["can_plan_more"]:
- logger.info(
- "跳过自动分配: biz_dt=%s reason=%s",
- biz_dt,
- planning_state["skip_reason"],
- )
- return {
- "skipped": True,
- "reason": planning_state["skip_reason"],
- "planning_state": planning_state,
- }
- groups = build_auto_assign_groups(
- biz_dt,
- unassigned_category_ids=planning_state["unassigned_category_ids"],
- max_demands_per_group=max_demands_per_group,
- )
- if not groups:
- logger.info(
- "跳过自动分配:无待分配需求 biz_dt=%s unassigned_categories=%s",
- biz_dt,
- len(planning_state["unassigned_category_ids"]),
- )
- return {
- "skipped": True,
- "reason": "无待分配需求",
- "planning_state": planning_state,
- }
- logger.info(
- "执行自动分配: biz_dt=%s unassigned_categories=%s planned_groups=%s max_demands_per_group=%s",
- biz_dt,
- len(planning_state["unassigned_category_ids"]),
- len(groups),
- max_demands_per_group,
- )
- prepared = prepare_grade_groups(
- biz_dt,
- _DEFAULT_GROUPING_STRATEGY,
- groups,
- assigned_category_ids=set(planning_state["assigned_category_ids"]),
- )
- persist_result = persist_groups_one_by_one(biz_dt, prepared)
- return {
- "skipped": False,
- "planning_state": planning_state,
- "prepared_group_count": len(prepared.get("groups") or []),
- "persist_result": persist_result,
- }
|