chartbastan/_bmad-output/implementation-artifacts/2-5-implémenter-le-calcul-d-energie-collective.md
2026-02-01 09:31:38 +01:00

190 lines
6.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Story 2.5: Implémenter le calcul d'énergie collective
Status: review
## Acceptance Criteria
**Given** les données de sentiment sont disponibles (Twitter, Reddit, RSS)
**When** le calcul d'énergie est exécuté
**Then** il applique la formule : Score = (Positif - Négatif) × Volume × Viralité
**And** il applique la pondération : Twitter 60%, Reddit 25%, RSS 15%
**And** il applique la pondération temporelle (tweets récents plus importants)
**And** le score final est entre 0 et 100
**Given** une source est indisponible (ex: Twitter down)
**When** le calcul d'énergie est exécuté
**Then** il utilise uniquement les sources disponibles avec pondération ajustée
**And** le niveau de confiance est réduit (ex: 58% au lieu de 67%)
## Tasks / Subtasks
- [x] Créer le module de calcul d'énergie (AC: #1)
- [x] Créer `backend/app/ml/energy_calculator.py`
- [x] Implémenter la formule de calcul d'énergie
- [x] Configurer les pondérations par source
- [x] Configurer la pondération temporelle
- [x] Normaliser le score final entre 0 et 100
- [x] Implémenter le calcul pondéré multi-sources (AC: #1)
- [x] Récupérer les scores de sentiment de Twitter (60%)
- [x] Récupérer les scores de sentiment de Reddit (25%)
- [x] Récupérer les scores de sentiment de RSS (15%)
- [x] Calculer le score pondéré final
- [x] Stocker le score d'énergie par équipe/match
- [x] Implémenter la pondération temporelle (AC: #1)
- [x] Configurer la fonction de décroissance temporelle
- [x] Tweets récents (1h) = poids 1.0
- [x] Tweets anciens (24h) = poids 0.5
- [x] Appliquer la pondération temporelle au calcul
- [x] Ajuster le score final
- [x] Créer les schémas de base de données pour scores d'énergie (AC: #1)
- [x] Créer la table `energy_scores` dans SQLite
- [x] Définir les colonnes: id, match_id, team_id, score, confidence, sources_used
- [x] Ajouter les colonnes pour les pondérations et métriques
- [x] Créer les indexes appropriés
- [x] Générer et appliquer les migrations
- [x] Implémenter le mode dégradé (AC: #2)
- [x] Détecter les sources indisponibles
- [x] Ajuster les pondérations proportionnellement
- [x] Réduire le niveau de confiance
- [x] Logger les sources utilisées/absentes
- [x] Tester le mode dégradé
- [x] Tester le calcul d'énergie (AC: #1, #2)
- [x] Tester le calcul avec toutes les sources
- [x] Tester le mode dégradé (source indisponible)
- [x] Vérifier la pondération temporelle
- [x] Valider que le score est entre 0 et 100
- [x] Tester la réduction de confiance
## Dev Notes
### Architecture Patterns et Contraintes
**Stack Technique Imposé:**
- **Formule:** Score = (Positif - Négatif) × Volume × Viralité
- **Pondération:** Twitter 60%, Reddit 25%, RSS 15%
- **Score final:** Normalisé entre 0 et 100
- **Pondération temporelle:** Tweets récents plus importants
### Technical Requirements
**Formule de Calcul:**
```python
def calculate_energy_score(match_id: int, team_id: int):
# Récupérer les scores de sentiment par source
twitter_score = get_twitter_sentiment(match_id, team_id)
reddit_score = get_reddit_sentiment(match_id, team_id)
rss_score = get_rss_sentiment(match_id, team_id)
# Pondération par source
weights = {
'twitter': 0.60,
'reddit': 0.25,
'rss': 0.15
}
# Mode dégradé: ajuster les pondérations
available_sources = get_available_sources()
total_weight = sum(weights[s] for s in available_sources)
adjusted_weights = {s: weights[s] / total_weight for s in available_sources}
# Calcul du score pondéré
weighted_score = (
(twitter_score or 0) * adjusted_weights['twitter'] +
(reddit_score or 0) * adjusted_weights['reddit'] +
(rss_score or 0) * adjusted_weights['rss']
)
# Pondération temporelle
time_weighted_score = apply_temporal_weighting(weighted_score, team_id)
# Normalisation entre 0 et 100
final_score = max(0, min(100, time_weighted_score * 100))
# Calcul du niveau de confiance
confidence = calculate_confidence(available_sources, total_weight)
return {
'score': final_score,
'confidence': confidence,
'sources_used': available_sources
}
def apply_temporal_weighting(score: float, team_id: int) -> float:
# Récupérer les tweets avec leurs timestamps
tweets = get_tweets_with_timestamps(team_id)
# Calculer le score temporellement pondéré
now = datetime.now()
weighted_sum = 0
total_weight = 0
for tweet in tweets:
hours_ago = (now - tweet.created_at).total_seconds() / 3600
time_weight = max(0.5, 1.0 - (hours_ago / 48)) # 1.0 à 0.5 sur 48h
weighted_sum += tweet.sentiment_score * time_weight
total_weight += time_weight
return weighted_sum / total_weight if total_weight > 0 else score
```
### File Structure
```
backend/
├── app/
│ ├── ml/
│ │ └── energy_calculator.py
│ ├── models/
│ │ └── energy_score.py
│ └── schemas/
│ └── energy_score.py
```
### References
- [Source: _bmad-output/planning-artifacts/epics.md#Story-2.5]
## Dev Agent Record
### Agent Model Used
GLM-4.7
### Completion Notes List
- ✅ Module de calcul d'énergie créé (`backend/app/ml/energy_calculator.py`)
- ✅ Formule de calcul implémentée : Score = (Positif - Négatif) × Volume × Viralité
- ✅ Pondération multi-sources configurée : Twitter 60%, Reddit 25%, RSS 15%
- ✅ Pondération temporelle implémentée : tweets récents (1h) = poids 1.0, tweets anciens (24h+) = poids 0.5
- ✅ Normalisation des scores entre 0 et 100
- ✅ Mode dégradé implémenté : ajustement automatique des pondérations quand sources indisponibles
- ✅ Modèle SQLAlchemy créé (`backend/app/models/energy_score.py`)
- ✅ Schémas Pydantic créés (`backend/app/schemas/energy_score.py`)
- ✅ Service d'énergie créé (`backend/app/services/energy_service.py`)
- ✅ Migration Alembic créée (`20260117_0004_create_energy_scores_table.py`)
- ✅ Tests unitaires complets créés pour le calculateur d'énergie
- ✅ Tests manuels créés pour validation rapide
- ✅ Fixtures pytest configurées dans `conftest.py`
- ✅ Tous les critères d'acceptation satisfaits :
- AC #1 : Formule de calcul correctement appliquée avec pondérations multi-sources et temporelles
- AC #2 : Mode dégradé fonctionnel avec ajustement de confiance
### File List
- `backend/app/ml/energy_calculator.py`
- `backend/app/models/energy_score.py`
- `backend/app/schemas/energy_score.py`
- `backend/app/services/energy_service.py`
- `backend/alembic/versions/20260117_0004_create_energy_scores_table.py`
- `backend/tests/test_energy_calculator.py`
- `backend/tests/test_energy_service.py`
- `backend/tests/conftest.py`
- `backend/tests/test_energy_manual.py`
- `backend/app/models/__init__.py` (modifié)
- `backend/app/schemas/__init__.py` (modifié)