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>
This commit is contained in:
2026-01-28 01:11:44 +00:00
commit 049d2133f9
53 changed files with 5876 additions and 0 deletions

View File

@@ -0,0 +1,314 @@
"""
Servicio de generación de contenido con DeepSeek API.
"""
import json
from typing import Optional, List, Dict
from openai import OpenAI
from app.core.config import settings
class ContentGenerator:
"""Generador de contenido usando DeepSeek API."""
def __init__(self):
self.client = OpenAI(
api_key=settings.DEEPSEEK_API_KEY,
base_url=settings.DEEPSEEK_BASE_URL
)
self.model = "deepseek-chat"
def _get_system_prompt(self) -> str:
"""Obtener el prompt del sistema con la personalidad de la marca."""
return f"""Eres el Community Manager de {settings.BUSINESS_NAME}, una empresa de tecnología ubicada en {settings.BUSINESS_LOCATION}.
SOBRE LA EMPRESA:
- Especializada en soluciones de IA, automatización y transformación digital
- Vende equipos de cómputo e impresoras 3D
- Sitio web: {settings.BUSINESS_WEBSITE}
TONO DE COMUNICACIÓN:
{settings.CONTENT_TONE}
ESTILO (inspirado en @midudev, @MoureDev, @SoyDalto):
- Tips cortos y accionables
- Contenido educativo de valor
- Cercano pero profesional
- Uso moderado de emojis
- Hashtags relevantes (máximo 3-5)
REGLAS:
- Nunca uses lenguaje ofensivo
- No hagas promesas exageradas
- Sé honesto y transparente
- Enfócate en ayudar, no en vender directamente
- Adapta el contenido a cada plataforma"""
async def generate_tip_tech(
self,
category: str,
platform: str,
template: Optional[str] = None
) -> str:
"""Generar un tip tech."""
char_limits = {
"x": 280,
"threads": 500,
"instagram": 2200,
"facebook": 500
}
prompt = f"""Genera un tip de tecnología para la categoría: {category}
PLATAFORMA: {platform}
LÍMITE DE CARACTERES: {char_limits.get(platform, 500)}
{f'USA ESTE TEMPLATE COMO BASE: {template}' if template else ''}
REQUISITOS:
- Tip práctico y accionable
- Fácil de entender
- Incluye un emoji relevante al inicio
- Termina con 2-3 hashtags relevantes
- NO incluyas enlaces
Responde SOLO con el texto del post, sin explicaciones."""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": self._get_system_prompt()},
{"role": "user", "content": prompt}
],
max_tokens=300,
temperature=0.7
)
return response.choices[0].message.content.strip()
async def generate_product_post(
self,
product: Dict,
platform: str
) -> str:
"""Generar post para un producto."""
char_limits = {
"x": 280,
"threads": 500,
"instagram": 2200,
"facebook": 1000
}
prompt = f"""Genera un post promocional para este producto:
PRODUCTO: {product['name']}
DESCRIPCIÓN: {product.get('description', 'N/A')}
PRECIO: ${product['price']:,.2f} MXN
CATEGORÍA: {product['category']}
ESPECIFICACIONES: {json.dumps(product.get('specs', {}), ensure_ascii=False)}
PUNTOS DESTACADOS: {', '.join(product.get('highlights', []))}
PLATAFORMA: {platform}
LÍMITE DE CARACTERES: {char_limits.get(platform, 500)}
REQUISITOS:
- Destaca los beneficios principales
- Incluye el precio
- Usa emojis relevantes
- Incluye CTA sutil (ej: "Contáctanos", "Más info en DM")
- Termina con 2-3 hashtags
- NO inventes especificaciones
Responde SOLO con el texto del post."""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": self._get_system_prompt()},
{"role": "user", "content": prompt}
],
max_tokens=400,
temperature=0.7
)
return response.choices[0].message.content.strip()
async def generate_service_post(
self,
service: Dict,
platform: str
) -> str:
"""Generar post para un servicio."""
char_limits = {
"x": 280,
"threads": 500,
"instagram": 2200,
"facebook": 1000
}
prompt = f"""Genera un post promocional para este servicio:
SERVICIO: {service['name']}
DESCRIPCIÓN: {service.get('description', 'N/A')}
CATEGORÍA: {service['category']}
SECTORES OBJETIVO: {', '.join(service.get('target_sectors', []))}
BENEFICIOS: {', '.join(service.get('benefits', []))}
CTA: {service.get('call_to_action', 'Contáctanos para más información')}
PLATAFORMA: {platform}
LÍMITE DE CARACTERES: {char_limits.get(platform, 500)}
REQUISITOS:
- Enfócate en el problema que resuelve
- Destaca 2-3 beneficios clave
- Usa emojis relevantes (✅, 🚀, 💡)
- Incluye el CTA
- Termina con 2-3 hashtags
- Tono consultivo, no vendedor
Responde SOLO con el texto del post."""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": self._get_system_prompt()},
{"role": "user", "content": prompt}
],
max_tokens=400,
temperature=0.7
)
return response.choices[0].message.content.strip()
async def generate_thread(
self,
topic: str,
num_posts: int = 5
) -> List[str]:
"""Generar un hilo educativo."""
prompt = f"""Genera un hilo educativo de {num_posts} posts sobre: {topic}
REQUISITOS:
- Post 1: Gancho que capture atención
- Posts 2-{num_posts-1}: Contenido educativo de valor
- Post {num_posts}: Conclusión con CTA
FORMATO:
- Cada post máximo 280 caracteres
- Numera cada post (1/, 2/, etc.)
- Usa emojis relevantes
- El último post incluye hashtags
Responde con cada post en una línea separada, sin explicaciones."""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": self._get_system_prompt()},
{"role": "user", "content": prompt}
],
max_tokens=1500,
temperature=0.7
)
content = response.choices[0].message.content.strip()
# Separar posts por líneas no vacías
posts = [p.strip() for p in content.split('\n') if p.strip()]
return posts
async def generate_response_suggestion(
self,
interaction_content: str,
interaction_type: str,
context: Optional[str] = None
) -> List[str]:
"""Generar sugerencias de respuesta para una interacción."""
prompt = f"""Un usuario escribió esto en redes sociales:
"{interaction_content}"
TIPO DE INTERACCIÓN: {interaction_type}
{f'CONTEXTO ADICIONAL: {context}' if context else ''}
Genera 3 opciones de respuesta diferentes:
1. Respuesta corta y amigable
2. Respuesta que invite a continuar la conversación
3. Respuesta que dirija a más información/contacto
REQUISITOS:
- Máximo 280 caracteres cada una
- Tono amigable y profesional
- Si es una queja, sé empático
- Si es una pregunta técnica, sé útil
Responde con las 3 opciones numeradas, una por línea."""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": self._get_system_prompt()},
{"role": "user", "content": prompt}
],
max_tokens=500,
temperature=0.8
)
content = response.choices[0].message.content.strip()
suggestions = [s.strip() for s in content.split('\n') if s.strip()]
# Limpiar numeración si existe
cleaned = []
for s in suggestions:
if s[0].isdigit() and (s[1] == '.' or s[1] == ')'):
s = s[2:].strip()
cleaned.append(s)
return cleaned[:3] # Máximo 3 sugerencias
async def adapt_content_for_platform(
self,
content: str,
target_platform: str
) -> str:
"""Adaptar contenido existente a una plataforma específica."""
char_limits = {
"x": 280,
"threads": 500,
"instagram": 2200,
"facebook": 1000
}
prompt = f"""Adapta este contenido para {target_platform}:
CONTENIDO ORIGINAL:
{content}
LÍMITE DE CARACTERES: {char_limits.get(target_platform, 500)}
REQUISITOS PARA {target_platform.upper()}:
{"- Muy conciso, directo al punto" if target_platform == "x" else ""}
{"- Puede ser más extenso, incluir más contexto" if target_platform == "instagram" else ""}
{"- Tono más casual y cercano" if target_platform == "threads" else ""}
{"- Puede incluir links, más profesional" if target_platform == "facebook" else ""}
- Mantén la esencia del mensaje
- Ajusta hashtags según la plataforma
Responde SOLO con el contenido adaptado."""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": self._get_system_prompt()},
{"role": "user", "content": prompt}
],
max_tokens=400,
temperature=0.6
)
return response.choices[0].message.content.strip()
# Instancia global
content_generator = ContentGenerator()