docs: Add comprehensive documentation for all new features

- FEATURES_OVERVIEW.md: Complete summary of all system features
- ANALYTICS.md: Analytics and reporting system documentation
- ODOO_INTEGRATION.md: Odoo ERP integration guide
- AB_TESTING.md: A/B testing system documentation
- CONTENT_RECYCLING.md: Content recycling system docs
- THREAD_SERIES.md: Thread series and scheduled posts
- IMAGE_TEMPLATES.md: Visual template system documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-28 03:17:23 +00:00
parent ecc2ca73ea
commit e2882ce72b
7 changed files with 2099 additions and 0 deletions

297
docs/AB_TESTING.md Normal file
View File

@@ -0,0 +1,297 @@
# A/B Testing
Sistema de pruebas A/B para optimizar contenido y maximizar engagement.
## Descripción
El A/B Testing permite comparar diferentes versiones de contenido para determinar cuál tiene mejor rendimiento. El sistema:
1. Crea múltiples variantes de contenido
2. Publica cada variante
3. Recopila métricas de cada una
4. Determina estadísticamente el ganador
## Modelos de Datos
### ABTest
```python
ABTest:
id: int
name: str
description: str
test_type: str # content, timing, hashtags, image
platform: str # x, threads, instagram, facebook
status: str # draft, running, completed, cancelled
started_at: datetime
ended_at: datetime
duration_hours: int # Duración del test (default 24)
winning_variant_id: int (FK)
confidence_level: float # Nivel de confianza estadística
min_sample_size: int # Mín impresiones por variante (default 100)
success_metric: str # engagement_rate, likes, comments, shares
```
### ABTestVariant
```python
ABTestVariant:
id: int
test_id: int (FK -> ab_tests)
name: str # A, B, C, D
content: str
hashtags: JSON
image_url: str
post_id: int (FK -> posts)
# Métricas
impressions: int
reach: int
likes: int
comments: int
shares: int
clicks: int
engagement_rate: float
is_winner: bool
published_at: datetime
```
## API Endpoints
### GET /api/ab-tests/
Lista todos los tests A/B.
**Parámetros:**
- `status`: draft, running, completed, cancelled
- `platform`: x, threads, etc.
- `limit` (int, default=20)
**Respuesta:**
```json
{
"tests": [
{
"id": 1,
"name": "Test de copies",
"platform": "x",
"status": "running",
"variants": [...]
}
],
"count": 5
}
```
### GET /api/ab-tests/{test_id}
Obtiene un test específico con sus variantes.
### POST /api/ab-tests/
Crea un nuevo test A/B.
**Body:**
```json
{
"name": "Test de copies para tips",
"platform": "x",
"variants": [
{
"name": "A",
"content": "💡 Tip: Automatiza tus procesos con IA...",
"hashtags": ["#IA", "#Automatización"]
},
{
"name": "B",
"content": "¿Sabías que la IA puede ahorrarte 10 horas semanales?...",
"hashtags": ["#Productividad", "#Tech"]
}
],
"test_type": "content",
"duration_hours": 24,
"min_sample_size": 100,
"success_metric": "engagement_rate"
}
```
**Validaciones:**
- Mínimo 2 variantes, máximo 4
- Cada variante debe tener contenido
### POST /api/ab-tests/{test_id}/start
Inicia un test A/B.
**Proceso:**
1. Crea posts para cada variante
2. Programa publicación (escalonada cada 5 min)
3. Cambia status a "running"
4. Registra start_time
**Respuesta:**
```json
{
"message": "A/B test started successfully",
"success": true,
"test_id": 1,
"post_ids": [101, 102],
"variants_count": 2
}
```
### POST /api/ab-tests/{test_id}/evaluate
Evalúa resultados y determina ganador.
**Proceso:**
1. Actualiza métricas de cada variante
2. Verifica tamaño de muestra mínimo
3. Ejecuta test estadístico (chi-square)
4. Determina ganador y confianza
5. Si duration_hours pasó, marca como completed
**Respuesta:**
```json
{
"success": true,
"winner": {
"variant_id": 1,
"name": "A",
"engagement_rate": 4.5,
"impressions": 1500
},
"runner_up": {
"variant_id": 2,
"name": "B",
"engagement_rate": 3.2,
"impressions": 1400
},
"confidence_level": 95.5,
"p_value": 0.045,
"test_status": "completed"
}
```
**Si datos insuficientes:**
```json
{
"success": true,
"status": "insufficient_data",
"min_impressions": 50,
"required": 100
}
```
### GET /api/ab-tests/{test_id}/results
Obtiene resultados actuales (sin determinar ganador).
### POST /api/ab-tests/{test_id}/cancel
Cancela un test en progreso.
## Tareas Programadas
### evaluate_ab_tests
- **Frecuencia:** Cada hora
- **Función:**
- Busca tests en estado "running"
- Si pasó duration_hours, evalúa y completa
- Si no, solo actualiza métricas
## Tipos de Test
| Tipo | Descripción |
|------|-------------|
| `content` | Prueba diferentes textos |
| `timing` | Prueba diferentes horarios |
| `hashtags` | Prueba diferentes conjuntos de hashtags |
| `image` | Prueba diferentes imágenes |
## Métricas de Éxito
| Métrica | Descripción |
|---------|-------------|
| `engagement_rate` | (likes + comments + shares) / impressions |
| `likes` | Total de likes |
| `comments` | Total de comentarios |
| `shares` | Total de compartidos |
| `clicks` | Total de clics (si aplica) |
## Análisis Estadístico
El sistema usa el **test chi-cuadrado** para determinar significancia estadística:
```python
# Tabla de contingencia
[
[engagements_A, non_engagements_A],
[engagements_B, non_engagements_B]
]
chi2, p_value, dof, expected = scipy.stats.chi2_contingency(tabla)
confidence = (1 - p_value) * 100
```
### Interpretación
| p-value | Confianza | Interpretación |
|---------|-----------|----------------|
| < 0.01 | > 99% | Muy significativo |
| < 0.05 | > 95% | Significativo |
| < 0.10 | > 90% | Marginalmente significativo |
| ≥ 0.10 | < 90% | No significativo |
## Flujo de Trabajo
```
1. Crear Test (status: draft)
2. Iniciar Test (status: running)
- Crea posts para variantes
- Programa publicación
3. Esperar duración
- Sistema recopila métricas cada 15 min
- Evalúa cada hora
4. Evaluar Resultados (status: completed)
- Determina ganador estadístico
- Calcula nivel de confianza
```
## Ejemplo de Uso
```python
from app.services.ab_testing_service import ab_testing_service
# Crear test
test = await ab_testing_service.create_test(
name="Test de engagement",
platform="x",
variants=[
{"name": "A", "content": "Versión corta y directa"},
{"name": "B", "content": "Versión más elaborada con detalles"}
],
duration_hours=48,
min_sample_size=200
)
# Iniciar
result = await ab_testing_service.start_test(test.id)
# Evaluar (después de publicado)
results = await ab_testing_service.evaluate_test(test.id)
if results.get("winner"):
print(f"Ganador: Variante {results['winner']['name']}")
print(f"Confianza: {results['confidence_level']:.1f}%")
```
## Mejores Prácticas
1. **Tamaño de muestra:** Espera al menos 100 impresiones por variante
2. **Una variable:** Prueba solo un elemento a la vez
3. **Duración:** Mínimo 24 horas para datos representativos
4. **Horarios:** Publica variantes en horarios similares
5. **Confianza:** Busca > 95% antes de tomar decisiones

264
docs/ANALYTICS.md Normal file
View File

@@ -0,0 +1,264 @@
# Analytics y Reportes
Sistema completo de métricas y análisis de rendimiento para optimizar tu estrategia de contenido.
## Modelos de Datos
### PostMetrics
Registra métricas de cada post a lo largo del tiempo.
```python
PostMetrics:
id: int
post_id: int (FK -> posts)
platform: str # x, threads, instagram, facebook
likes: int
comments: int
shares: int
impressions: int
reach: int
saves: int
clicks: int
replies: int
quotes: int
engagement_rate: float
recorded_at: datetime
```
### AnalyticsReport
Reportes agregados (diarios, semanales, mensuales).
```python
AnalyticsReport:
id: int
report_type: str # daily, weekly, monthly
period_start: date
period_end: date
platform: str (opcional)
total_posts: int
total_impressions: int
total_engagements: int
avg_engagement_rate: float
top_posts: JSON # Lista de mejores posts
best_times: JSON # Mejores horarios
content_performance: JSON # Por tipo de contenido
platform_breakdown: JSON # Por plataforma
summary_text: str # Texto para Telegram
```
## API Endpoints
### GET /api/analytics/dashboard
Obtiene datos del dashboard principal.
**Parámetros:**
- `days` (int, default=30): Período a analizar
- `platform` (str, opcional): Filtrar por plataforma
**Respuesta:**
```json
{
"period_days": 30,
"total_posts": 45,
"total_impressions": 125000,
"total_engagements": 3500,
"total_likes": 2800,
"total_comments": 450,
"total_shares": 250,
"avg_engagement_rate": 2.8,
"platform_breakdown": {
"x": {"posts": 20, "engagements": 1500},
"threads": {"posts": 25, "engagements": 2000}
},
"content_breakdown": {
"tip_tech": {"posts": 15, "engagements": 1200},
"producto": {"posts": 10, "engagements": 800}
},
"pending_interactions": 12
}
```
### GET /api/analytics/top-posts
Obtiene los posts con mejor rendimiento.
**Parámetros:**
- `days` (int, default=30): Período a analizar
- `limit` (int, default=10): Máximo de posts
- `platform` (str, opcional): Filtrar por plataforma
**Respuesta:**
```json
{
"posts": [
{
"id": 123,
"content": "Tip: Usa IA para...",
"content_type": "tip_tech",
"platforms": ["x", "threads"],
"published_at": "2025-01-15T10:00:00",
"likes": 150,
"comments": 25,
"shares": 30,
"impressions": 5000,
"engagement_rate": 4.1
}
],
"count": 10
}
```
### GET /api/analytics/optimal-times
Calcula los mejores horarios para publicar basado en datos históricos.
**Parámetros:**
- `platform` (str, opcional): Filtrar por plataforma
- `days` (int, default=90): Días de datos a analizar
**Respuesta:**
```json
{
"optimal_times": [
{
"day": 1,
"day_name": "Mar",
"hour": 12,
"hour_formatted": "12:00",
"avg_engagement_rate": 4.5,
"sample_size": 15
}
],
"analysis_period_days": 90,
"platform": "x"
}
```
### GET /api/analytics/engagement-trend
Obtiene tendencia de engagement para gráficos.
**Parámetros:**
- `days` (int, default=30): Período
- `platform` (str, opcional): Plataforma
**Respuesta:**
```json
{
"trend": [
{
"date": "2025-01-01",
"posts": 3,
"impressions": 5000,
"engagements": 200
}
],
"period_days": 30,
"platform": null
}
```
### GET /api/analytics/reports
Obtiene reportes históricos.
**Parámetros:**
- `report_type` (str): daily, weekly, monthly
- `limit` (int, default=10): Máximo de reportes
### POST /api/analytics/reports/generate
Genera un nuevo reporte.
**Parámetros:**
- `report_type` (str): weekly (otros tipos próximamente)
### POST /api/analytics/reports/send-telegram
Genera y envía reporte por Telegram.
### GET /api/analytics/posts/{post_id}/metrics
Obtiene métricas detalladas de un post específico.
**Respuesta:**
```json
{
"post_id": 123,
"current_metrics": {"likes": 150, "comments": 25},
"published_at": "2025-01-15T10:00:00",
"platforms": ["x", "threads"],
"metrics_history": [
{
"recorded_at": "2025-01-15T12:00:00",
"likes": 50,
"comments": 10,
"engagement_rate": 2.5
}
]
}
```
## Tareas Programadas
### fetch_post_metrics
- **Frecuencia:** Cada 15 minutos
- **Función:** Obtiene métricas actualizadas de las APIs de cada plataforma
- **Posts afectados:** Publicados en los últimos 7 días
### generate_weekly_analytics_report
- **Frecuencia:** Domingos a las 9:00 AM
- **Función:** Genera reporte semanal completo
- **Acciones:**
- Calcula métricas agregadas
- Compara con semana anterior
- Genera texto para Telegram
- Envía notificación (si está configurado)
### recalculate_optimal_times
- **Frecuencia:** Lunes a las 2:00 AM
- **Función:** Recalcula mejores horarios basado en últimos 90 días
## Dashboard
Accede al dashboard de analytics en `/dashboard/analytics`.
### Características:
- **Cards de métricas:** Posts, impresiones, engagements, tasa
- **Gráfico de tendencia:** Chart.js con impresiones y engagements
- **Desglose por plataforma:** Comparativa visual
- **Top posts:** Lista de mejores performers
- **Mejores horarios:** Mapa de calor visual
- **Rendimiento por contenido:** Por tipo de publicación
## Configuración
```bash
# .env
ANALYTICS_FETCH_INTERVAL=15 # minutos
TELEGRAM_REPORT_ENABLED=true
TELEGRAM_REPORT_DAY=6 # 0=Lunes, 6=Domingo
```
## Ejemplo de Uso
```python
from app.services.analytics_service import analytics_service
# Obtener stats del dashboard
stats = await analytics_service.get_dashboard_stats(days=30, platform="x")
# Obtener top posts
top = await analytics_service.get_top_posts(days=7, limit=5)
# Generar reporte semanal
report = await analytics_service.generate_weekly_report()
print(report.summary_text) # Texto formateado para Telegram
```
## Cálculos
### Engagement Rate
```
engagement_rate = (likes + comments + shares) / impressions * 100
```
### Score de Horario Óptimo
```
Para cada combinación (día, hora):
promedio_engagement = sum(engagement_rates) / count(posts)
ordenar por promedio_engagement descendente
```

267
docs/CONTENT_RECYCLING.md Normal file
View File

@@ -0,0 +1,267 @@
# Reciclaje de Contenido
Sistema para republica contenido exitoso y maximizar su alcance.
## Descripción
El reciclaje de contenido permite:
- Identificar posts con alto engagement
- Republicarlos con modificaciones opcionales
- Trackear rendimiento de versiones recicladas
- Automatizar el proceso de reciclaje
## Modelo de Datos
### RecycledPost
```python
RecycledPost:
id: int
original_post_id: int (FK -> posts)
new_post_id: int (FK -> posts)
recycle_number: int # 1, 2, 3... (veces reciclado)
modifications: JSON
# {"content_changed": true, "hashtags_updated": true, "image_changed": false}
modification_notes: str
original_engagement_rate: float
new_engagement_rate: float
status: str # pending, published, cancelled
reason: str # high_performer, evergreen, seasonal, manual
recycled_at: datetime
scheduled_for: datetime
```
### Campos en Post
```python
# Campos añadidos al modelo Post
is_recyclable: bool # Si puede ser reciclado (default True)
recycled_from_id: int (FK -> posts) # Post original si es reciclado
recycle_count: int # Veces que este post ha sido reciclado
```
## Configuración
```python
# En recycling_service.py
MIN_DAYS_SINCE_PUBLISH = 30 # No reciclar posts recientes
MIN_ENGAGEMENT_RATE = 2.0 # Mínimo 2% engagement
MAX_RECYCLE_COUNT = 3 # Máximo 3 veces por post
```
## API Endpoints
### GET /api/recycling/candidates
Obtiene posts candidatos para reciclar.
**Parámetros:**
- `platform` (str): Filtrar por plataforma
- `content_type` (str): Filtrar por tipo de contenido
- `min_engagement_rate` (float, default=2.0): Engagement mínimo
- `min_days` (int, default=30): Días desde publicación
- `limit` (int, default=20): Máximo candidatos
**Respuesta:**
```json
{
"candidates": [
{
"id": 123,
"content": "Tip: Usa IA para automatizar...",
"full_content": "...",
"content_type": "tip_tech",
"platforms": ["x"],
"published_at": "2024-12-01T10:00:00",
"days_since_publish": 58,
"engagement_rate": 4.5,
"recycle_count": 0,
"score": 3.8,
"metrics": {"likes": 150, "comments": 30}
}
],
"count": 10,
"filters": {
"min_engagement_rate": 2.0,
"min_days": 30
}
}
```
### POST /api/recycling/{post_id}
Recicla un post específico.
**Body (opcional):**
```json
{
"content": "Versión actualizada del contenido...",
"hashtags": ["#nuevo", "#hashtag"],
"image_url": "https://...",
"scheduled_for": "2025-02-01T10:00:00",
"platforms": ["x", "threads"],
"reason": "high_performer"
}
```
**Respuesta:**
```json
{
"message": "Post recycled successfully",
"success": true,
"new_post_id": 456,
"recycle_record_id": 1,
"scheduled_for": "2025-02-01T10:00:00",
"platforms": ["x", "threads"]
}
```
### POST /api/recycling/auto
Reciclaje automático de mejores posts.
**Parámetros:**
- `platform` (str, opcional): Plataforma específica
- `count` (int, default=1, max=5): Cantidad a reciclar
- `min_engagement_rate` (float, default=2.0)
**Respuesta:**
```json
{
"success": true,
"recycled": 2,
"posts": [
{
"original_id": 123,
"new_post_id": 456,
"engagement_rate": 4.5
}
]
}
```
### GET /api/recycling/history
Obtiene historial de reciclaje.
**Parámetros:**
- `original_post_id` (int, opcional): Filtrar por post original
- `limit` (int, default=50)
### POST /api/recycling/{post_id}/disable
Marca un post como no reciclable.
## Sistema de Puntuación
Los candidatos se puntúan con la fórmula:
```python
score = engagement_rate * recency_factor * recycled_penalty
donde:
recency_factor = min(days_since_publish / 90, 1.0)
recycled_penalty = 1 - (recycle_count * 0.2)
```
### Ejemplo
| Post | Engagement | Días | Reciclajes | Score |
|------|------------|------|------------|-------|
| A | 4.0% | 60 | 0 | 4.0 × 0.67 × 1.0 = 2.68 |
| B | 5.0% | 90 | 1 | 5.0 × 1.0 × 0.8 = 4.00 |
| C | 3.0% | 45 | 0 | 3.0 × 0.5 × 1.0 = 1.50 |
Post B tiene el score más alto.
## Tareas Programadas
### auto_recycle_content
- **Frecuencia:** Diario a las 2:00 AM
- **Función:**
- Busca 1 post por plataforma con engagement > 3%
- Programa reciclaje automático
- **Plataformas:** x, threads
## Flujo de Reciclaje
```
1. Identificar Candidatos
- Posts con > 30 días de antigüedad
- Engagement rate > 2%
- recycle_count < 3
- is_recyclable = true
2. Seleccionar por Score
- Ordenar por score descendente
3. Crear Post Reciclado
- Clonar contenido (o modificar)
- Establecer recycled_from_id
- Programar publicación
4. Registrar en RecycledPost
- Guardar relación
- Incrementar recycle_count del original
5. Publicar y Trackear
- Comparar new_engagement_rate vs original
```
## Razones de Reciclaje
| Razón | Descripción |
|-------|-------------|
| `high_performer` | Post con engagement alto |
| `evergreen` | Contenido atemporal relevante |
| `seasonal` | Contenido de temporada que regresa |
| `manual` | Reciclado manualmente |
## Ejemplo de Uso
```python
from app.services.recycling_service import recycling_service
# Buscar candidatos
candidates = await recycling_service.find_recyclable_posts(
platform="x",
min_engagement_rate=3.0,
limit=10
)
for candidate in candidates:
print(f"Post {candidate['id']}: {candidate['engagement_rate']}% - Score {candidate['score']}")
# Reciclar manualmente
result = await recycling_service.recycle_post(
post_id=123,
modifications={"content": "Versión actualizada..."},
reason="evergreen"
)
# Reciclaje automático
result = await recycling_service.auto_recycle(
platform="x",
count=2
)
```
## Mejores Prácticas
1. **Esperar suficiente tiempo:** Mínimo 30 días entre reciclajes
2. **Modificar ligeramente:** Actualiza hashtags o intro
3. **No abusar:** Máximo 3 reciclajes por post
4. **Monitorear:** Compara rendimiento nuevo vs original
5. **Contenido evergreen:** Prioriza contenido atemporal
## Tipos de Contenido Ideales para Reciclar
| Tipo | Ideal | Razón |
|------|-------|-------|
| Tips técnicos | ✅ | Siempre relevantes |
| Tutoriales | ✅ | Valor educativo permanente |
| Productos | ⚠️ | Si stock disponible |
| Promociones | ❌ | Fechas específicas |
| Efemérides | ❌ | Fechas específicas |
| Noticias | ❌ | Se vuelven obsoletas |

218
docs/FEATURES_OVERVIEW.md Normal file
View File

@@ -0,0 +1,218 @@
# Features Overview
Sistema de automatización de redes sociales para Consultoría AS.
## Tabla de Contenidos
1. [Analytics y Reportes](#analytics-y-reportes)
2. [Integración Odoo](#integración-odoo)
3. [A/B Testing](#ab-testing)
4. [Reciclaje de Contenido](#reciclaje-de-contenido)
5. [Thread Series](#thread-series)
6. [Image Templates](#image-templates)
---
## Analytics y Reportes
Sistema completo de métricas y análisis de rendimiento.
**Documentación completa:** [ANALYTICS.md](./ANALYTICS.md)
### Características principales:
- Dashboard interactivo con métricas en tiempo real
- Tracking de engagement por post y plataforma
- Análisis de mejores horarios para publicar
- Reportes semanales automáticos vía Telegram
- Histórico de métricas por post
### Endpoints API:
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| GET | `/api/analytics/dashboard` | Datos del dashboard |
| GET | `/api/analytics/top-posts` | Posts con mejor rendimiento |
| GET | `/api/analytics/optimal-times` | Mejores horarios |
| GET | `/api/analytics/engagement-trend` | Tendencia de engagement |
| GET | `/api/analytics/reports` | Reportes históricos |
| POST | `/api/analytics/reports/generate` | Generar reporte |
| POST | `/api/analytics/reports/send-telegram` | Enviar reporte a Telegram |
---
## Integración Odoo
Sincronización bidireccional con Odoo ERP.
**Documentación completa:** [ODOO_INTEGRATION.md](./ODOO_INTEGRATION.md)
### Características principales:
- Sincronización de productos desde Odoo
- Sincronización de servicios desde Odoo
- Exportación de leads al CRM de Odoo
- Gestión de leads desde interacciones sociales
- Logs de sincronización
### Endpoints API:
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| GET | `/api/odoo/status` | Estado de conexión |
| POST | `/api/odoo/sync/products` | Sincronizar productos |
| POST | `/api/odoo/sync/services` | Sincronizar servicios |
| POST | `/api/odoo/sync/leads` | Exportar leads |
| GET | `/api/odoo/sync/logs` | Historial de sync |
| GET | `/api/leads/` | Listar leads |
| POST | `/api/leads/` | Crear lead |
| POST | `/api/leads/from-interaction/{id}` | Lead desde interacción |
---
## A/B Testing
Sistema de pruebas A/B para optimizar contenido.
**Documentación completa:** [AB_TESTING.md](./AB_TESTING.md)
### Características principales:
- Crear tests con 2-4 variantes
- Publicación automática de variantes
- Seguimiento de métricas por variante
- Análisis estadístico (chi-square)
- Determinación automática de ganador
### Endpoints API:
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| GET | `/api/ab-tests/` | Listar tests |
| POST | `/api/ab-tests/` | Crear test |
| POST | `/api/ab-tests/{id}/start` | Iniciar test |
| POST | `/api/ab-tests/{id}/evaluate` | Evaluar resultados |
| GET | `/api/ab-tests/{id}/results` | Ver resultados |
| POST | `/api/ab-tests/{id}/cancel` | Cancelar test |
---
## Reciclaje de Contenido
Republica contenido exitoso automáticamente.
**Documentación completa:** [CONTENT_RECYCLING.md](./CONTENT_RECYCLING.md)
### Características principales:
- Identificación de posts reciclables por engagement
- Sistema de puntuación para candidatos
- Modificaciones opcionales al reciclar
- Límite de reciclajes por post
- Reciclaje automático programado
### Endpoints API:
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| GET | `/api/recycling/candidates` | Posts candidatos |
| POST | `/api/recycling/{post_id}` | Reciclar post |
| POST | `/api/recycling/auto` | Reciclaje automático |
| GET | `/api/recycling/history` | Historial |
| POST | `/api/recycling/{post_id}/disable` | Deshabilitar reciclaje |
---
## Thread Series
Publica hilos de múltiples posts programados.
**Documentación completa:** [THREAD_SERIES.md](./THREAD_SERIES.md)
### Características principales:
- Crear series de posts conectados
- Generación con IA
- Programación con intervalos configurables
- Soporte para reply chains
- Seguimiento de progreso
### Endpoints API:
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| GET | `/api/threads/` | Listar series |
| POST | `/api/threads/` | Crear serie manual |
| POST | `/api/threads/generate` | Generar con IA |
| POST | `/api/threads/{id}/schedule` | Programar serie |
| POST | `/api/threads/{id}/publish-next` | Publicar siguiente |
| POST | `/api/threads/{id}/cancel` | Cancelar serie |
---
## Image Templates
Sistema de plantillas para generar imágenes.
**Documentación completa:** [IMAGE_TEMPLATES.md](./IMAGE_TEMPLATES.md)
### Características principales:
- Plantillas HTML/CSS inline
- Variables dinámicas
- Múltiples tamaños de salida
- Categorías y tipos de plantillas
- Preview antes de generar
### Endpoints API:
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| GET | `/api/templates/` | Listar plantillas |
| POST | `/api/templates/` | Crear plantilla |
| PUT | `/api/templates/{id}` | Actualizar |
| DELETE | `/api/templates/{id}` | Eliminar |
| POST | `/api/templates/preview` | Previsualizar |
---
## Tareas Programadas (Celery Beat)
| Tarea | Frecuencia | Descripción |
|-------|------------|-------------|
| `check_scheduled_posts` | Cada minuto | Publica posts programados |
| `check_thread_schedules` | Cada minuto | Publica posts de hilos |
| `fetch_post_metrics` | Cada 15 min | Actualiza métricas |
| `sync_interactions` | Cada 15 min | Sincroniza interacciones |
| `export_leads_to_odoo` | Cada hora | Exporta leads |
| `evaluate_ab_tests` | Cada hora | Evalúa tests A/B |
| `generate_daily_content` | 6:00 AM | Genera contenido |
| `sync_products_from_odoo` | 6:00 AM | Sincroniza productos |
| `sync_services_from_odoo` | 6:05 AM | Sincroniza servicios |
| `auto_recycle_content` | 2:00 AM | Recicla contenido |
| `recalculate_optimal_times` | Lunes 2:00 AM | Recalcula horarios |
| `generate_weekly_report` | Domingo 9:00 AM | Genera reporte |
| `send_daily_summary` | 9:00 PM | Resumen diario |
| `cleanup_old_data` | Domingo 3:00 AM | Limpieza de datos |
---
## Configuración
Variables de entorno requeridas en `.env`:
```bash
# Analytics
ANALYTICS_FETCH_INTERVAL=15
TELEGRAM_REPORT_ENABLED=true
TELEGRAM_REPORT_DAY=6
# Odoo
ODOO_URL=https://tuempresa.odoo.com
ODOO_DB=nombre_bd
ODOO_USERNAME=usuario
ODOO_PASSWORD=api_key
ODOO_SYNC_ENABLED=false
```
---
## Dashboard URLs
| URL | Descripción |
|-----|-------------|
| `/dashboard` | Panel principal |
| `/dashboard/analytics` | Analytics |
| `/dashboard/leads` | Gestión de leads |
| `/dashboard/posts` | Gestión de posts |
| `/dashboard/calendar` | Calendario |
| `/dashboard/interactions` | Interacciones |
| `/api/docs` | Documentación Swagger |

350
docs/IMAGE_TEMPLATES.md Normal file
View File

@@ -0,0 +1,350 @@
# Image Templates
Sistema de plantillas para generar imágenes dinámicas.
## Descripción
Las plantillas de imagen permiten:
- Definir diseños reutilizables en HTML/CSS
- Insertar variables dinámicas
- Generar imágenes para diferentes plataformas
- Mantener consistencia visual
## Modelo de Datos
### ImageTemplate
```python
ImageTemplate:
id: int
name: str
description: str
category: str # tip, producto, servicio, promocion, etc.
template_type: str # tip_card, product_card, quote, promo, announcement
# Plantilla
template_file: str # Ruta a archivo (opcional)
html_template: str # HTML inline
preview_url: str # URL de imagen preview
# Variables
variables: [str] # ["title", "content", "accent_color"]
# Configuración de diseño
design_config: JSON
# {
# "width": 1080,
# "height": 1080,
# "background_color": "#1a1a2e",
# "accent_color": "#d4a574",
# "font_family": "Inter"
# }
# Tamaños de salida
output_sizes: JSON
# {
# "instagram": {"width": 1080, "height": 1080},
# "x": {"width": 1200, "height": 675},
# "facebook": {"width": 1200, "height": 630}
# }
is_active: bool
```
## API Endpoints
### GET /api/templates/
Lista todas las plantillas.
**Parámetros:**
- `category`: tip, producto, servicio, etc.
- `template_type`: tip_card, product_card, etc.
- `active_only` (bool, default=true)
- `limit` (int, default=50)
**Respuesta:**
```json
{
"templates": [
{
"id": 1,
"name": "Tip Card Oscuro",
"description": "Tarjeta para tips con fondo oscuro",
"category": "tip",
"template_type": "tip_card",
"variables": ["title", "content", "emoji"],
"preview_url": "/uploads/previews/tip_card_dark.png"
}
],
"count": 10
}
```
### GET /api/templates/{template_id}
Obtiene una plantilla con detalles completos.
Incluye `full_html_template` con el HTML completo.
### POST /api/templates/
Crea una nueva plantilla.
**Body:**
```json
{
"name": "Quote Card",
"description": "Tarjeta para frases motivacionales",
"category": "frase",
"template_type": "quote",
"html_template": "<div class='card'>...</div>",
"variables": ["quote", "author", "background_image"],
"design_config": {
"width": 1080,
"height": 1080,
"background_color": "#1a1a2e"
},
"output_sizes": {
"instagram": {"width": 1080, "height": 1080},
"x": {"width": 1200, "height": 675}
}
}
```
**Validación:**
- Requiere `html_template` o `template_file`
### PUT /api/templates/{template_id}
Actualiza una plantilla.
### DELETE /api/templates/{template_id}
Elimina una plantilla.
### POST /api/templates/preview
Genera preview de una plantilla con variables.
**Body:**
```json
{
"template_id": 1,
"variables": {
"title": "Tip del día",
"content": "Automatiza tus procesos con IA",
"emoji": "💡"
},
"output_size": {"width": 1080, "height": 1080}
}
```
O con HTML directo:
```json
{
"html_template": "<div>{{title}}</div>",
"variables": {
"title": "Mi título"
}
}
```
**Respuesta:**
```json
{
"rendered_html": "<div>Mi título</div>",
"output_size": {"width": 1080, "height": 1080},
"variables_used": ["title"]
}
```
### GET /api/templates/categories/list
Lista categorías disponibles.
### GET /api/templates/types/list
Lista tipos de plantilla disponibles.
## Estructura HTML
### Variables
Las variables se definen con doble llave: `{{variable}}`
```html
<div class="card">
<span class="emoji">{{emoji}}</span>
<h1>{{title}}</h1>
<p>{{content}}</p>
</div>
```
### Ejemplo Completo
```html
<!DOCTYPE html>
<html>
<head>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
width: 1080px;
height: 1080px;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
font-family: 'Inter', sans-serif;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
.card {
width: 900px;
padding: 60px;
background: rgba(255,255,255,0.05);
border-radius: 24px;
border: 1px solid rgba(212, 165, 116, 0.3);
}
.emoji {
font-size: 64px;
display: block;
margin-bottom: 24px;
}
h1 {
color: #d4a574;
font-size: 36px;
margin-bottom: 24px;
}
p {
font-size: 24px;
line-height: 1.6;
color: #e0e0e0;
}
.footer {
margin-top: 40px;
color: #888;
font-size: 18px;
}
</style>
</head>
<body>
<div class="card">
<span class="emoji">{{emoji}}</span>
<h1>{{title}}</h1>
<p>{{content}}</p>
<div class="footer">@{{username}} • Consultoría AS</div>
</div>
</body>
</html>
```
## Categorías
| Categoría | Uso |
|-----------|-----|
| `tip` | Tips tecnológicos |
| `producto` | Fichas de producto |
| `servicio` | Promoción de servicios |
| `promocion` | Ofertas y descuentos |
| `frase` | Frases motivacionales |
| `dato` | Datos curiosos |
| `anuncio` | Anuncios generales |
## Tipos de Plantilla
| Tipo | Descripción |
|------|-------------|
| `tip_card` | Tarjeta de tip con emoji |
| `product_card` | Ficha de producto con imagen |
| `quote` | Frase con autor |
| `promo` | Promoción con precio |
| `announcement` | Anuncio destacado |
| `stats` | Estadísticas/números |
| `comparison` | Antes/después o A vs B |
## Tamaños por Plataforma
| Plataforma | Ancho | Alto | Ratio |
|------------|-------|------|-------|
| Instagram Post | 1080 | 1080 | 1:1 |
| Instagram Story | 1080 | 1920 | 9:16 |
| X (Twitter) | 1200 | 675 | 16:9 |
| Facebook | 1200 | 630 | 1.91:1 |
| LinkedIn | 1200 | 627 | 1.91:1 |
| Threads | 1080 | 1080 | 1:1 |
## Ejemplo de Uso
```python
from app.models.image_template import ImageTemplate
from app.core.database import SessionLocal
db = SessionLocal()
# Crear plantilla
template = ImageTemplate(
name="Tip Card Dark",
category="tip",
template_type="tip_card",
html_template="""
<div style="...">
<h1>{{title}}</h1>
<p>{{content}}</p>
</div>
""",
variables=["title", "content"],
design_config={
"width": 1080,
"height": 1080,
"background_color": "#1a1a2e"
}
)
db.add(template)
db.commit()
# Renderizar
html = template.html_template
html = html.replace("{{title}}", "Mi Título")
html = html.replace("{{content}}", "Mi contenido")
```
## Generación de Imágenes
Para convertir HTML a imagen se recomienda:
### Playwright (recomendado)
```python
from playwright.async_api import async_playwright
async def html_to_image(html: str, width: int, height: int) -> bytes:
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page(viewport={"width": width, "height": height})
await page.set_content(html)
screenshot = await page.screenshot(type="png")
await browser.close()
return screenshot
```
### WeasyPrint (alternativa)
```python
from weasyprint import HTML
def html_to_pdf(html: str) -> bytes:
return HTML(string=html).write_pdf()
```
## Mejores Prácticas
1. **Fuentes web:** Usa Google Fonts o incluye fuentes inline
2. **Colores consistentes:** Define palette en design_config
3. **Responsive:** Usa unidades relativas cuando sea posible
4. **Contraste:** Asegura legibilidad texto/fondo
5. **Logo:** Incluye branding en todas las plantillas
6. **Variables descriptivas:** `{{product_name}}` mejor que `{{name}}`
7. **Fallbacks:** Define valores por defecto para variables opcionales
## Integración con Posts
```python
# Al crear un post con imagen generada
post = Post(
content="Tip del día...",
image_template_id=template.id, # Referencia a la plantilla usada
image_url="/uploads/generated/tip_123.png"
)
```

369
docs/ODOO_INTEGRATION.md Normal file
View File

@@ -0,0 +1,369 @@
# Integración con Odoo
Sincronización bidireccional con Odoo ERP para productos, servicios y leads.
## Descripción General
La integración permite:
- **Importar** productos y servicios desde Odoo
- **Exportar** leads generados en redes sociales al CRM de Odoo
- **Consultar** resumen de ventas
## Configuración
### Variables de Entorno
```bash
# .env
ODOO_URL=https://tuempresa.odoo.com
ODOO_DB=nombre_base_datos
ODOO_USERNAME=usuario@empresa.com
ODOO_PASSWORD=api_key_o_password
ODOO_SYNC_ENABLED=true # false para deshabilitar
```
### Obtener API Key en Odoo
1. Ir a **Ajustes > Usuarios**
2. Seleccionar tu usuario
3. Pestaña **Claves de API**
4. Crear nueva clave
## Modelos de Datos
### Lead
Leads generados desde interacciones en redes sociales.
```python
Lead:
id: int
interaction_id: int (FK, opcional)
platform: str # x, threads, instagram, facebook, manual
# Contacto
name: str
email: str
phone: str
company: str
# Social
username: str
profile_url: str
# Interés
interest: str
source_content: str
notes: str
products_interested: [int] # IDs de productos
services_interested: [int] # IDs de servicios
# Estado
status: str # new, contacted, qualified, proposal, won, lost
priority: str # low, medium, high, urgent
# Odoo
odoo_lead_id: int
synced_to_odoo: bool
odoo_synced_at: datetime
```
### OdooSyncLog
Registro de operaciones de sincronización.
```python
OdooSyncLog:
id: int
sync_type: str # products, services, leads, sales
direction: str # import, export
status: str # started, completed, failed, partial
records_processed: int
records_created: int
records_updated: int
records_failed: int
error_message: str
error_details: JSON
started_at: datetime
completed_at: datetime
```
### Campos Odoo en Product/Service
```python
# En Product
odoo_product_id: int (unique)
odoo_last_synced: datetime
# En Service
odoo_service_id: int (unique)
odoo_last_synced: datetime
```
## API Endpoints
### Odoo Status
#### GET /api/odoo/status
Verifica conexión con Odoo.
**Respuesta exitosa:**
```json
{
"connected": true,
"version": "17.0",
"uid": 2
}
```
**Sin conexión:**
```json
{
"connected": false,
"error": "Authentication failed",
"configured": true
}
```
### Sincronización
#### POST /api/odoo/sync/products
Sincroniza productos desde Odoo.
**Parámetros:**
- `limit` (int, default=100): Máximo de productos
**Respuesta:**
```json
{
"message": "Products synced successfully",
"success": true,
"processed": 50,
"created": 10,
"updated": 40,
"failed": 0
}
```
#### POST /api/odoo/sync/services
Sincroniza servicios desde Odoo.
#### POST /api/odoo/sync/leads
Exporta leads sin sincronizar a Odoo CRM.
**Respuesta:**
```json
{
"message": "Leads exported successfully",
"success": true,
"processed": 5,
"created": 5,
"failed": 0
}
```
#### GET /api/odoo/sync/logs
Obtiene historial de sincronizaciones.
**Parámetros:**
- `limit` (int, default=20)
#### GET /api/odoo/sales
Obtiene resumen de ventas desde Odoo.
**Parámetros:**
- `days` (int, default=30)
**Respuesta:**
```json
{
"success": true,
"period_days": 30,
"total_orders": 15,
"total_revenue": 125000.00,
"avg_order_value": 8333.33,
"orders": [...]
}
```
### Leads API
#### GET /api/leads/
Lista leads con filtros.
**Parámetros:**
- `status`: new, contacted, qualified, proposal, won, lost
- `priority`: low, medium, high, urgent
- `platform`: x, threads, instagram, facebook, manual
- `synced`: true/false (sincronizado a Odoo)
- `limit`, `offset`: Paginación
#### GET /api/leads/{lead_id}
Obtiene un lead específico.
#### POST /api/leads/
Crea lead manualmente.
**Body:**
```json
{
"name": "Juan Pérez",
"email": "juan@empresa.com",
"phone": "+52 664 123 4567",
"company": "Empresa SA",
"platform": "manual",
"interest": "Interesado en automatización",
"priority": "high"
}
```
#### POST /api/leads/from-interaction/{interaction_id}
Convierte una interacción en lead.
**Parámetros:**
- `interest` (str): Descripción del interés
- `priority` (str): Prioridad
- `notes` (str): Notas adicionales
#### PUT /api/leads/{lead_id}
Actualiza un lead.
#### DELETE /api/leads/{lead_id}
Elimina un lead.
#### POST /api/leads/{lead_id}/sync-odoo
Sincroniza un lead específico a Odoo.
**Respuesta:**
```json
{
"message": "Lead synced to Odoo successfully",
"odoo_lead_id": 1234
}
```
#### GET /api/leads/stats/summary
Obtiene estadísticas de leads.
**Respuesta:**
```json
{
"total": 50,
"by_status": {
"new": 20,
"contacted": 15,
"qualified": 10,
"won": 5
},
"by_platform": {
"x": 25,
"threads": 15,
"manual": 10
},
"by_priority": {
"high": 10,
"medium": 30,
"low": 10
},
"unsynced_to_odoo": 8
}
```
## Tareas Programadas
### sync_products_from_odoo
- **Frecuencia:** Diario a las 6:00 AM
- **Función:** Importa/actualiza productos desde Odoo
- **Límite:** 200 productos por ejecución
### sync_services_from_odoo
- **Frecuencia:** Diario a las 6:05 AM
- **Función:** Importa/actualiza servicios desde Odoo
- **Límite:** 100 servicios por ejecución
### export_leads_to_odoo
- **Frecuencia:** Cada hora (minuto 30)
- **Función:** Exporta leads no sincronizados al CRM
## Dashboard de Leads
Accede en `/dashboard/leads`.
### Características:
- Cards de estadísticas (total, nuevos, contactados, etc.)
- Filtros por estado, prioridad y plataforma
- Lista paginada de leads
- Modal para crear/editar leads
- Botones de sincronización individual y masiva
### Estados de Lead
| Estado | Descripción |
|--------|-------------|
| `new` | Lead nuevo sin contactar |
| `contacted` | Se ha hecho contacto inicial |
| `qualified` | Lead calificado con potencial |
| `proposal` | Se envió propuesta |
| `won` | Lead convertido a cliente |
| `lost` | Lead perdido |
### Prioridades
| Prioridad | Color |
|-----------|-------|
| `urgent` | Rojo |
| `high` | Naranja |
| `medium` | Azul |
| `low` | Gris |
## Ejemplo de Uso
```python
from app.services.odoo_service import odoo_service
# Verificar conexión
status = await odoo_service.test_connection()
if status["connected"]:
print(f"Conectado a Odoo {status['version']}")
# Sincronizar productos
result = await odoo_service.sync_products(limit=50)
print(f"Productos: {result['created']} nuevos, {result['updated']} actualizados")
# Exportar leads
result = await odoo_service.export_leads_to_odoo()
print(f"Leads exportados: {result['created']}")
# Obtener ventas
sales = await odoo_service.get_sales_summary(days=30)
print(f"Ventas: ${sales['total_revenue']:,.2f}")
```
## Mapeo de Campos
### Producto Odoo → Local
| Odoo | Local |
|------|-------|
| id | odoo_product_id |
| name | name |
| description_sale | description |
| list_price | price |
| categ_id | category |
| qty_available | stock |
### Lead Local → Odoo
| Local | Odoo |
|-------|------|
| interest | name |
| name | contact_name |
| email | email_from |
| phone | phone |
| company | partner_name |
| (generated) | description |
| priority | priority (0-2) |
## Notas Técnicas
- La conexión usa XML-RPC (protocolo estándar de Odoo)
- Cada sincronización crea un registro en `odoo_sync_logs`
- Los productos/servicios se identifican por `odoo_product_id`/`odoo_service_id`
- Si un producto local ya existe (mismo ID de Odoo), se actualiza
- Los leads se exportan como tipo "lead" (no "opportunity")

334
docs/THREAD_SERIES.md Normal file
View File

@@ -0,0 +1,334 @@
# Thread Series
Sistema para crear y publicar hilos de múltiples posts conectados.
## Descripción
Los Thread Series permiten:
- Crear contenido largo dividido en posts conectados
- Generar hilos con IA
- Programar publicación escalonada
- Mantener cadena de respuestas (reply chain)
## Modelos de Datos
### ThreadSeries
```python
ThreadSeries:
id: int
name: str
description: str
topic: str
platform: str # x, threads
# Configuración de programación
schedule_type: str # sequential, timed
interval_minutes: int # Tiempo entre posts (default 5)
start_time: datetime
# Estado
total_posts: int
posts_published: int
status: str # draft, scheduled, publishing, completed, paused, cancelled
# Reply chain
first_platform_post_id: str # ID del primer post (para replies)
# IA
ai_generated: bool
generation_prompt: str
hashtags: JSON # Hashtags comunes
```
### ThreadPost
```python
ThreadPost:
id: int
series_id: int (FK -> thread_series)
sequence_number: int # 1, 2, 3...
content: str
image_url: str
post_id: int (FK -> posts)
# Para reply chain
platform_post_id: str
reply_to_platform_id: str
scheduled_at: datetime
status: str # pending, scheduled, published, failed
error_message: str
published_at: datetime
```
## API Endpoints
### GET /api/threads/
Lista todas las series.
**Parámetros:**
- `status`: draft, scheduled, publishing, completed
- `platform`: x, threads
- `limit` (int, default=20)
### GET /api/threads/{series_id}
Obtiene una serie con todos sus posts.
**Respuesta:**
```json
{
"id": 1,
"name": "Hilo sobre IA",
"topic": "Inteligencia Artificial",
"platform": "x",
"status": "scheduled",
"total_posts": 5,
"posts_published": 0,
"start_time": "2025-02-01T10:00:00",
"interval_minutes": 5,
"posts": [
{
"id": 1,
"sequence_number": 1,
"content": "🧵 Hilo: Todo sobre IA...",
"status": "scheduled",
"scheduled_at": "2025-02-01T10:00:00"
},
{
"id": 2,
"sequence_number": 2,
"content": "1/ La IA está transformando...",
"status": "scheduled",
"scheduled_at": "2025-02-01T10:05:00"
}
]
}
```
### POST /api/threads/
Crea una serie manualmente.
**Body:**
```json
{
"name": "Tips de productividad",
"platform": "x",
"posts": [
{"content": "🧵 Hilo: 5 tips para ser más productivo"},
{"content": "1/ Usa la técnica Pomodoro..."},
{"content": "2/ Elimina distracciones..."},
{"content": "3/ Prioriza con Eisenhower..."},
{"content": "4/ Automatiza tareas repetitivas..."},
{"content": "5/ Revisa tu progreso diario..."}
],
"description": "Tips de productividad para profesionales",
"schedule_type": "sequential",
"interval_minutes": 3,
"hashtags": ["#Productividad", "#Tips"]
}
```
**Validaciones:**
- Mínimo 2 posts, máximo 20
- Platform requerido
### POST /api/threads/generate
Genera un hilo con IA.
**Body:**
```json
{
"topic": "Cómo empezar con inteligencia artificial",
"platform": "x",
"num_posts": 5,
"style": "educational",
"name": "Intro a IA" // Opcional: si se incluye, guarda la serie
}
```
**Estilos disponibles:**
- `educational`: Contenido informativo y didáctico
- `storytelling`: Formato narrativo
- `tips`: Lista de consejos prácticos
**Respuesta (sin name):**
```json
{
"message": "Thread generated (not saved)",
"generated_posts": [
{"sequence": 1, "content": "🧵 Te explico qué es la IA..."},
{"sequence": 2, "content": "1/ La IA es..."}
],
"count": 5
}
```
**Respuesta (con name):**
```json
{
"message": "Thread generated and saved",
"series": {...},
"generated_posts": [...]
}
```
### POST /api/threads/{series_id}/schedule
Programa una serie para publicación.
**Body (opcional):**
```json
{
"start_time": "2025-02-01T10:00:00"
}
```
Si no se especifica, inicia en 5 minutos.
**Proceso:**
1. Crea posts reales para cada ThreadPost
2. Programa cada uno con el intervalo configurado
3. Cambia status a "scheduled"
**Respuesta:**
```json
{
"message": "Series scheduled successfully",
"success": true,
"series_id": 1,
"start_time": "2025-02-01T10:00:00",
"posts_scheduled": 5
}
```
### POST /api/threads/{series_id}/publish-next
Publica manualmente el siguiente post de la serie.
### POST /api/threads/{series_id}/cancel
Cancela una serie y sus posts programados.
## Tareas Programadas
### check_thread_schedules
- **Frecuencia:** Cada minuto
- **Función:**
- Busca ThreadPosts programados para ahora
- Encola tarea de publicación
- Actualiza estado
### update_thread_post_status
- **Trigger:** Después de publicar un post
- **Función:**
- Actualiza estado del ThreadPost
- Guarda platform_post_id (para reply chain)
- Actualiza progreso de la serie
- Marca serie como completed si todos publicados
## Tipos de Programación
| Tipo | Descripción |
|------|-------------|
| `sequential` | Posts uno tras otro con intervalo fijo |
| `timed` | Posts en horarios específicos (próximamente) |
## Reply Chain
Para que los posts aparezcan como respuestas:
1. Se publica el primer post
2. Se guarda su `platform_post_id`
3. Los siguientes posts se publican como respuesta al anterior
4. Cada uno guarda su `reply_to_platform_id`
```
Post 1 (original)
└── Post 2 (reply to 1)
└── Post 3 (reply to 2)
└── Post 4 (reply to 3)
```
## Ejemplo de Uso
```python
from app.services.thread_service import thread_service
# Crear serie manual
series = await thread_service.create_series(
name="Tips de Python",
platform="x",
posts_content=[
{"content": "🧵 Hilo: 5 tips de Python que debes conocer"},
{"content": "1/ List comprehensions..."},
{"content": "2/ F-strings..."},
{"content": "3/ Context managers..."},
{"content": "4/ Generators..."},
{"content": "5/ Decorators..."}
],
interval_minutes=3
)
# Generar con IA
result = await thread_service.generate_thread_with_ai(
topic="Beneficios de la automatización",
platform="threads",
num_posts=5,
style="storytelling"
)
# Programar
await thread_service.schedule_series(
series_id=series.id,
start_time=datetime(2025, 2, 1, 10, 0)
)
# Ver estado
series = await thread_service.get_series(series.id)
print(f"Publicados: {series['posts_published']}/{series['total_posts']}")
```
## Flujo Completo
```
1. Crear Serie
- Manual: Proporcionar posts
- IA: Generar con prompt
2. Revisar y Editar
- Verificar contenido
- Ajustar hashtags
3. Programar
- Establecer start_time
- Crear posts reales
4. Publicación Automática
- Celery Beat cada minuto
- Publica posts programados
- Mantiene reply chain
5. Completado
- Todos los posts publicados
- Status: completed
```
## Mejores Prácticas
1. **Primer post atractivo:** El 1/5 o 🧵 debe captar atención
2. **Numeración clara:** "1/", "2/" o "1.", "2."
3. **Intervalos cortos:** 3-5 minutos mantienen engagement
4. **Último post con CTA:** Llamado a la acción al final
5. **Hashtags solo al final:** No saturar cada post
6. **Máximo 10-15 posts:** Hilos muy largos pierden audiencia
## Plataformas Soportadas
| Plataforma | Reply Chain | Notas |
|------------|-------------|-------|
| X (Twitter) | ✅ | Ideal para threads |
| Threads | ✅ | Buen soporte |
| Instagram | ❌ | No soporta threads |
| Facebook | ❌ | No soporta threads |