import httpx import json import logging import re from app.config import settings logger = logging.getLogger(__name__) PROMPTS = { "minutes": ( "Voce e um assistente especializado em reunioes corporativas. " "Com base na transcricao a seguir, gere uma ata estruturada em JSON contendo: " "title (string), participants (array de objetos com name e role), " "agenda (array de strings), decisions (array de strings), " "action_items (array de objetos com description, responsible e deadline), " "next_steps (array de strings), open_points (array de strings). " "Retorne APENAS o JSON valido, sem texto adicional. " "Transcricao: {transcription}" ), "sentiment": ( "Analise o tom emocional desta reuniao e retorne um JSON com: " "overall_sentiment (positive/neutral/negative), " "timeline (array de objetos com time_range, sentiment e notes), " "participants_sentiment (array de objetos com speaker, sentiment e details), " "tension_moments (array de strings), " "consensus_moments (array de strings), " "participation_metrics (array de objetos com speaker, talk_percentage e interventions_count). " "Retorne APENAS o JSON valido. " "Transcricao: {transcription}" ), "psychological": ( "Analise os padroes comportamentais dos participantes e retorne um JSON com: " "participants_profiles (array de objetos com speaker, name, communication_style, " "leadership_tendencies, disengagement_signs, power_dynamics_role), " "group_dynamics (string), " "key_observations (array de strings). " "Retorne APENAS o JSON valido. " "Transcricao: {transcription}" ), "communication": ( "Avalie a comunicacao dos participantes nesta reuniao e retorne um JSON com: " "overall_score (numero de 1 a 10), " "dimensions (objeto com clarity, active_listening, assertiveness, meeting_facilitation, " "cada um com score e notes), " "strengths (array de objetos com description e example), " "improvement_areas (array de objetos com description e suggestion), " "general_feedback (string). " "Retorne APENAS o JSON valido. " "Transcricao: {transcription}" ), "summary": ( "Gere um resumo executivo desta reuniao em JSON com: " "summary (string), " "key_points (array de strings), " "duration_minutes (number), " "total_participants (number). " "Retorne APENAS o JSON valido. " "Transcricao: {transcription}" ), } async def run_analysis(analysis_type: str, transcription: dict) -> dict: """Run AI analysis on transcription using Ollama""" transcription_text = json.dumps(transcription, ensure_ascii=False) prompt_template = PROMPTS.get(analysis_type, PROMPTS["summary"]) prompt = prompt_template.replace("{transcription}", transcription_text[:8000]) logger.info(f"Running {analysis_type} analysis with Ollama model {settings.OLLAMA_MODEL}") try: headers = {} if settings.OLLAMA_API_KEY: headers["X-API-Key"] = settings.OLLAMA_API_KEY async with httpx.AsyncClient(timeout=180.0) as client: response = await client.post( f"{settings.OLLAMA_URL}/api/generate", headers=headers, json={ "model": settings.OLLAMA_MODEL, "prompt": prompt, "stream": False, "format": "json", "options": {"temperature": 0.3}, }, ) response.raise_for_status() result = response.json() response_text = result.get("response", "{}") try: return json.loads(response_text) except json.JSONDecodeError: json_match = re.search(r"\{.*\}", response_text, re.DOTALL) if json_match: try: return json.loads(json_match.group()) except json.JSONDecodeError: pass return {"raw_response": response_text, "parse_error": "Could not parse JSON"} except httpx.ConnectError as e: logger.error(f"Cannot connect to Ollama at {settings.OLLAMA_URL}: {e}") return {"error": "Ollama unavailable", "analysis_type": analysis_type} except Exception as e: logger.error(f"Ollama analysis error for {analysis_type}: {e}") return {"error": str(e), "analysis_type": analysis_type}