- 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>
268 lines
6.4 KiB
Markdown
268 lines
6.4 KiB
Markdown
# 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 |
|