"""Helpers for seed project creation and SSTC recovery.""" from __future__ import annotations import json from typing import Optional from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.models import Signal, Task, TruthNode, User from app.services.auth import AuthService PIXELLE_SIGNAL_CONTENTS = [ ( "HackerNews", "Pixelle-Video: An AI-powered automated short video generation platform with script-to-video automation", 9.2, "critical", ), ( "ProductHunt", "Pixelle-Video launches API for programmatic video content generation", 8.5, "high", ), ( "TechCrunch", "Pixelle-Video raises Series A funding to scale AI video infrastructure", 7.8, "high", ), ] PIXELLE_TASK_BLUEPRINT = [ {"title": "Integrate Pixelle-Video API", "priority": "high", "hours": 8.0}, {"title": "Design Video Workflow UI", "priority": "medium", "hours": 12.0}, {"title": "Optimize Video Pipeline", "priority": "medium", "hours": 16.0}, ] def _build_signal_payload(impact_score: float) -> tuple[str, str]: strategic_analysis = json.dumps( { "decision_proposal": { "is_strategic": True, "threat_level": "HIGH", "lead_time_days": 14, "impact_score": impact_score, "recommendation": "立即集成 Pixelle-Video API 到主平台", }, "competitiveness_radar": { "innovation": 85, "market_potential": 90, "technical_complexity": 75, "resource_intensity": 70, }, "detected_tech_stacks": ["AI/ML", "Video Processing", "REST API"], "related_knowledge_nodes": [], "rag_context_used": 0, } ) tasks_generated = json.dumps( [ {"task_name": "Integrate Pixelle-Video API", "type": "backend", "estimated_hours": 8.0}, {"task_name": "Design Video Workflow UI", "type": "frontend", "estimated_hours": 12.0}, {"task_name": "Optimize Video Pipeline", "type": "ai_engineer", "estimated_hours": 16.0}, ] ) return strategic_analysis, tasks_generated def build_pixelle_signals() -> list[Signal]: signals: list[Signal] = [] for source, content, impact_score, priority in PIXELLE_SIGNAL_CONTENTS: signal = Signal( source=source, content=content, impact_score=impact_score, priority=priority, processed=True, ) strategic_analysis, tasks_generated = _build_signal_payload(impact_score) signal.strategic_analysis = strategic_analysis signal.tasks_generated = tasks_generated signals.append(signal) return signals async def ensure_seed_user(session: AsyncSession) -> User: user_result = await session.execute(select(User).limit(1)) seed_user = user_result.scalar_one_or_none() if seed_user: return seed_user seed_user = User( username="boss", email="boss@pmflow.local", password_hash=AuthService.hash_password("boss123"), name="负责人", role="BOSS", status="active", ) session.add(seed_user) await session.flush() return seed_user async def create_pixelle_charter_and_tasks( session: AsyncSession, *, project_id: int, created_by: int, signal_ids: list[int], ) -> TruthNode: charter = TruthNode( node_type="charter", parent_id=None, project_id=project_id, created_by=created_by, title="Pixelle-Video 集成需求宪章", content={ "rationale": "基于 HackerNews/ProductHunt/TechCrunch 信号,决定集成 Pixelle-Video API 到主平台", "signal_ids": signal_ids, "decision": "立即集成 Pixelle-Video API,支持脚本到视频的自动化生成", }, version=1, status="aligned", ) session.add(charter) await session.flush() for task_item in PIXELLE_TASK_BLUEPRINT: task = Task( truth_node_id=charter.id, project_id=project_id, title=task_item["title"], required_skill_tag_ids=[], status="todo", priority=task_item["priority"], estimated_hours=task_item["hours"], ) session.add(task) return charter def build_ai_signal() -> Signal: signal = Signal( source="ArXiv", content="New paper: Multi-Agent LLM Voting System improves accuracy by 23%", impact_score=7.5, priority="medium", processed=True, ) signal.strategic_analysis = json.dumps( { "decision_proposal": { "is_strategic": True, "threat_level": "MEDIUM", "lead_time_days": 30, "impact_score": 7.5, "recommendation": "实现多模型投票机制提升 AI 分析准确性", }, "detected_tech_stacks": ["LLM", "Voting", "Multi-Agent"], } ) return signal def pick_signal_ids(signals: Optional[list[Signal]]) -> list[int]: return [signal.id for signal in (signals or []) if signal.id is not None]