akira / modules /api_integrations /art_providers.py
akra35567's picture
Upload 6 files
2b11c4c verified
"""
Art Providers - Museu, Galeria e Geração de Imagens
"""
import requests
import logging
from typing import Dict, Optional, List
logger = logging.getLogger("ArtProviders")
class ArtProviders:
"""Gerencia múltiplos provedores de arte e criatividade"""
API_TIMEOUT = 5.0
@staticmethod
def search_metropolitan_museum(query: str, max_results: int = 5) -> Optional[Dict]:
"""
Busca no acervo do Museu Metropolitano (470k+ obras)
Sem autenticação necessária!
"""
try:
logger.info(f"🖼️ Buscando no Met Museum por '{query}'")
# Busca IDs de objetos
search_url = "https://collectionapi.metmuseum.org/public/collection/v1/search"
search_params = {
"q": query,
"hasImages": "true",
"isPublicDomain": "true"
}
response = requests.get(search_url, params=search_params, timeout=ArtProviders.API_TIMEOUT)
if response.status_code != 200:
logger.warning(f"❌ Met Museum search retornou {response.status_code}")
return None
data = response.json()
object_ids = data.get("objectIDs", [])[:max_results]
if not object_ids:
logger.warning(f"❌ Nenhuma obra encontrada para '{query}'")
return None
# Busca detalhes das obras
obras = []
for obj_id in object_ids[:max_results]:
try:
obj_url = f"https://collectionapi.metmuseum.org/public/collection/v1/objects/{obj_id}"
obj_response = requests.get(obj_url, timeout=ArtProviders.API_TIMEOUT)
if obj_response.status_code == 200:
obj_data = obj_response.json()
obras.append({
"titulo": obj_data.get("title", "Desconhecido"),
"artista": obj_data.get("artistDisplayName", "Artista desconhecido"),
"ano": obj_data.get("objectDate", "Data desconhecida"),
"tecnica": obj_data.get("medium", "Técnica desconhecida"),
"url_imagem": obj_data.get("primaryImage"),
"url_met": obj_data.get("objectURL"),
"descricao": obj_data.get("creditLine", ""),
"departamento": obj_data.get("department", "")
})
except Exception as e:
logger.debug(f"Erro ao buscar objeto {obj_id}: {e}")
continue
return {
"sucesso": True,
"tipo": "museum_search",
"query": query,
"obras": obras,
"total": len(obras),
"fonte": "met_museum"
}
except requests.Timeout:
logger.warning("⏱️ Met Museum timeout")
return None
except Exception as e:
logger.error(f"💥 Erro em Met Museum: {e}")
return None
@staticmethod
def generate_with_pollinations(prompt: str, style: str = None) -> Optional[Dict]:
"""
Gera imagem com Pollinations AI (fallback para Flux)
Vantagem: Sem autenticação, resposta direta (binary)
Desvantagem: Menos controle, qualidade variável
"""
try:
logger.info(f"🤖 Gerando imagem com Pollinations AI: {prompt}")
# Pollinations retorna imagem diretamente como URL
# Devemos usar endpoint especial para json
api_url = "https://api.pollinations.ai/v1/images/generations"
payload = {
"prompt": prompt,
"model": "flux",
"width": 1024,
"height": 1024
}
response = requests.post(
api_url,
json=payload,
timeout=ArtProviders.API_TIMEOUT
)
if response.status_code != 200:
logger.warning(f"❌ Pollinations retornou {response.status_code}")
return None
data = response.json()
# Pollinations retorna URL da imagem gerada
if "data" in data and len(data["data"]) > 0:
return {
"sucesso": True,
"tipo": "image_generation",
"prompt": prompt,
"url_imagem": data["data"][0].get("url"),
"modelo": "flux",
"fonte": "pollinations_ai"
}
return None
except requests.Timeout:
logger.warning("⏱️ Pollinations timeout")
return None
except Exception as e:
logger.error(f"💥 Erro em Pollinations: {e}")
return None
@staticmethod
def generate_simple_ascii_art(theme: str) -> Dict:
"""
Fallback: ASCII art simples
Quando tudo falha, pelo menos retorna algo criativo
"""
ascii_arts = {
"cat": """
/\\_/\\
( o.o )
> ^ <
/| |\\
| |
""",
"heart": """
❤️ ❤️ ❤️
❤️ ❤️ ❤️
❤️ ❤️ ❤️
❤️ ❤️
❤️ ❤️
❤️ ❤️
❤️ ❤️
❤️ ❤️
❤️ ❤️
❤️ ❤️
❤️❤️
""",
"rocket": """
/\\
/ \\
/ \\
/______\\
| |
/| |\\
/ | | \\
/ |______| \\
/ /\\ \\
/ / \\ \\
(_/ \\_)
""",
"tree": """
*
/|\\
|
/*\\
/ \\
|
/**\\
/ \\
|
/***\\
/ \\
||
/||\\
/_||_\\
"""
}
art = ascii_arts.get(theme, ascii_arts["cat"])
return {
"sucesso": True,
"tipo": "ascii_art",
"tema": theme,
"arte": art,
"fonte": "fallback_ascii"
}