from __future__ import annotations from typing import Any from ..schemas import TaskBreakdownBusinessObject, TaskBreakdownPayload from .task_persistence_core import SkillTagResolution, resolve_skill_tag_ids_by_names from .task_persistence_core.shared import AsyncSession def normalize_task_breakdown_payload(raw_payload: Any) -> TaskBreakdownPayload: """将模型结构化输出归一为任务拆解载荷。""" if isinstance(raw_payload, TaskBreakdownPayload): return raw_payload if not isinstance(raw_payload, dict): raise ValueError("task_breakdown_payload must be a JSON object") return TaskBreakdownPayload.model_validate(raw_payload) def build_task_breakdown_ai_payload(payload: TaskBreakdownPayload) -> dict[str, Any]: """将结构化拆解载荷保存为 JSON 负载。""" return payload.model_dump(mode="json") async def resolve_task_breakdown_skill_tag_ids( db: AsyncSession, *, tenant_id: int, task: TaskBreakdownBusinessObject, ) -> tuple[list[int], SkillTagResolution]: """将任务里的技能名称和已有 skill_tag_id 合并成最终 ID 列表。""" resolution = await resolve_skill_tag_ids_by_names( db, tenant_id=tenant_id, skill_names=task.required_skill_names, ) merged_ids: list[int] = [] seen: set[int] = set() for raw in list(task.required_skill_tag_ids or []) + list(resolution.matched_ids or []): try: skill_id = int(raw) except (TypeError, ValueError): continue if skill_id <= 0 or skill_id in seen: continue seen.add(skill_id) merged_ids.append(skill_id) return merged_ids, resolution def should_auto_assign_breakdown_task( *, task: TaskBreakdownBusinessObject, top_match_score: float | None, top_workload_rate: float | None, confidence_threshold: float = 0.85, match_score_threshold: float = 75.0, workload_threshold: float = 70.0, ) -> bool: """判断 AI 拆解任务是否可自动分配负责人。""" confidence = float(task.confidence or 0.0) if confidence < confidence_threshold: return False if str(task.risk_level or "").strip().lower() not in {"low"}: return False if top_match_score is None or top_workload_rate is None: return False if top_match_score < match_score_threshold: return False if top_workload_rate >= workload_threshold: return False return True __all__ = [ "normalize_task_breakdown_payload", "build_task_breakdown_ai_payload", "resolve_task_breakdown_skill_tag_ids", "should_auto_assign_breakdown_task", ]