PMFlow/backend/app/services/ai_steward_service/mixin_creation_pipeline.py

107 lines
4.1 KiB
Python

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),
}