""" API Routes para gestión de Interacciones. """ from datetime import datetime from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from pydantic import BaseModel from app.core.database import get_db from app.models.interaction import Interaction router = APIRouter() # =========================================== # SCHEMAS # =========================================== class InteractionResponse(BaseModel): content: str class Config: from_attributes = True # =========================================== # ENDPOINTS # =========================================== @router.get("/") async def list_interactions( platform: Optional[str] = Query(None), interaction_type: Optional[str] = Query(None), responded: Optional[bool] = Query(None), is_lead: Optional[bool] = Query(None), is_read: Optional[bool] = Query(None), limit: int = Query(50, le=100), offset: int = Query(0), db: Session = Depends(get_db) ): """Listar interacciones con filtros.""" query = db.query(Interaction) if platform: query = query.filter(Interaction.platform == platform) if interaction_type: query = query.filter(Interaction.interaction_type == interaction_type) if responded is not None: query = query.filter(Interaction.responded == responded) if is_lead is not None: query = query.filter(Interaction.is_lead == is_lead) if is_read is not None: query = query.filter(Interaction.is_read == is_read) interactions = query.order_by( Interaction.interaction_at.desc() ).offset(offset).limit(limit).all() return [i.to_dict() for i in interactions] @router.get("/pending") async def list_pending_interactions(db: Session = Depends(get_db)): """Listar interacciones sin responder.""" interactions = db.query(Interaction).filter( Interaction.responded == False, Interaction.is_archived == False ).order_by( Interaction.priority.desc(), Interaction.interaction_at.desc() ).all() return [i.to_dict() for i in interactions] @router.get("/leads") async def list_leads(db: Session = Depends(get_db)): """Listar interacciones marcadas como leads.""" interactions = db.query(Interaction).filter( Interaction.is_lead == True ).order_by(Interaction.interaction_at.desc()).all() return [i.to_dict() for i in interactions] @router.get("/stats") async def get_interaction_stats(db: Session = Depends(get_db)): """Obtener estadísticas de interacciones.""" total = db.query(Interaction).count() pending = db.query(Interaction).filter( Interaction.responded == False, Interaction.is_archived == False ).count() leads = db.query(Interaction).filter(Interaction.is_lead == True).count() # Por plataforma by_platform = {} for platform in ["x", "threads", "instagram", "facebook"]: by_platform[platform] = db.query(Interaction).filter( Interaction.platform == platform ).count() return { "total": total, "pending": pending, "leads": leads, "by_platform": by_platform } @router.get("/{interaction_id}") async def get_interaction(interaction_id: int, db: Session = Depends(get_db)): """Obtener una interacción por ID.""" interaction = db.query(Interaction).filter(Interaction.id == interaction_id).first() if not interaction: raise HTTPException(status_code=404, detail="Interacción no encontrada") return interaction.to_dict() @router.post("/{interaction_id}/respond") async def respond_to_interaction( interaction_id: int, response_data: InteractionResponse, db: Session = Depends(get_db) ): """Responder a una interacción.""" interaction = db.query(Interaction).filter(Interaction.id == interaction_id).first() if not interaction: raise HTTPException(status_code=404, detail="Interacción no encontrada") # TODO: Enviar respuesta a la plataforma correspondiente # from app.publishers import get_publisher # publisher = get_publisher(interaction.platform) # result = await publisher.reply(interaction.external_id, response_data.content) interaction.responded = True interaction.response_content = response_data.content interaction.responded_at = datetime.utcnow() db.commit() return { "message": "Respuesta guardada", "interaction_id": interaction_id, "note": "La publicación a la plataforma está en desarrollo" } @router.post("/{interaction_id}/suggest-response") async def suggest_response(interaction_id: int, db: Session = Depends(get_db)): """Generar sugerencia de respuesta con IA.""" interaction = db.query(Interaction).filter(Interaction.id == interaction_id).first() if not interaction: raise HTTPException(status_code=404, detail="Interacción no encontrada") # TODO: Implementar generación con DeepSeek # from app.services.content_generator import generate_response_suggestion # suggestions = await generate_response_suggestion(interaction) # Respuestas placeholder suggestions = [ f"¡Gracias por tu comentario! Nos da gusto que te interese nuestro contenido.", f"¡Hola! Gracias por escribirnos. ¿En qué podemos ayudarte?", f"¡Excelente pregunta! Te respondemos por DM para darte más detalles." ] return { "suggestions": suggestions, "note": "La generación con IA está en desarrollo" } @router.post("/{interaction_id}/mark-as-lead") async def mark_as_lead(interaction_id: int, db: Session = Depends(get_db)): """Marcar interacción como lead potencial.""" interaction = db.query(Interaction).filter(Interaction.id == interaction_id).first() if not interaction: raise HTTPException(status_code=404, detail="Interacción no encontrada") interaction.is_lead = not interaction.is_lead db.commit() return { "message": f"{'Marcado' if interaction.is_lead else 'Desmarcado'} como lead", "is_lead": interaction.is_lead } @router.post("/{interaction_id}/mark-as-read") async def mark_as_read(interaction_id: int, db: Session = Depends(get_db)): """Marcar interacción como leída.""" interaction = db.query(Interaction).filter(Interaction.id == interaction_id).first() if not interaction: raise HTTPException(status_code=404, detail="Interacción no encontrada") interaction.is_read = True db.commit() return {"message": "Marcado como leído", "interaction_id": interaction_id} @router.post("/{interaction_id}/archive") async def archive_interaction(interaction_id: int, db: Session = Depends(get_db)): """Archivar una interacción.""" interaction = db.query(Interaction).filter(Interaction.id == interaction_id).first() if not interaction: raise HTTPException(status_code=404, detail="Interacción no encontrada") interaction.is_archived = True db.commit() return {"message": "Interacción archivada", "interaction_id": interaction_id} @router.delete("/{interaction_id}") async def delete_interaction(interaction_id: int, db: Session = Depends(get_db)): """Eliminar una interacción.""" interaction = db.query(Interaction).filter(Interaction.id == interaction_id).first() if not interaction: raise HTTPException(status_code=404, detail="Interacción no encontrada") db.delete(interaction) db.commit() return {"message": "Interacción eliminada", "interaction_id": interaction_id}