""" ================================================================================ CELLCOG INTEGRATION - MULTI-MODAL AI CAPABILITIES ================================================================================ Integração com CellCog para geração de imagens, vídeos, áudio, pesquisa, análise. TIER 1: Primário — Usa CellCog API (se disponível) TIER 2: Fallback — Usa Pollinations Flux (se CellCog falhar) ================================================================================ """ import os import json import base64 import requests from typing import Dict, Any, Optional, List from loguru import logger class CellCogClient: """ Cliente para integração com CellCog. Suporta: Image, Video, Audio, Research, Data Analysis, e mais. """ def __init__(self, api_key: Optional[str] = None): """ Inicializa cliente CellCog. Args: api_key: Chave da API CellCog (obtém de env se não fornecido) """ self.api_key = api_key or os.getenv("CELLCOG_API_KEY") self.base_url = os.getenv("CELLCOG_BASE_URL", "https://api.cellcog.ai/v1") self.available = bool(self.api_key) if self.available: logger.success("✅ CellCog integrado com sucesso") else: logger.warning("⚠️ CellCog não configurado - usando fallbacks") def generate_image( self, prompt: str, model: str = "image", aspect_ratio: str = "1:1", quality: str = "high" ) -> Dict[str, Any]: """ Gera imagem via CellCog Image Cog. Args: prompt: Descrição da imagem model: Tipo de geração (image, anime, photo, 3d, etc.) aspect_ratio: Proporção (1:1, 16:9, 9:16, 4:3, etc.) quality: Qualidade (low, medium, high, ultra) Returns: Dict com imagem gerada ou erro """ if not self.available: logger.warning("⚠️ CellCog não configurado, pulando para Flux...") return {"success": False, "error": "CellCog não disponível"} try: logger.info(f"🖼️ [CellCog] Gerando imagem: '{prompt[:50]}...'") payload = { "prompt": prompt, "model": model, "aspect_ratio": aspect_ratio, "quality": quality, "format": "url" # Retorna URL ao invés de base64 } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } response = requests.post( f"{self.base_url}/image", json=payload, headers=headers, timeout=60 ) if response.status_code == 200: result = response.json() image_url = result.get("url") if image_url: # Download da imagem para retornar como buffer try: img_response = requests.get(image_url, timeout=30) if img_response.status_code == 200 and len(img_response.content) > 1000: logger.success(f"✅ [CellCog] Imagem gerada e baixada com sucesso") return { "success": True, "image_data": base64.b64encode(img_response.content).decode('utf-8'), "mime_type": "image/png", "model": "cellcog", "prompt": prompt } except Exception as dl_err: logger.warning(f"⚠️ [CellCog] Falha ao baixar imagem: {dl_err}") return {"success": False, "error": f"Falha ao baixar: {str(dl_err)}"} return {"success": False, "error": "URL de imagem não retornada"} else: logger.error(f"❌ [CellCog] Status {response.status_code}: {response.text[:200]}") return {"success": False, "error": f"Status {response.status_code}"} except requests.exceptions.Timeout: logger.error(f"❌ [CellCog] Timeout na requisição") return {"success": False, "error": "Timeout - CellCog lento"} except requests.exceptions.ConnectionError as e: logger.error(f"❌ [CellCog] Erro de conexão: {str(e)[:100]}") return {"success": False, "error": "Erro de conexão - CellCog indisponível"} except Exception as e: logger.error(f"❌ [CellCog Image] Erro: {str(e)[:150]}") return {"success": False, "error": str(e)[:100]} def generate_video( self, prompt: str, duration: int = 10, resolution: str = "1080p" ) -> Dict[str, Any]: """ Gera vídeo via CellCog Video Cog. Args: prompt: Descrição do vídeo duration: Duração em segundos (5-240) resolution: Resolução (720p, 1080p, 4k) Returns: Dict com vídeo gerado ou erro """ if not self.available: return {"success": False, "error": "CellCog não disponível"} try: logger.info(f"🎬 [CellCog] Gerando vídeo: '{prompt[:50]}...' ({duration}s)") payload = { "prompt": prompt, "duration": min(duration, 240), # Máximo 4 minutos "resolution": resolution, "format": "url" } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } response = requests.post( f"{self.base_url}/video", json=payload, headers=headers, timeout=120 # Videos levam mais tempo ) if response.status_code == 200: result = response.json() logger.success(f"✅ [CellCog] Vídeo gerado com sucesso") return { "success": True, "video_url": result.get("url"), "model": "cellcog", "prompt": prompt, "duration": duration } else: logger.error(f"❌ [CellCog] Status {response.status_code}: {response.text}") return {"success": False, "error": f"Status {response.status_code}"} except Exception as e: logger.error(f"❌ [CellCog Video] Erro: {e}") return {"success": False, "error": str(e)} def generate_audio( self, text: str, voice: str = "default", language: str = "pt-PT" ) -> Dict[str, Any]: """ Gera áudio/TTS via CellCog Audio Cog. Args: text: Texto a converter voice: Voz a usar language: Idioma (pt-PT, pt-BR, en-US, etc.) Returns: Dict com áudio gerado ou erro """ if not self.available: return {"success": False, "error": "CellCog não disponível"} try: logger.info(f"🎙️ [CellCog] Gerando áudio ({language}): '{text[:40]}...'") payload = { "text": text, "voice": voice, "language": language, "format": "mp3" } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } response = requests.post( f"{self.base_url}/audio", json=payload, headers=headers, timeout=60 ) if response.status_code == 200: result = response.json() logger.success(f"✅ [CellCog] Áudio gerado com sucesso") return { "success": True, "audio_url": result.get("url"), "model": "cellcog", "duration": result.get("duration"), "language": language } else: logger.error(f"❌ [CellCog] Status {response.status_code}") return {"success": False, "error": f"Status {response.status_code}"} except Exception as e: logger.error(f"❌ [CellCog Audio] Erro: {e}") return {"success": False, "error": str(e)} def research( self, query: str, depth: str = "medium" ) -> Dict[str, Any]: """ Realiza pesquisa profunda via CellCog Research Cog. Args: query: Pergunta ou tópico depth: Profundidade (quick, medium, thorough) Returns: Dict com resultados da pesquisa """ if not self.available: return {"success": False, "error": "CellCog não disponível"} try: logger.info(f"🔬 [CellCog] Pesquisando: '{query}'") payload = { "query": query, "depth": depth, "sources": 10, "format": "json" } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } response = requests.post( f"{self.base_url}/research", json=payload, headers=headers, timeout=90 ) if response.status_code == 200: result = response.json() logger.success(f"✅ [CellCog] Pesquisa concluída") return { "success": True, "findings": result.get("findings"), "sources": result.get("sources", []), "model": "cellcog" } else: logger.error(f"❌ [CellCog] Status {response.status_code}") return {"success": False, "error": f"Status {response.status_code}"} except Exception as e: logger.error(f"❌ [CellCog Research] Erro: {e}") return {"success": False, "error": str(e)} def analyze_data( self, csv_data: str, analysis_type: str = "exploratory" ) -> Dict[str, Any]: """ Analisa dados via CellCog Data Cog. Args: csv_data: Dados em formato CSV analysis_type: Tipo (exploratory, statistical, predictive) Returns: Dict com análise """ if not self.available: return {"success": False, "error": "CellCog não disponível"} try: logger.info(f"📊 [CellCog] Analisando dados ({analysis_type})") payload = { "data": csv_data, "analysis_type": analysis_type, "format": "json" } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } response = requests.post( f"{self.base_url}/analyze", json=payload, headers=headers, timeout=90 ) if response.status_code == 200: result = response.json() logger.success(f"✅ [CellCog] Análise concluída") return { "success": True, "analysis": result.get("analysis"), "insights": result.get("insights", []), "model": "cellcog" } else: logger.error(f"❌ [CellCog] Status {response.status_code}") return {"success": False, "error": f"Status {response.status_code}"} except Exception as e: logger.error(f"❌ [CellCog Data] Erro: {e}") return {"success": False, "error": str(e)} def think_brainstorm( self, prompt: str, depth: str = "medium" ) -> Dict[str, Any]: """ Raciocínio avançado e brainstorming via CellCog Think Cog. Args: prompt: Pergunta ou problema a resolver depth: Profundidade (quick, medium, thorough) Returns: Dict com ideias e soluções """ if not self.available: return {"success": False, "error": "CellCog não disponível"} try: logger.info(f"💭 [CellCog] Brainstorming: '{prompt[:50]}...'") payload = { "prompt": prompt, "depth": depth, "format": "json" } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } response = requests.post( f"{self.base_url}/think", json=payload, headers=headers, timeout=90 ) if response.status_code == 200: result = response.json() logger.success(f"✅ [CellCog] Raciocínio concluído") return { "success": True, "ideas": result.get("ideas", []), "reasoning": result.get("reasoning", ""), "solutions": result.get("solutions", []), "model": "cellcog" } else: logger.error(f"❌ [CellCog] Status {response.status_code}") return {"success": False, "error": f"Status {response.status_code}"} except Exception as e: logger.error(f"❌ [CellCog Think] Erro: {e}") return {"success": False, "error": str(e)} def generate_document( self, content: str, doc_type: str = "report", format: str = "pdf" ) -> Dict[str, Any]: """ Gera documentos (PDF/DOCX) via CellCog Docs Cog. Args: content: Conteúdo do documento doc_type: Tipo (report, contract, invoice, resume, letter) format: Formato (pdf, docx) Returns: Dict com documento gerado """ if not self.available: return {"success": False, "error": "CellCog não disponível"} try: logger.info(f"📄 [CellCog] Gerando documento ({doc_type})...") payload = { "content": content, "doc_type": doc_type, "format": format } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } response = requests.post( f"{self.base_url}/document", json=payload, headers=headers, timeout=120 ) if response.status_code == 200: result = response.json() doc_url = result.get("url") if doc_url: # Download do documento try: doc_response = requests.get(doc_url, timeout=30) if doc_response.status_code == 200: logger.success(f"✅ [CellCog] Documento gerado e baixado") return { "success": True, "buffer": doc_response.content, "mime_type": f"application/{format}" if format == "pdf" else "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "filename": result.get("filename", f"documento.{format}"), "model": "cellcog" } except Exception as dl_err: logger.warning(f"⚠️ [CellCog] Falha ao baixar documento: {dl_err}") return {"success": False, "error": "URL de documento não retornada"} else: logger.error(f"❌ [CellCog] Status {response.status_code}") return {"success": False, "error": f"Status {response.status_code}"} except Exception as e: logger.error(f"❌ [CellCog Document] Erro: {e}") return {"success": False, "error": str(e)} def generate_presentation( self, title: str, content: str, slides: int = 10, style: str = "professional" ) -> Dict[str, Any]: """ Gera apresentações (PPTX) via CellCog Slides Cog. Args: title: Título da apresentação content: Conteúdo/tópicos slides: Número de slides style: Estilo (professional, creative, minimal) Returns: Dict com apresentação gerada """ if not self.available: return {"success": False, "error": "CellCog não disponível"} try: logger.info(f"📊 [CellCog] Gerando apresentação: '{title[:40]}...'") payload = { "title": title, "content": content, "num_slides": slides, "style": style, "format": "pptx" } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } response = requests.post( f"{self.base_url}/presentation", json=payload, headers=headers, timeout=120 ) if response.status_code == 200: result = response.json() pptx_url = result.get("url") if pptx_url: # Download da apresentação try: pptx_response = requests.get(pptx_url, timeout=30) if pptx_response.status_code == 200: logger.success(f"✅ [CellCog] Apresentação gerada e baixada") return { "success": True, "buffer": pptx_response.content, "mime_type": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "filename": f"{title}.pptx", "num_slides": slides, "model": "cellcog" } except Exception as dl_err: logger.warning(f"⚠️ [CellCog] Falha ao baixar apresentação: {dl_err}") return {"success": False, "error": "URL de apresentação não retornada"} else: logger.error(f"❌ [CellCog] Status {response.status_code}") return {"success": False, "error": f"Status {response.status_code}"} except Exception as e: logger.error(f"❌ [CellCog Presentation] Erro: {e}") return {"success": False, "error": str(e)} def generate_brand_identity( self, brand_name: str, description: str, industry: str = "general" ) -> Dict[str, Any]: """ Gera identidade de marca completa via CellCog Brand Cog. Args: brand_name: Nome da marca description: Descrição da marca industry: Indústria/setor Returns: Dict com identidade de marca (logo, cores, guidelines) """ if not self.available: return {"success": False, "error": "CellCog não disponível"} try: logger.info(f"🎨 [CellCog] Gerando branding para '{brand_name}'...") payload = { "brand_name": brand_name, "description": description, "industry": industry } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } response = requests.post( f"{self.base_url}/brand", json=payload, headers=headers, timeout=120 ) if response.status_code == 200: result = response.json() logger.success(f"✅ [CellCog] Identidade de marca gerada") # Tentar baixar logo se disponível logo_url = result.get("logo_url") logo_buffer = None if logo_url: try: logo_response = requests.get(logo_url, timeout=30) if logo_response.status_code == 200: logo_buffer = logo_response.content except: pass return { "success": True, "brand_name": brand_name, "logo_buffer": logo_buffer, "colors": result.get("color_palette", []), "typography": result.get("typography", {}), "guidelines": result.get("guidelines", ""), "style": result.get("style", ""), "model": "cellcog" } else: logger.error(f"❌ [CellCog] Status {response.status_code}") return {"success": False, "error": f"Status {response.status_code}"} except Exception as e: logger.error(f"❌ [CellCog Brand] Erro: {e}") return {"success": False, "error": str(e)} # ============================================================================ # FALLBACK: Pollinations Flux (quando CellCog não está disponível) # ============================================================================ class PollinationsFluxFallback: """ Fallback para geração de imagens usando Pollinations Flux. """ BASE_URL = "https://image.pollinations.ai/prompt" @staticmethod def generate( prompt: str, aspect_ratio: str = "1:1", model: str = "flux" ) -> Dict[str, Any]: """ Gera imagem via Pollinations Flux como fallback (baixa e retorna como buffer). """ try: logger.info(f"🔄 [Flux Fallback] Gerando imagem: '{prompt[:50]}...'") # Converte aspect_ratio para width/height ratio_map = { "1:1": (1024, 1024), "16:9": (1344, 756), "9:16": (756, 1344), "4:3": (1024, 768), "3:4": (768, 1024) } width, height = ratio_map.get(aspect_ratio, (1024, 1024)) # Monta URL com parâmetros import urllib.parse encoded_prompt = urllib.parse.quote(prompt) url = f"{PollinationsFluxFallback.BASE_URL}/{encoded_prompt}" params = { "width": width, "height": height, "model": model, "nologo": "true" } # Monta URL completa image_url = f"{url}?{'&'.join(f'{k}={v}' for k, v in params.items())}" # Retry logic para Flux max_retries = 2 for attempt in range(max_retries): try: # Baixa a imagem response = requests.get(image_url, timeout=60) # Aumentado para 60s if response.status_code == 200 and len(response.content) > 1000: logger.success(f"✅ [Flux Fallback] Imagem gerada e baixada com sucesso (tentativa {attempt + 1})") return { "success": True, "image_data": base64.b64encode(response.content).decode('utf-8'), "mime_type": "image/png", "model": "flux-fallback", "prompt": prompt } if response.status_code == 429: logger.warning(f"⚠️ [Flux Fallback] Rate limit (429). Tentativa {attempt + 1}/{max_retries}...") import time time.sleep(5) continue except requests.exceptions.Timeout: logger.warning(f"⚠️ [Flux Fallback] Timeout na tentativa {attempt + 1}/{max_retries}") if attempt < max_retries - 1: import time time.sleep(2) continue except Exception as e: logger.error(f"❌ [Flux Fallback] Erro na tentativa {attempt + 1}: {e}") if attempt < max_retries - 1: continue break return {"success": False, "error": f"Flux retornou status {response.status_code}"} except Exception as e: logger.error(f"❌ [Flux Fallback] Erro: {e}") return {"success": False, "error": str(e)} # ============================================================================ # FACTORY: Escolhe melhor provider (CellCog ou Flux) # ============================================================================ class AIMediaFactory: """ Factory que escolhe o melhor provider disponível. """ def __init__(self): self.cellcog = CellCogClient() self.flux = PollinationsFluxFallback() def generate_image( self, prompt: str, model: str = "flux", aspect_ratio: str = "1:1" ) -> Dict[str, Any]: """ Gera imagem com fallback automático. Tenta CellCog primeiro, depois Flux. """ # Tenta CellCog se disponível if self.cellcog.available: result = self.cellcog.generate_image( prompt=prompt, aspect_ratio=aspect_ratio, quality="high" ) if result.get("success"): return result logger.warning("⚠️ CellCog falhou, tentando Flux...") # Fallback para Flux return self.flux.generate(prompt, aspect_ratio, model) # Instância global _media_factory = None def get_media_factory() -> AIMediaFactory: """Retorna instância singleton do factory.""" global _media_factory if _media_factory is None: _media_factory = AIMediaFactory() return _media_factory