"""Presentation service — generates HTML slides from idea + analysis reports.""" import json import logging from datetime import datetime, timezone from typing import Any, Optional from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.agents.models import AgentReport from app.models.idea import Idea from app.services.disk_service import DiskService logger = logging.getLogger(__name__) ROLE_EMOJI = { "coordinator": "🎯", "task_organizer": "📋", "business_analyst": "💼", "legal_expert": "⚖️", "financial_consultant": "💰", "solution_architect": "🏗️", "tester": "🧪", "ui_designer": "🎨", "smm_specialist": "📱", "life_coach": "🌟", "accessibility_expert": "♿", } ROLE_LABELS = { "coordinator": "Координатор", "task_organizer": "Организатор задач", "business_analyst": "Бизнес-аналитик", "legal_expert": "Юрист", "financial_consultant": "Финансовый консультант", "solution_architect": "Архитектор решения", "tester": "Тестировщик", "ui_designer": "UI/Дизайнер", "smm_specialist": "SMM-специалист", "life_coach": "Лайф-коуч", "accessibility_expert": "Эксперт доступности", } REVEAL_HTML_TEMPLATE = """ {title} — VoIdea Презентация

{title}

{author} · {status_label} · {date}
{executive_summary} {role_slides}

Спасибо за внимание!

Создано в VoIdea · {date}

""" class PresentationService: def __init__(self, db: AsyncSession): self.db = db async def generate( self, idea_id: str, roles: Optional[list[str]] = None, user_name: str = "", ) -> Optional[str]: """Generate HTML presentation for an idea. Args: idea_id: UUID of the idea roles: List of roles to include (None = all available) user_name: Author display name Returns: HTML string or None if idea not found """ result = await self.db.execute( select(Idea).where(Idea.id == idea_id) ) idea = result.scalar_one_or_none() if not idea: return None result = await self.db.execute( select(AgentReport).where( AgentReport.details["idea_id"].as_string() == idea_id ).order_by(AgentReport.created_at.asc()) ) reports = result.scalars().all() if roles is not None: reports = [ r for r in reports if r.agent_id.replace("ai_", "") in roles ] funnel_labels = { "raw": "Сырая", "validated": "Подтверждена", "backlog": "Бэклог", "in_progress": "В работе", "launched": "Запущена", "retrospective": "Ретроспектива", } status_label = funnel_labels.get( idea.funnel_status or "", idea.funnel_status or "Без статуса" ) date_str = datetime.now(timezone.utc).strftime("%d.%m.%Y") role_slides = [] for r in reports: role_name = r.agent_id.replace("ai_", "") emoji = ROLE_EMOJI.get(role_name, "📄") label = ROLE_LABELS.get(role_name, role_name) content = r.message or "Нет данных" role_slides.append(f"""

{emoji} {label}

{content}
""") success_count = sum(1 for r in reports if r.success) if role_slides: exec_summary = f"""

📊 Executive Summary

Проанализировано ролей: {len(reports)}

Успешных анализов: {success_count}

""" else: exec_summary = "" return REVEAL_HTML_TEMPLATE.format( title=idea.title, author=user_name or "Пользователь", status_label=status_label, date=date_str, executive_summary=exec_summary, role_slides="".join(role_slides), )