from __future__ import annotations from .shared import * class AIStewardCreationPipelineMixin: async def create_project_from_natural_language( self, input_text: str, creator_id: int, tenant_id: int = 1, requested_member_user_ids: list[int] | None = None, ) -> Dict[str, Any]: """零配置项目创建,统一走 draft -> normalize -> persist 三段式。""" analysis = await self._analyze_project_input(input_text, tenant_id) draft = await self._generate_project_creation_draft( input_text=input_text, analysis=analysis, tenant_id=tenant_id, ) normalized = await self._normalize_project_creation_draft( draft=draft, input_text=input_text, creator_id=creator_id, tenant_id=tenant_id, ) payload = await self._persist_project_creation_draft( normalized=normalized, input_text=input_text, creator_id=creator_id, tenant_id=tenant_id, requested_member_user_ids=requested_member_user_ids, ) await self.db.commit() try: charter = payload["charter"] project = payload["project"] asyncio.create_task( AdaptiveRAGService.upsert_pmflow_record_async( tenant_id=tenant_id, record_type="charter", record_id=int(charter["id"]), project_id=int(project["id"]), title=str(charter.get("title") or "项目宪章"), content=json.dumps(charter.get("content") or {}, ensure_ascii=False), ) ) for task in payload.get("tasks", []): task_id = int(str(task.get("id") or "0") or 0) if task_id <= 0: continue asyncio.create_task( AdaptiveRAGService.upsert_pmflow_record_async( tenant_id=tenant_id, record_type="task", record_id=task_id, project_id=int(project["id"]), title=str(task.get("title") or "任务"), content=str(task.get("description") or ""), ) ) except Exception: pass return payload async def _generate_project_creation_draft( self, *, input_text: str, analysis: Dict[str, Any], tenant_id: int, ) -> dict[str, Any]: if PROJECT_CREATION_SERIAL_DRAFT_STEPS: signal_draft = await self._generate_competitive_signal_draft(analysis=analysis, tenant_id=tenant_id) charter_draft = await self._generate_charter_draft(analysis=analysis, tenant_id=tenant_id) task_drafts = await self._generate_task_chain_draft( analysis=analysis, tenant_id=tenant_id, charter_content=charter_draft.get("content"), ) else: signal_draft, charter_draft = await asyncio.gather( self._generate_competitive_signal_draft(analysis=analysis, tenant_id=tenant_id), self._generate_charter_draft(analysis=analysis, tenant_id=tenant_id), ) task_drafts = await self._generate_task_chain_draft( analysis=analysis, tenant_id=tenant_id, charter_content=charter_draft.get("content"), ) return { "analysis": analysis, "project": { "name": analysis.get("project_name") or input_text[:20] or "未命名项目", "title": analysis.get("project_title") or input_text[:50] or "未命名项目", "description": input_text, "assigned_role": analysis.get("primary_role") or "backend", "domain_id": analysis.get("domain_id"), }, "signal": signal_draft, "charter": charter_draft, "tasks": task_drafts, "risks": self._build_risk_alert_drafts(analysis=analysis), }