Spaces:
Running
Running
| """ | |
| ================================================================================ | |
| 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" | |
| 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 | |