""" 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()