Files
social-media-automation/app/services/image_generator.py
Consultoría AS 049d2133f9 Implementación inicial del sistema de automatización de redes sociales
- Estructura completa del proyecto con FastAPI
- Modelos de base de datos (productos, servicios, posts, calendario, interacciones)
- Publishers para X, Threads, Instagram, Facebook
- Generador de contenido con DeepSeek API
- Worker de Celery con tareas programadas
- Dashboard básico con templates HTML
- Docker Compose para despliegue
- Documentación completa

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 01:11:44 +00:00

175 lines
5.0 KiB
Python

"""
Servicio de generación de imágenes para posts.
"""
import os
from typing import Dict, Optional
from pathlib import Path
from html2image import Html2Image
from PIL import Image
from jinja2 import Environment, FileSystemLoader
from app.core.config import settings
class ImageGenerator:
"""Generador de imágenes usando plantillas HTML."""
def __init__(self):
self.templates_dir = Path("templates")
self.output_dir = Path("uploads/generated")
self.output_dir.mkdir(parents=True, exist_ok=True)
self.jinja_env = Environment(
loader=FileSystemLoader(self.templates_dir)
)
self.hti = Html2Image(
output_path=str(self.output_dir),
custom_flags=['--no-sandbox', '--disable-gpu']
)
def _render_template(self, template_name: str, variables: Dict) -> str:
"""Renderizar una plantilla HTML con variables."""
template = self.jinja_env.get_template(template_name)
return template.render(**variables)
async def generate_tip_card(
self,
title: str,
content: str,
category: str,
output_name: str
) -> str:
"""Generar imagen de tip tech."""
variables = {
"title": title,
"content": content,
"category": category,
"logo_url": f"{settings.BUSINESS_WEBSITE}/logo.png",
"website": settings.BUSINESS_WEBSITE,
"business_name": settings.BUSINESS_NAME
}
html_content = self._render_template("tip_card.html", variables)
# Generar imagen
output_file = f"{output_name}.png"
self.hti.screenshot(
html_str=html_content,
save_as=output_file,
size=(1080, 1080)
)
return str(self.output_dir / output_file)
async def generate_product_card(
self,
name: str,
price: float,
image_url: str,
highlights: list,
output_name: str
) -> str:
"""Generar imagen de producto."""
variables = {
"name": name,
"price": f"${price:,.2f} MXN",
"image_url": image_url,
"highlights": highlights[:3], # Máximo 3 highlights
"logo_url": f"{settings.BUSINESS_WEBSITE}/logo.png",
"website": settings.BUSINESS_WEBSITE,
"business_name": settings.BUSINESS_NAME
}
html_content = self._render_template("product_card.html", variables)
output_file = f"{output_name}.png"
self.hti.screenshot(
html_str=html_content,
save_as=output_file,
size=(1080, 1080)
)
return str(self.output_dir / output_file)
async def generate_service_card(
self,
name: str,
tagline: str,
benefits: list,
icon: str,
output_name: str
) -> str:
"""Generar imagen de servicio."""
variables = {
"name": name,
"tagline": tagline,
"benefits": benefits[:4], # Máximo 4 beneficios
"icon": icon,
"logo_url": f"{settings.BUSINESS_WEBSITE}/logo.png",
"website": settings.BUSINESS_WEBSITE,
"business_name": settings.BUSINESS_NAME
}
html_content = self._render_template("service_card.html", variables)
output_file = f"{output_name}.png"
self.hti.screenshot(
html_str=html_content,
save_as=output_file,
size=(1080, 1080)
)
return str(self.output_dir / output_file)
async def resize_for_platform(
self,
image_path: str,
platform: str
) -> str:
"""Redimensionar imagen para una plataforma específica."""
sizes = {
"x": (1200, 675), # 16:9
"threads": (1080, 1080), # 1:1
"instagram": (1080, 1080), # 1:1
"facebook": (1200, 630) # ~1.9:1
}
target_size = sizes.get(platform, (1080, 1080))
img = Image.open(image_path)
# Crear nueva imagen con el tamaño objetivo
new_img = Image.new('RGB', target_size, (26, 26, 46)) # Color de fondo de la marca
# Calcular posición para centrar
img_ratio = img.width / img.height
target_ratio = target_size[0] / target_size[1]
if img_ratio > target_ratio:
# Imagen más ancha
new_width = target_size[0]
new_height = int(new_width / img_ratio)
else:
# Imagen más alta
new_height = target_size[1]
new_width = int(new_height * img_ratio)
img_resized = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
# Centrar en la nueva imagen
x = (target_size[0] - new_width) // 2
y = (target_size[1] - new_height) // 2
new_img.paste(img_resized, (x, y))
# Guardar
output_path = image_path.replace('.png', f'_{platform}.png')
new_img.save(output_path, 'PNG', quality=95)
return output_path
# Instancia global
image_generator = ImageGenerator()