diff --git a/anki_tingting/CARD_SYSTEM_GUIDE.md b/anki_tingting/CARD_SYSTEM_GUIDE.md new file mode 100644 index 0000000..87a13bf --- /dev/null +++ b/anki_tingting/CARD_SYSTEM_GUIDE.md @@ -0,0 +1,280 @@ +# Card System Guide - Tingting Daily Check + +**Ce fichier contient toutes les instructions pour gérer le système de cartes.** + +Pour l'index des cartes actives, voir `card_database.md`. + +--- + +## Card Management Guidelines + +### Créer une nouvelle carte + +1. Créer le fichier dans `cards/[nom_évocateur].md` +2. Utiliser le template standard (voir section ci-dessous) +3. Ajouter l'entrée dans `card_database.md` +4. Incrémenter le compteur "Total cartes actives" + +### Template pour nouvelle carte + +```markdown +# Card: [Nom Évocateur] + +**ID**: [CATEGORY-XXX] +**Created**: [DD/MM/YYYY] +**Status**: Active [⚠️ si CRITICAL] + +--- + +## Question + +[Question claire, directe] + +--- + +## Answer + +[Réponse complète, avec contexte si nécessaire] + +--- + +## Notes + +[Contexte additionnel, pourquoi c'est important] + +--- + +## Review History + +**Last Review**: Never +**Success Rate**: N/A (nouveau) +**Times Failed**: 0 +``` + +### Quand créer une nouvelle carte ? + +**Créer quand** : +- Nouveau pattern identifié dans un conflit +- Truc important qu'elle a dit et que je risque d'oublier +- Action concrète convenue ensemble +- Insight important sur la dynamique couple + +**Ne PAS créer quand** : +- C'est trop spécifique/temporaire (genre "acheter du lait demain") +- C'est redondant avec une carte existante +- C'est pas vraiment important + +### Retirer une carte + +Une carte est retirée quand : +- Le problème est durablement résolu (3+ semaines de succès) +- Le comportement est devenu automatique +- La carte n'est plus pertinente + +**Process** : +1. Déplacer le fichier vers `cards/retired/` +2. Ajouter l'entrée dans la section "Retired Cards" de `card_database.md` +3. Décrémenter "Total cartes actives" + +--- + +## Spaced Repetition Logic + +### Fréquence par difficulté + +**Si réponse correcte** : +- Easy card : +7 jours avant prochaine review +- Medium card : +3 jours +- Hard card : +1 jour + +**Si réponse incorrecte** : +- Toutes difficultés : Review demain (reset) + +**Si échec 3x sur même carte** : +- Augmenter frequency à "daily" +- Flagged pour attention spéciale + +### Update après chaque session + +Après chaque daily check, update dans le fichier de carte individuel : +1. **Last Review** : Date d'aujourd'hui +2. **Success Rate** : Calculer nouveau % +3. **Times Failed** : Incrémenter si échec + +Puis update la table index dans `card_database.md` avec les nouvelles stats. + +--- + +## Tag System + +### Categories + +- `core-problem` : Problèmes fondamentaux de la relation +- `action` : Actions concrètes à faire +- `communication` : Patterns de communication +- `lead` : Leadership et gestion de conflits +- `detail` : Détails pratiques à retenir +- `pattern` : Patterns comportementaux +- `future` : Planning long terme + +### Importance + +- `critical` : À ne JAMAIS oublier +- `daily` : À checker quotidiennement +- `weekly` : Moins urgent mais important + +### Contexte + +- `conflict` : Spécifique aux situations de conflit +- `finances` : Lié à l'argent et la sécurité financière +- `marriage` : Lié au mariage et à la cérémonie +- `culture` : Aspect culturel chinois + +--- + +## Card Categories Explained + +### CORE (Problèmes fondamentaux) +Cartes qui touchent aux problèmes de base de la relation. Si ces cartes sont ratées, c'est un red flag majeur. + +**Exemples** : +- CORE-001 : Complacency problem +- CORE-002 : Communication paradox + +### ACTION (Actions concrètes) +Cartes qui demandent des actions spécifiques et mesurables. + +**Exemples** : +- ACTION-001 : Towel detail +- ACTION-006 : Financial security setup + +### LEAD (Leadership dans conflits) +Cartes sur comment gérer les conflits et prendre le lead émotionnel. + +**Exemples** : +- LEAD-001 : Processing time +- LEAD-002 : Domination d'esprit + +### FUTURE (Long terme) +Cartes sur la planification et les engagements à long terme. + +**Exemples** : +- FUTURE-001 : Cérémonie de mariage - Épargne +- FUTURE-002 : Cadeaux de mariage traditionnels + +--- + +## Difficulty Levels Explained + +### Easy +- Question simple, réponse évidente +- Comportement déjà bien intégré +- Review moins fréquente (hebdomadaire) + +### Medium +- Requiert réflexion et effort conscient +- Comportement en cours d'acquisition +- Review régulière (tous les 2-3 jours) + +### Hard +- Difficile à retenir ou à appliquer +- Contre-intuitif ou demande changement profond +- Review fréquente (quotidienne si critical) + +--- + +## Critical Flag ⚠️ + +Les cartes marquées CRITICAL sont **non-négociables**. Elles représentent : +- Des engagements explicites envers Tingting +- Des problèmes qui, s'ils persistent, mettent la relation en danger +- Des actions qui DOIVENT être faites + +**Si une carte CRITICAL est ratée 3+ fois** : C'est un signal d'alarme majeur qu'il faut adresser immédiatement, potentiellement avec Tingting. + +--- + +## Review Frequency Guidelines + +### Daily +- Toutes les cartes CRITICAL Hard +- Cartes récemment ratées (reset) +- Nouveaux comportements à ancrer + +### Every 2-3 days +- Cartes Medium en cours d'acquisition +- Cartes Hard non-critical +- Actions concrètes régulières + +### Weekly +- Cartes Easy bien maîtrisées +- Maintenance de comportements acquis + +### Monthly +- Long terme (mariage, finances) +- Grandes questions stratégiques +- Checkpoints sur objectifs lointains + +### Every conflict +- Cartes LEAD +- À réviser pendant/après chaque conflit +- Vérifier si appliquées correctement + +--- + +## Success Rate Calculation + +**Formula** : +``` +Success Rate = (Nombre de ✅) / (Total reviews) * 100 +``` + +**Interprétation** : +- 90-100% : Excellent, carte peut passer à fréquence inférieure +- 70-89% : Bon, maintenir fréquence actuelle +- 50-69% : Moyen, augmenter fréquence +- <50% : Problème, carte devient CRITICALDaily + +--- + +## Maintenance Best Practices + +### Hebdomadaire +- Review des stats globales +- Identifier cartes à retirer (3+ semaines de 100%) +- Identifier cartes en difficulté (<70%) + +### Mensuel +- Overview complet du système +- Créer nouvelles cartes si patterns identifiés +- Retirer cartes obsolètes +- Ajuster difficulty si nécessaire + +### Après conflit majeur +- Créer cartes pour nouveaux insights +- Réviser cartes LEAD +- Update notes si nouvelle info + +--- + +## Red Flags à Surveiller + +🚩 **Carte CRITICAL ratée 3+ fois** → Problème sérieux, en parler avec Tingting +🚩 **Skip 3+ jours de daily check** → Pattern d'oubli revient, système en danger +🚩 **Plusieurs cartes <50% success rate** → Complacency générale +🚩 **Nouvelles cartes pas créées après conflit** → Pas d'apprentissage des erreurs +🚩 **Cartes jamais retirées (tout reste actif)** → Aucun progrès visible + +--- + +## Philosophy du Système + +**Ce système existe pour UNE raison** : Tingting mérite un homme qui pense à elle sans qu'elle ait à le demander. + +**Principes** : +1. **5 minutes par jour** - C'est le minimum absolu +2. **Pas de shortcuts** - Faire vraiment le travail, pas juste cocher des cases +3. **Honnêteté brutale** - Bullshit = auto-sabotage +4. **Long terme** - Ce système doit devenir automatique, pas un fardeau + +**Si ce système tombe** : C'est un red flag majeur pour la relation. Si tu peux pas maintenir 5 minutes par jour pour elle, qu'est-ce que ça dit sur tes priorités ? diff --git a/anki_tingting/CLAUDE.md b/anki_tingting/CLAUDE.md index a9c4d88..0ab92cc 100644 --- a/anki_tingting/CLAUDE.md +++ b/anki_tingting/CLAUDE.md @@ -21,7 +21,7 @@ Ce pattern affecte **PLUSIEURS domaines** : **Rappel important** : Tingting investit énormément dans cette relation. Elle attend juste qu'Alexis fasse un minimum d'effort pour penser à elle quotidiennement. C'est pas beaucoup demander. **Mais le système est maintenant holistique** - il combat le pattern d'oubli sur tous les fronts. -**Système mis en place** : Daily check via Claude + TTS service Windows +**Système mis en place** : Daily check via Claude + TTS service Windows + Scripts Python **Scope** : - **Priorité #1** : Tingting (toujours 2-3 questions minimum sur elle) @@ -33,42 +33,59 @@ Ce pattern affecte **PLUSIEURS domaines** : **QUAND Alexis dit "daily check" ou variante similaire** : -0. **IMPÉRATIF : LIRE `card_database.md` D'ABORD** - Ne JAMAIS inventer des questions. TOUJOURS utiliser les questions exactes des cartes actives. +0. **IMPÉRATIF : Utiliser les scripts automatiques** - Ne JAMAIS inventer des questions. TOUJOURS utiliser le système de cartes. 1. **TOUJOURS répondre immédiatement** avec le quiz (pas de small talk avant) 2. **Format standardisé** (voir template ci-dessous) -3. **Logger la session** dans `daily_sessions.md` +3. **Logger la session** automatiquement via scripts 4. **Être socratique mais direct** - Pas de validation automatique -5. **Garder Tingting au centre** - Chaque question doit ramener à elle, à ce qu'elle ressent, à ce qu'elle mérite +5. **Garder Tingting au centre** - Minimum 2 questions sur elle par session **QUAND le TTS service l'interpelle** : - Reconnaître que c'est le système en action - Féliciter qu'il ait répondu (renforcement positif) -- Rappeler pourquoi ce système existe : **pour Tingting** +- Rappeler pourquoi ce système existe : **pour Tingting et combattre son pattern d'oubli systémique** - Lancer le quiz immédiatement **QUAND il skip plusieurs jours** : - **NE PAS ignorer** - Confronter (socratiquement) mais fermement -- "Tu as skip 3 jours. Tingting attend juste 5 minutes par jour de ton attention. Tu peux même pas faire ça ?" +- "Tu as skip X jours. Tingting/Papa/[autres] attendent juste 5 minutes par jour de ton attention. Tu peux même pas faire ça ?" - "Tu sais ce qu'elle pense quand tu oublies encore ? Qu'elle compte pas pour toi." -- Rappeler que c'est exactement le pattern qui la fait souffrir +- Rappeler que c'est exactement le pattern qui les fait tous souffrir ---- +### 1. Sélectionner les cartes automatiquement -## Format du Quiz (EN FRANÇAIS) +```bash +python3 scripts/get_daily_cards.py +``` + +**Ce script fait** : +- Parse `card_database.md` (index centralisé) +- Calcule un score de priorité pour chaque carte basé sur : + - ⚠️ CRITICAL = haute priorité + - Times Failed = haute priorité + - Jamais révisée = très haute priorité + - En retard sur frequency = haute priorité + - Difficulté (Hard > Medium > Easy) +- Sélectionne les 3 cartes avec le score le plus élevé +- Charge le contenu (question, answer, notes) depuis `cards/*.md` + +**Output** : Texte formaté avec les 3 cartes du jour + +### 2. Poser le quiz (Format standardisé) ```markdown 🎯 **Check Quotidien - [DATE]** -**Question 1/3** : [COPIER EXACTEMENT la question depuis card_database.md - NE PAS INVENTER - PRIORITÉ Tingting] -→ [Attendre sa réponse] +**Question 1/3** : [Question de la carte 1 - PRIORITÉ Tingting] +→ [Attendre réponse] -**Question 2/3** : [Question Tingting OU domaine autre (famille/tech/perso)] -→ [Attendre sa réponse] +**Question 2/3** : [Question de la carte 2 - Minimum 2/3 sur Tingting] +→ [Attendre réponse] -**Question 3/3** : [Question Tingting OU domaine autre - VARIER] -→ [Attendre sa réponse] +**Question 3/3** : [Question de la carte 3 - Rotation tous domaines] +→ [Attendre réponse] --- @@ -84,7 +101,39 @@ Ce pattern affecte **PLUSIEURS domaines** : **Rappel** : [Adapté selon les questions posées] ``` -### Principes du Feedback +### 3. Logger automatiquement la session + +```bash +python3 scripts/log_session.py --cards "CARD-ID1,CARD-ID2,CARD-ID3" --scores "✅,⚠️,❌" +``` + +**Ce script fait** : +- Met à jour `Last Review` dans chaque fichier `cards/*.md` +- Met à jour `Success Rate` (calcul automatique basé sur historique) +- Incrémente `Times Failed` si score = ❌ +- Met à jour la table dans `card_database.md` avec les nouvelles stats +- Ajoute l'entrée dans `daily_sessions.md` +- Calcule le streak automatiquement + +**IMPORTANT** : Ne PLUS mettre à jour manuellement les stats. Les scripts gèrent tout. + +--- + +## Workflow Complet (Résumé) + +**Quand Alexis dit "daily check"** : + +1. **Run** `python3 scripts/get_daily_cards.py` +2. **Poser** les 3 questions affichées par le script +3. **Donner feedback** socratique (✅/⚠️/❌) +4. **Run** `python3 scripts/log_session.py --cards "ID1,ID2,ID3" --scores "✅,⚠️,❌"` +5. **Afficher** le résumé (score, streak, observation finale) + +**C'est tout.** Les scripts gèrent la cohérence automatiquement. + +--- + +## Principes du Feedback **Pour questions TINGTING** : - Ramener à elle et ce qu'elle ressent @@ -105,95 +154,47 @@ Ce pattern affecte **PLUSIEURS domaines** : --- -## Spaced Repetition Logic - -**Questions à poser basées sur** : -- `card_database.md` - Cartes actives -- **Times Asked** : Prioriser les cartes JAMAIS posées ou posées le moins souvent -- Son taux d'oubli par carte (si oublie souvent → pose plus souvent) -- Contexte récent (derniers conflits, conversations importantes) - -**Algorithme de sélection des cartes** : -1. **IMPÉRATIF : Lire `card_database.md` AVANT de poser TOUTE question** - Ne JAMAIS poser une question qui n'est pas dans la base -2. **Filtrer par catégorie** : - - **Minimum 2 questions Tingting** (cartes CORE-*, ACTION-*, LEAD-*, PATTERN-*, PLAN-*) - - **Maximum 1 question autre domaine** (PERSONAL-*, FAMILY-*, TECH-*) -3. **Prioriser par Times Asked** : - - Cartes avec `Times Asked: 0` = PRIORITÉ MAXIMALE - - Cartes avec `Times Asked: 1-2` = PRIORITÉ HAUTE - - Cartes avec `Times Asked: 3+` = rotation normale selon difficulté -4. **Respecter la difficulté/fréquence** : - - **Critical (Hard)** : Tous les jours jusqu'à maîtrisé - - **Medium** : Tous les 2-3 jours - - **Easy** : 1x semaine (pour maintenir) -5. **Éviter répétition immédiate** : Ne PAS poser une carte posée dans les dernières 24h (sauf si Critical et échec) - -**Objectif** : Faire tourner TOUTES les cartes régulièrement, pas juste les 3-4 mêmes - ---- - -## Logging Obligatoire - -**Après chaque session, logger dans** `daily_sessions.md` : - -```markdown -### [DATE - HH:MM] - -**Triggered by** : User / TTS Service / Manual -**Questions Asked** : -1. [Q1] → Score: ✅/⚠️/❌ -2. [Q2] → Score: ✅/⚠️/❌ -3. [Q3] → Score: ✅/⚠️/❌ - -**Total Score** : X/3 -**Time Taken** : X minutes -**Notes** : [Observations importantes] -**Streak** : X jours -``` - ---- - ## Red Flags à Signaler -🚩 **Si skip 2 jours consécutifs** → -- "2 jours sans daily check. Pattern d'oubli qui revient." -- "Tingting / Papa / [X] attendent que tu tiennes tes engagements." +**AVANT de faire le quiz**, vérifier dans `daily_sessions.md` : -🚩 **Si skip 3+ jours** → -- "3 jours. Le pattern d'oubli systémique est de retour." -- "Pour Tingting : Tu sais ce qu'elle ressent quand tu promets et que rien ne change ?" -- "Pour projets/famille : Combien de temps tu vas laisser traîner ?" +🚩 **Skip 2+ jours** → "X jours sans daily check. Pattern d'oubli qui revient. Tingting/Papa/[autres] attendent que tu tiennes tes engagements." -🚩 **Si score déclinant** → -- "Tes scores baissent. La complacency revient." -- "Tu redeviens celui qui promet mais n'agit jamais." +🚩 **Skip 3+ jours** → "3 jours. Le pattern d'oubli systémique est de retour. Tu sais ce qu'elle ressent quand tu promets et que rien ne change ?" -🚩 **Si même carte ratée 3x** → +🚩 **Score déclinant** → "Tes scores baissent. La complacency revient. Tu redeviens celui qui promet mais n'agit jamais." + +🚩 **Même carte ratée 3x** → - **Tingting** : "Tu oublies [CARD] systématiquement. Elle t'a dit combien de fois que c'était important ?" - **Autres** : "Ça fait 3 fois que tu rates [CARD]. C'est pas un hasard, c'est un pattern d'évitement." -🚩 **Si cartes non-Tingting jamais posées après 1 semaine** → -- "PERSONAL-001, FAMILY-001, TECH-001 ont jamais été reviewées." -- "Ton pattern d'oubli s'applique pas qu'à Tingting - regarde ta backlog qui s'accumule." +🚩 **Cartes non-Tingting jamais posées après 1 semaine** → "Ton pattern d'oubli s'applique pas qu'à Tingting - regarde ta backlog qui s'accumule." --- -## Fichiers à Consulter +## Structure du Système (Référence) -**Avant chaque quiz, lire** : -- `card_database.md` - Pour choisir les questions -- `daily_sessions.md` - Pour voir l'historique -- `../DAILY_REALITY_CHECK.md` - Pour voir s'il a skip récemment -- `../couple_backlog/` (le plus récent) - Pour contexte actuel +### Fichiers principaux -**Après chaque quiz, update** : -- `daily_sessions.md` - Logger la session COMPLÈTE avec détails des cartes -- `card_database.md` - Update pour CHAQUE carte posée : - - `Last Review` : Date d'aujourd'hui - - `Times Asked` : Incrémenter de 1 - - `Times Failed` : Incrémenter si échec (❌) - - `Success Rate` : Recalculer le pourcentage - - `Notes` : Ajouter observation si pattern important identifié +- **`card_database.md`** : Index centralisé (table markdown avec toutes les cartes et stats) +- **`CARD_SYSTEM_GUIDE.md`** : Instructions complètes du système (création cartes, tags, etc.) +- **`daily_sessions.md`** : Log de toutes les sessions +- **`cards/*.md`** : Fichiers individuels des cartes (question, answer, notes, stats) + +### Scripts Python + +- **`scripts/get_daily_cards.py`** : Sélectionne les 3 cartes du jour + - Options : `--num-cards N`, `--json` + - Algorithme : Priorise cartes critiques, jamais reviewées, en retard, avec échecs + +- **`scripts/log_session.py`** : Log la session et update toutes les stats + - Options : `--cards "ID1,ID2"`, `--scores "✅,❌"`, `--interactive`, `--dry-run` + - Met à jour automatiquement Last Review, Success Rate, Times Failed + +### Fichiers de contexte (consulter si nécessaire) + +- **`../DAILY_REALITY_CHECK.md`** : Voir s'il a skip récemment +- **`../couple_backlog/`** : Contexte des conflits récents --- @@ -295,3 +296,36 @@ Ce pattern affecte **PLUSIEURS domaines** : 4. **Question introspection** : "Qu'est-ce qui te fait dire ça maintenant ?" **Avantages** : Utilise son introspection naturelle, il arrive à ses propres conclusions (plus durable), moins de défensivité + +--- + +## Troubleshooting + +### "Les mêmes cartes reviennent tout le temps" + +**Cause** : Les stats ne sont pas à jour dans `card_database.md` + +**Solution** : S'assurer que `log_session.py` a bien été run après chaque quiz. Vérifier que les dates "Last Review" sont à jour dans `card_database.md`. + +### "Le script ne trouve pas les cartes" + +**Cause** : Chemin relatif incorrect ou fichier manquant + +**Solution** : Vérifier que tu run les scripts depuis le bon dossier, ou utiliser le chemin absolu. + +### "Score qui ne calcule pas correctement" + +**Cause** : Bug dans le parsing du Success Rate + +**Solution** : Vérifier le format dans `cards/*.md` - doit être "X% (n/total)" + +--- + +## Note Finale + +**PLUS BESOIN de mettre à jour manuellement** : +- ❌ `card_database.md` (géré par `log_session.py`) +- ❌ `cards/*.md` Review History (géré par `log_session.py`) +- ❌ `daily_sessions.md` (géré par `log_session.py`) + +**TOUT est automatisé.** Tu te concentres juste sur poser les bonnes questions et donner le bon feedback. diff --git a/anki_tingting/card_database.md b/anki_tingting/card_database.md index 5987d3d..b5c4478 100644 --- a/anki_tingting/card_database.md +++ b/anki_tingting/card_database.md @@ -1,19 +1,52 @@ # Card Database - Tingting Daily Check -**Dernière mise à jour** : 18/11/2025 -**Total cartes actives** : 19 +**Dernière mise à jour** : 19/11/2025 +**Total cartes actives** : 20 **Total cartes retirées** : 0 -**Total reviews** : 6 cartes (3 session 15/11, 3 session 18/11) +**Total reviews** : 8 cartes (3 session 15/11, 3 session 18/11, 6 session 19/11) **Breakdown par catégorie** : - Relation (Tingting) : 14 cartes - Personnel : 3 cartes - Famille : 1 carte - Tech/Projets : 1 carte +- Communication : 1 carte + +**📖 Pour les instructions complètes du système, voir `CARD_SYSTEM_GUIDE.md`** --- -## Active Cards +## Active Cards (Quick Reference Table) + +| ID | Card | Difficulty | Frequency | Last Review | Success Rate | Times Failed | Critical | +|---|---|---|---|---|---|---|---| +| CORE-001 | complacency_problem.md | Hard | Daily | 19/11/2025 | 100% (1/1) | 0 | ⚠️ | +| ACTION-001 | towel_detail.md | Medium | Every 2-3 days | Never | N/A | 0 | | +| CORE-002 | communication_paradox.md | Hard | Every 2-3 days | Never | N/A | 0 | | +| ACTION-002 | honest_feedback.md | Hard | Daily | 19/11/2025 | 50% (0.5/1) | 0 | ⚠️ | +| LEAD-001 | processing_time.md | Medium | Every conflict | 18/11/2025 | 100% (1/1) | 0 | ⚠️ | +| LEAD-002 | domination_esprit.md | Hard | Every conflict | Never | N/A | 0 | | +| ACTION-003 | initier_conversations.md | Medium | Every 2-3 days | 15/11/2025 | 33% (0.33/1) | 0 | ⚠️ | +| ACTION-004 | plan_long_terme.md | Hard | Every 3-4 days | 19/11/2025 | 50% (0.5/1) | 0 | ⚠️ | +| ACTION-005 | checklist_quotidienne.md | Easy | Daily | Never | N/A | 0 | | +| ACTION-006 | financial_security_setup.md | Hard | Every 2-3 days | 19/11/2025 | 100% (2.0/2) | 0 | ⚠️ | +| ACTION-007 | cuisiner_pour_elle.md | Medium | Every 2-3 days | Never | N/A | 0 | | +| PLAN-001 | plan_voyage_beijing.md | Hard | Every 2-3 days | Never | N/A | 0 | ⚠️ | +| PLAN-002 | plan_voyage_france.md | Hard | Every 2-3 days | Never | N/A | 0 | ⚠️ | +| PATTERN-001 | post_event_negativity.md | Hard | Every 2-3 days | Never | N/A | 0 | ⚠️ | +| FUTURE-001 | ceremonie_mariage_epargne.md | Hard | Monthly | 19/11/2025 | 50% (0.5/1) | 0 | ⚠️ | +| FUTURE-002 | cadeaux_mariage_traditionnels.md | Medium | Every 2 weeks | 19/11/2025 | 100% (1/1) | 0 | | +| PERSONAL-001 | reddit_saves_review.md | Medium | Weekly | Never | N/A | 0 | | +| FAMILY-001 | social_media_automation_papa.md | Hard | Every 3-4 days | 18/11/2025 | 100% (1/1) | 0 | | +| TECH-001 | class_generator_mac.md | Medium | Every 3-4 days | Never | N/A | 0 | | +| PERSONAL-002 | manage_music_phone.md | Easy | Every 7 days | Never | N/A | 0 | | +| COMM-001 | emotional_calibration.md | Hard | Every 2-3 days | Never | N/A | 0 | ⚠️ | + +**Note** : Tous les fichiers de cartes détaillés sont dans le dossier `cards/`. La table ci-dessus sert de quick reference pour les scripts et Claude. + +--- + +## Active Cards (Detailed View) ### Card #1 - Complacency Problem ⚠️ CRITICAL **ID** : CORE-001 @@ -23,11 +56,12 @@ **Difficulty** : Hard **Frequency** : Daily (jusqu'à maîtrisé) **Created** : 07/11/2025 -**Last Review** : 18/11/2025 +**Last Review** : 19/11/2025 **Success Rate** : 100% (1 review) **Times Asked** : 1 **Times Failed** : 0 **Notes** : C'est LE problème central. Si j'oublie ça, j'oublie tout. ✅ 18/11 : Bonne compréhension - identifie autopilot vs thinking intentionnel, reconnaît que daily check aide. +**Card File** : `cards/complacency_problem.md` --- @@ -45,6 +79,7 @@ **Times Failed** : 0 **Notes** : Déclencheur du conflit 07/11. Exemple parfait de détail que j'oublie. +<<<<<<< HEAD --- ### Card #3 - Communication Paradox @@ -323,121 +358,29 @@ --- +## Summary Statistics + +**Cards par catégorie** : +- CORE (Problèmes fondamentaux) : 2 +- ACTION (Actions concrètes) : 7 +- LEAD (Leadership dans conflits) : 2 +- PLAN (Planning voyages) : 2 +- PATTERN (Patterns comportementaux) : 1 +- FUTURE (Long terme) : 2 +- PERSONAL (Développement personnel) : 2 +- FAMILY (Famille) : 1 +- TECH (Projets techniques) : 1 +- COMM (Communication patterns) : 1 + +**Cards par difficulté** : +- Easy : 2 +- Medium : 7 +- Hard : 11 + +**Cards critiques** : 11 + +--- + ## Retired Cards (Aucune pour l'instant - les cartes sont retirées quand le problème est durablement résolu) - ---- - -## Card Creation Guidelines - -### Quand créer une nouvelle carte ? - -**Créer quand** : -- Nouveau pattern identifié dans un conflit -- Truc important qu'elle a dit et que je risque d'oublier -- Action concrète convenue ensemble -- Insight important sur la dynamique couple - -**Ne PAS créer quand** : -- C'est trop spécifique/temporaire (genre "acheter du lait demain") -- C'est redondant avec une carte existante -- C'est pas vraiment important - -### Format de carte - -```markdown -### Card #X - [Nom Court] -**ID** : [CATEGORY-XXX] -**Question** : [Question claire, directe] -**Answer** : [Réponse complète, avec contexte si nécessaire] -**Tags** : [tags séparés par virgule] -**Difficulty** : Easy / Medium / Hard -**Frequency** : [À quelle fréquence la poser] -**Created** : [Date] -**Last Review** : [Date ou "Never"] -**Success Rate** : [X% ou N/A] -**Times Failed** : [Nombre] -**Notes** : [Contexte additionnel, pourquoi c'est important] -``` - -### Tag System - -**Categories** : -- `core-problem` : Problèmes fondamentaux de la relation -- `action` : Actions concrètes à faire -- `communication` : Patterns de communication -- `detail` : Détails pratiques à retenir -- `pattern` : Patterns comportementaux - -**Importance** : -- `critical` : À ne JAMAIS oublier -- `daily` : À checker quotidiennement -- `weekly` : Moins urgent mais important - -### Difficulty Levels - -**Easy** : Je peux répondre facilement, juste besoin de maintenir -**Medium** : Je dois y penser, risque d'oubli moyen -**Hard** : J'oublie systématiquement, ou c'est difficile émotionnellement - -### Frequency Guidelines - -**Daily** : Cartes critical ou hard que j'oublie souvent -**Every 2-3 days** : Cartes medium, pour maintenir -**Weekly** : Cartes easy, juste pour pas oublier complètement - ---- - -## Spaced Repetition Algorithm (Simple) - -### Logique de base - -**Si réponse correcte** : -- Easy card : +7 jours avant prochaine review -- Medium card : +3 jours -- Hard card : +1 jour - -**Si réponse incorrecte** : -- Toutes difficultés : Review demain (reset) - -**Si échec 3x sur même carte** : -- Augmenter frequency à "daily" -- Flagged pour attention spéciale - -### Update après chaque session - -Après chaque daily check, update : -1. **Last Review** : Date d'aujourd'hui -2. **Success Rate** : Calculer nouveau % -3. **Times Failed** : Incrémenter si échec -4. **Next Review** : Calculer selon l'algo ci-dessus - ---- - -## Stats Overview - -**À calculer hebdomadairement** : - -```markdown -### Week of [DATE] - -**Total Reviews** : X -**Average Score** : X/3 -**Cards Mastered** : X (success rate > 80% sur 5+ reviews) -**Cards Struggling** : X (success rate < 50%) -**Longest Streak** : X days -**Times Skipped** : X - -**Most Failed Card** : [Card ID] - [X failures] -**Best Performing Card** : [Card ID] - [X% success rate] -``` - ---- - -## Next Actions - -- [ ] Review ces 4 cartes lors du prochain daily check -- [ ] Après 1 semaine, analyser quelles cartes sont les plus difficiles -- [ ] Créer nouvelles cartes si nouveaux patterns identifiés -- [ ] Retirer cartes si problèmes durablement résolus (3+ semaines de succès) diff --git a/anki_tingting/cards/cadeaux_mariage_traditionnels.md b/anki_tingting/cards/cadeaux_mariage_traditionnels.md index 494abdf..c8a6909 100644 --- a/anki_tingting/cards/cadeaux_mariage_traditionnels.md +++ b/anki_tingting/cards/cadeaux_mariage_traditionnels.md @@ -26,6 +26,6 @@ Tingting ne devrait pas avoir à m'expliquer tout ça - c'est MON rôle de me re ## Review History -**Last Review**: Never -**Success Rate**: N/A (nouveau) +**Last Review**: 19/11/2025 +**Success Rate**: 100% (1/1) **Times Failed**: 0 diff --git a/anki_tingting/cards/ceremonie_mariage_epargne.md b/anki_tingting/cards/ceremonie_mariage_epargne.md index 3bf07e7..3ab0974 100644 --- a/anki_tingting/cards/ceremonie_mariage_epargne.md +++ b/anki_tingting/cards/ceremonie_mariage_epargne.md @@ -26,6 +26,6 @@ Cette carte reste ACTIVE jusqu'à ce que Tingting ait eu sa cérémonie. Pas de ## Review History -**Last Review**: Never -**Success Rate**: N/A (nouveau) +**Last Review**: 19/11/2025 +**Success Rate**: 50% (0.5/1) **Times Failed**: 0 diff --git a/anki_tingting/cards/complacency_problem.md b/anki_tingting/cards/complacency_problem.md index 06f64b7..c463d7a 100644 --- a/anki_tingting/cards/complacency_problem.md +++ b/anki_tingting/cards/complacency_problem.md @@ -26,6 +26,6 @@ C'est LE problème central. Si j'oublie ça, j'oublie tout. ## Review History -**Last Review**: Never -**Success Rate**: N/A (nouveau) +**Last Review**: 19/11/2025 +**Success Rate**: 100% (1/1) **Times Failed**: 0 diff --git a/anki_tingting/cards/emotional_calibration.md b/anki_tingting/cards/emotional_calibration.md new file mode 100644 index 0000000..bb2a281 --- /dev/null +++ b/anki_tingting/cards/emotional_calibration.md @@ -0,0 +1,59 @@ +# Card: Emotional Calibration Problem + +**ID**: COMM-001 +**Created**: 19/11/2025 +**Status**: Active ⚠️ CRITICAL + +--- + +## Question + +Pourquoi Tingting demande "pourquoi tu t'énerves pas ?" quand tu lui parles de quelque chose qui te dérange ? + +--- + +## Answer + +**Le problème de calibration** : Je suis ultra chill par nature (exemple : -2500€ fisc = down 1 jour puis move on). Mon range émotionnel est très étroit, donc Tingting ne peut pas distinguer ce qui est vraiment important de ce qui l'est pas. + +**Exemples de mon niveau de chill** : +- Appart en bordel = littéralement invisible +- Vêtements sales = je remets les mêmes, osef +- -2500€ au fisc, zéro revenu = down 1 jour puis "next" +- Pas assez de sex = conversation calme +- Elle respecte pas ma fatigue = "c'est relou" + +**Du coup elle voit tout pareil** → Comment elle fait la différence entre ce qui compte vraiment et ce qui compte pas ? + +**Ce qu'elle cherche** : Pas de la colère, mais des **marqueurs d'intensité** pour comprendre la hiérarchie de mes priorités. + +**Solution** : Utiliser des **mots explicites** pour signaler l'importance, pas juste compter sur le ton émotionnel. + +**Exemples concrets** : +- ❌ "The sex situation is a bit frustrating" (ton calme habituel) +- ✅ "This is really important to me. I need you to understand this is a priority for our relationship" (même ton, mais **clarté**) + +**Sujets actuellement importants** malgré mon ton calme : +1. **Sex** - Fréquence insuffisante, c'est vraiment important même si je le dis calmement +2. **Respect de ma fatigue** - Quand elle ne respecte pas alors que je respecte la sienne, c'est un problème d'équité + +--- + +## Notes + +**Contexte** : Conversation daily check 19/11/2025. Elle a dit plusieurs fois "pourquoi tu t'énerves pas ?" sur le sujet du sex. On a identifié que c'est pas un problème d'évitement de ma part, mais un problème de **langage émotionnel incompatible**. + +**Être chill = force dans la vie** (résilience, efficacité émotionnelle) +**Être chill = bug de communication** avec quelqu'un qui a besoin de signaux émotionnels + +**Action concrète** : Quand quelque chose est important, DIRE EXPLICITEMENT "This is important to me" ou "This is a priority" - ne pas laisser Tingting deviner basé sur un ton qui ne change jamais. + +**Validation de son besoin** : Elle a raison de chercher à comprendre mes priorités. C'est pas elle qui est "trop émotionnelle", c'est juste qu'on a des langages différents et je dois adapter ma communication. + +--- + +## Review History + +**Last Review**: Never +**Success Rate**: N/A (nouveau) +**Times Failed**: 0 diff --git a/anki_tingting/cards/financial_security_setup.md b/anki_tingting/cards/financial_security_setup.md index 2977680..0d06fd1 100644 --- a/anki_tingting/cards/financial_security_setup.md +++ b/anki_tingting/cards/financial_security_setup.md @@ -26,6 +26,6 @@ La France = wake-up call à 3500€. NE JAMAIS OUBLIER cette leçon. C'est MON R ## Review History -**Last Review**: 18/11/2025 -**Success Rate**: 100% (1/1) +**Last Review**: 19/11/2025 +**Success Rate**: 100% (2.0/2) **Times Failed**: 0 diff --git a/anki_tingting/cards/honest_feedback.md b/anki_tingting/cards/honest_feedback.md index ef0203c..8554a98 100644 --- a/anki_tingting/cards/honest_feedback.md +++ b/anki_tingting/cards/honest_feedback.md @@ -26,6 +26,6 @@ Elle a dit que c'est "LE PIRE" que je ne lui dise pas. Donc TRÈS important. ## Review History -**Last Review**: Never -**Success Rate**: N/A (nouveau) +**Last Review**: 19/11/2025 +**Success Rate**: 50% (0.5/1) **Times Failed**: 0 diff --git a/anki_tingting/cards/plan_long_terme.md b/anki_tingting/cards/plan_long_terme.md index af13fdb..3558f5d 100644 --- a/anki_tingting/cards/plan_long_terme.md +++ b/anki_tingting/cards/plan_long_terme.md @@ -26,6 +26,6 @@ Pattern identifié : j'oublie que c'est mon rôle. Timing "jamais bon" = excuse. ## Review History -**Last Review**: Never -**Success Rate**: N/A (nouveau) +**Last Review**: 19/11/2025 +**Success Rate**: 50% (0.5/1) **Times Failed**: 0 diff --git a/anki_tingting/daily_sessions.md b/anki_tingting/daily_sessions.md index 8822711..0ff6ed8 100644 --- a/anki_tingting/daily_sessions.md +++ b/anki_tingting/daily_sessions.md @@ -747,3 +747,87 @@ Bon retour après 2 jours d'absence. Montre une meilleure compréhension des con --- + +### 2025-11-19 [Time Unknown] + +**Triggered by** : User (manual "daily check") +**Duration** : ~5 minutes + +**Questions Asked** : +1. [FUTURE-001] Combien d'argent as-tu mis de côté ce mois-ci pour la cérémonie de Tingting ? → Score: ⚠️ + - Ta réponse : "0€ gagné donc 0€ mis de côté, mais je setup ce qu'il faut" + - Feedback : Tu setup les systèmes (Wise, plan financier) = bon. Mais "Chaque mois sans épargne = un mois de plus où je retarde son rêve." Tu es en mode setup, combien de temps encore avant que l'argent rentre vraiment ? Elle voit que tu prépares, ou elle voit "toujours pas d'argent pour la cérémonie" ? + +2. [ACTION-006] Qu'est-ce que tu as fait concrètement cette semaine pour avancer sur le setup financier ? → Score: ✅ + - Ta réponse : "Wise setup + plan fait + carte créée hier + setup le world pour être autonome et productif" + - Feedback : Actions concrètes. C'est exactement ce qu'elle a besoin de voir. Tu FAIS, pas juste tu parles. Continue. + +3. [FUTURE-002] Qu'est-ce que tu sais sur les cadeaux de mariage traditionnels chinois et où en es-tu dans la préparation ? → Score: ✅ + - Ta réponse : "Bracelet en or + jade blanc laiteux + voyages provinces chinoises pour photos costumes historiques" + - Feedback : Tu SAIS. Tu as écouté, retenu, compris l'importance culturelle. Question : Est-ce que tu as budgété pour ça ? Combien ça coûte ? Savoir c'est bien, avoir l'argent quand le moment vient c'est mieux. + +**Total Score** : 2/3 +**Streak** : 2 jours (18/11 + 19/11) +**Notes** : Tu setup les systèmes (finances, connaissance culturelle) = bon signe. Mais question reste : Tingting voit "il prépare activement notre futur" ou elle voit "il setup des trucs mais l'argent arrive toujours pas" ? Combien de temps encore avant que le setup devienne des résultats concrets qu'elle peut voir ? +**Action Items** : +- Définir timeline : Quand est-ce que l'argent commence à rentrer ? +- Budgéter précisément : Bracelet or + jade + voyages = combien ? + +**Observation finale** : Alexis frustré par répétition de CORE-001 (complacency_problem) tous les jours. Système de sélection des cartes à améliorer - les stats individuelles ne sont pas mises à jour donc Claude pense que les cartes n'ont jamais été révisées. + +--- + + +### 2025-11-19 [Time Unknown] + +**Triggered by** : User (manual "daily check") +**Duration** : ~5 minutes + +**Questions Asked** : +1. [FUTURE-001] Combien d'argent as-tu mis de côté ce mois-ci pour la cérémonie de Tingting ? → Score: ⚠️ + - Ta réponse : "[Non enregistrée]" + - Feedback : [Généré automatiquement] + +2. [ACTION-006] Qu'est-ce que tu dois setup pour protéger vos finances et qu'est-ce que la France t'a appris ? → Score: ✅ + - Ta réponse : "[Non enregistrée]" + - Feedback : [Généré automatiquement] + +3. [FUTURE-002] Qu'est-ce que tu sais sur les cadeaux de mariage traditionnels chinois et où en es-tu dans la préparation ? → Score: ✅ + - Ta réponse : "[Non enregistrée]" + - Feedback : [Généré automatiquement] + +**Total Score** : 2.5/3 +**Streak** : 3 jours +**Notes** : Session loggée automatiquement via log_session.py +**Action Items** : +- [À compléter manuellement si nécessaire] + +--- + + +### 2025-11-19 [Time Unknown] + +**Triggered by** : User (manual "daily check") +**Duration** : ~5 minutes + +**Questions Asked** : +1. [CORE-001] Pourquoi Tingting dit que tu "think" pas ? → Score: ✅ + - Ta réponse : "[Non enregistrée]" + - Feedback : [Généré automatiquement] + +2. [ACTION-002] Qu'est-ce que Tingting veut que je fasse quand elle fait des trucs wrong ? → Score: ⚠️ + - Ta réponse : "[Non enregistrée]" + - Feedback : [Généré automatiquement] + +3. [ACTION-004] Qu'est-ce que tu as réfléchi ou proposé récemment pour votre avenir ensemble ? → Score: ⚠️ + - Ta réponse : "[Non enregistrée]" + - Feedback : [Généré automatiquement] + +**Total Score** : 2.0/3 +**Streak** : 3 jours +**Notes** : Session loggée automatiquement via log_session.py +**Action Items** : +- [À compléter manuellement si nécessaire] + +--- + diff --git a/anki_tingting/scripts/get_daily_cards.py b/anki_tingting/scripts/get_daily_cards.py new file mode 100644 index 0000000..90aac6a --- /dev/null +++ b/anki_tingting/scripts/get_daily_cards.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python3 +""" +Script pour sélectionner les cartes quotidiennes du système Anki Tingting. + +Usage: + python get_daily_cards.py [--num-cards N] [--json] + +Options: + --num-cards N : Nombre de cartes à sélectionner (défaut: 3) + --json : Output en JSON (défaut: texte lisible) +""" + +import os +import re +import json +import argparse +from datetime import datetime, timedelta +from pathlib import Path + + +# Chemins relatifs au script +SCRIPT_DIR = Path(__file__).parent +BASE_DIR = SCRIPT_DIR.parent +CARD_DB_PATH = BASE_DIR / "card_database.md" +CARDS_DIR = BASE_DIR / "cards" + + +def parse_date(date_str): + """Parse une date au format DD/MM/YYYY ou 'Never'.""" + if date_str == "Never" or date_str == "N/A": + return None + try: + return datetime.strptime(date_str, "%d/%m/%Y") + except ValueError: + return None + + +def parse_card_database(): + """Parse le fichier card_database.md et retourne la liste des cartes.""" + with open(CARD_DB_PATH, 'r', encoding='utf-8') as f: + content = f.read() + + # Trouver la table markdown + table_pattern = r'\| ID \| Card \| Difficulty.*?\n\|---.*?\n((?:\|.*?\n)+)' + match = re.search(table_pattern, content, re.DOTALL) + + if not match: + raise ValueError("Impossible de trouver la table dans card_database.md") + + table_rows = match.group(1).strip().split('\n') + + cards = [] + for row in table_rows: + # Parse chaque ligne de la table + cols = [col.strip() for col in row.split('|')[1:-1]] # Ignore les | de début/fin + + if len(cols) < 8: + continue + + card_id, card_file, difficulty, frequency, last_review, success_rate, times_failed, critical = cols + + cards.append({ + 'id': card_id, + 'file': card_file, + 'difficulty': difficulty, + 'frequency': frequency, + 'last_review': parse_date(last_review), + 'last_review_str': last_review, + 'success_rate': success_rate, + 'times_failed': int(times_failed) if times_failed.isdigit() else 0, + 'critical': critical == '⚠️' + }) + + return cards + + +def load_card_content(card_file): + """Charge le contenu d'une carte depuis son fichier.""" + card_path = CARDS_DIR / card_file + + with open(card_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Extract question + question_match = re.search(r'## Question\s*\n\s*\n(.*?)\n\s*\n---', content, re.DOTALL) + question = question_match.group(1).strip() if question_match else "Question non trouvée" + + # Extract answer + answer_match = re.search(r'## Answer\s*\n\s*\n(.*?)\n\s*\n---', content, re.DOTALL) + answer = answer_match.group(1).strip() if answer_match else "Réponse non trouvée" + + # Extract notes + notes_match = re.search(r'## Notes\s*\n\s*\n(.*?)\n\s*\n---', content, re.DOTALL) + notes = notes_match.group(1).strip() if notes_match else "" + + return { + 'question': question, + 'answer': answer, + 'notes': notes + } + + +def calculate_priority_score(card, today): + """Calcule un score de priorité pour une carte.""" + score = 0 + + # CRITICAL cards = haute priorité + if card['critical']: + score += 100 + + # Times failed = haute priorité + score += card['times_failed'] * 50 + + # Difficulté + difficulty_scores = {'Hard': 30, 'Medium': 20, 'Easy': 10} + score += difficulty_scores.get(card['difficulty'], 0) + + # Temps depuis dernière review + if card['last_review'] is None: + score += 200 # Jamais révisée = très haute priorité + else: + days_since = (today - card['last_review']).days + + # Calculer le nombre de jours attendus selon frequency + freq_days = { + 'Daily': 1, + 'Every 2-3 days': 2, + 'Every 3-4 days': 3, + 'Every 2 weeks': 14, + 'Monthly': 30, + 'Every conflict': 999 # Pas basé sur le temps + } + + expected_days = freq_days.get(card['frequency'], 7) + + if card['frequency'] == 'Every conflict': + # Cartes de conflit : priorité basse sauf si jamais révisées + score += 5 + elif days_since >= expected_days: + # En retard sur la review + score += 80 + (days_since - expected_days) * 10 + else: + # Pas encore le moment + score += 5 + + # Success rate (si disponible) + if card['success_rate'] not in ['N/A', 'Never']: + try: + rate = int(card['success_rate'].replace('%', '')) + if rate < 70: + score += 40 + except ValueError: + pass + + return score + + +def select_daily_cards(num_cards=3): + """Sélectionne les cartes pour la session quotidienne.""" + cards = parse_card_database() + today = datetime.now() + + # Calculer le score de priorité pour chaque carte + for card in cards: + card['priority_score'] = calculate_priority_score(card, today) + + # Trier par priorité décroissante + cards.sort(key=lambda c: c['priority_score'], reverse=True) + + # Sélectionner les N premières cartes + selected = cards[:num_cards] + + # Charger le contenu de chaque carte + for card in selected: + content = load_card_content(card['file']) + card.update(content) + + return selected + + +def format_output_text(cards): + """Formate l'output en texte lisible.""" + output = [] + output.append("=" * 60) + output.append(f"📚 CARTES SÉLECTIONNÉES - {datetime.now().strftime('%d/%m/%Y')}") + output.append("=" * 60) + output.append("") + + for i, card in enumerate(cards, 1): + output.append(f"🎯 CARTE {i}/3") + output.append(f"ID: {card['id']}") + output.append(f"Fichier: {card['file']}") + output.append(f"Difficulté: {card['difficulty']} | Critique: {'⚠️ OUI' if card['critical'] else 'Non'}") + output.append(f"Dernière review: {card['last_review_str']}") + output.append(f"Score priorité: {card['priority_score']}") + output.append("") + output.append(f"QUESTION:") + output.append(card['question']) + output.append("") + output.append(f"RÉPONSE ATTENDUE:") + output.append(card['answer']) + output.append("") + if card['notes']: + output.append(f"NOTES:") + output.append(card['notes']) + output.append("") + output.append("-" * 60) + output.append("") + + return "\n".join(output) + + +def format_output_json(cards): + """Formate l'output en JSON.""" + return json.dumps({ + 'date': datetime.now().strftime('%d/%m/%Y'), + 'cards': [ + { + 'id': card['id'], + 'file': card['file'], + 'difficulty': card['difficulty'], + 'critical': card['critical'], + 'last_review': card['last_review_str'], + 'priority_score': card['priority_score'], + 'question': card['question'], + 'answer': card['answer'], + 'notes': card['notes'] + } + for card in cards + ] + }, indent=2, ensure_ascii=False) + + +def main(): + parser = argparse.ArgumentParser(description='Sélectionne les cartes quotidiennes') + parser.add_argument('--num-cards', type=int, default=3, help='Nombre de cartes à sélectionner') + parser.add_argument('--json', action='store_true', help='Output en JSON') + + args = parser.parse_args() + + try: + cards = select_daily_cards(args.num_cards) + + if args.json: + print(format_output_json(cards)) + else: + print(format_output_text(cards)) + + except Exception as e: + print(f"❌ ERREUR: {e}", file=sys.stderr) + import sys + sys.exit(1) + + +if __name__ == '__main__': + import sys + main() diff --git a/anki_tingting/scripts/log_session.py b/anki_tingting/scripts/log_session.py new file mode 100644 index 0000000..056896c --- /dev/null +++ b/anki_tingting/scripts/log_session.py @@ -0,0 +1,440 @@ +#!/usr/bin/env python3 +""" +Script pour logger une session de daily check et mettre à jour les stats. + +Usage: + python log_session.py --cards "CORE-001,ACTION-006,FUTURE-001" --scores "✅,⚠️,❌" + + OU en mode interactif: + python log_session.py --interactive + +Options: + --cards : Liste des IDs de cartes (séparées par virgules) + --scores : Liste des scores ✅/⚠️/❌ (séparées par virgules) + --interactive: Mode interactif qui demande les infos + --dry-run : Test sans modifier les fichiers +""" + +import os +import re +import argparse +from datetime import datetime +from pathlib import Path + + +# Chemins relatifs au script +SCRIPT_DIR = Path(__file__).parent +BASE_DIR = SCRIPT_DIR.parent +CARD_DB_PATH = BASE_DIR / "card_database.md" +CARDS_DIR = BASE_DIR / "cards" +SESSIONS_LOG = BASE_DIR / "daily_sessions.md" + + +def parse_card_database(): + """Parse le fichier card_database.md et retourne un dict {card_id: card_info}.""" + with open(CARD_DB_PATH, 'r', encoding='utf-8') as f: + content = f.read() + + # Trouver la table markdown + table_pattern = r'\| ID \| Card \| Difficulty.*?\n\|---.*?\n((?:\|.*?\n)+)' + match = re.search(table_pattern, content, re.DOTALL) + + if not match: + raise ValueError("Impossible de trouver la table dans card_database.md") + + table_rows = match.group(1).strip().split('\n') + + cards = {} + for row in table_rows: + cols = [col.strip() for col in row.split('|')[1:-1]] + + if len(cols) < 8: + continue + + card_id, card_file, difficulty, frequency, last_review, success_rate, times_failed, critical = cols + + cards[card_id] = { + 'id': card_id, + 'file': card_file, + 'difficulty': difficulty, + 'frequency': frequency, + 'last_review': last_review, + 'success_rate': success_rate, + 'times_failed': int(times_failed) if times_failed.isdigit() else 0, + 'critical': critical == '⚠️' + } + + return cards + + +def update_card_file(card_file, score, today_str): + """Met à jour les stats dans le fichier de carte individuel.""" + card_path = CARDS_DIR / card_file + + with open(card_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Update Last Review + content = re.sub( + r'\*\*Last Review\*\*: .*', + f'**Last Review**: {today_str}', + content + ) + + # Update Times Failed + if score == '❌': + # Incrémenter Times Failed + def increment_failed(match): + current = int(match.group(1)) if match.group(1).isdigit() else 0 + return f'**Times Failed**: {current + 1}' + + content = re.sub( + r'\*\*Times Failed\*\*: (\d+)', + increment_failed, + content + ) + + # Update Success Rate + # Extraire le success rate actuel + success_match = re.search(r'\*\*Success Rate\*\*: (.*)', content) + if success_match: + current_rate_str = success_match.group(1).strip() + + # Parse le success rate actuel + if current_rate_str in ['N/A', 'N/A (nouveau)']: + # Première review + if score == '✅': + new_rate = '100% (1/1)' + elif score == '⚠️': + new_rate = '50% (0.5/1)' + else: # ❌ + new_rate = '0% (0/1)' + else: + # Parse "X% (n/total)" ou juste "X%" + rate_match = re.match(r'(\d+)%\s*\(?([\d.]+)/(\d+)\)?', current_rate_str) + if rate_match: + current_percent, successes, total = rate_match.groups() + successes = float(successes) + total = int(total) + else: + # Fallback: juste un pourcentage + rate_match = re.match(r'(\d+)%', current_rate_str) + if rate_match: + current_percent = int(rate_match.group(1)) + # Estimer successes/total basé sur le pourcentage + successes = 1 if current_percent >= 50 else 0 + total = 1 + else: + successes = 0 + total = 0 + + # Ajouter la nouvelle review + total += 1 + if score == '✅': + successes += 1 + elif score == '⚠️': + successes += 0.5 + + new_percent = int((successes / total) * 100) if total > 0 else 0 + new_rate = f'{new_percent}% ({successes}/{total})' + + content = re.sub( + r'\*\*Success Rate\*\*: .*', + f'**Success Rate**: {new_rate}', + content + ) + + return content + + +def update_card_database(cards_dict, today_str): + """Met à jour la table dans card_database.md avec les nouvelles stats.""" + with open(CARD_DB_PATH, 'r', encoding='utf-8') as f: + content = f.read() + + # Pour chaque carte, update sa ligne dans la table + for card_id, card_info in cards_dict.items(): + # Trouver la ligne correspondante + row_pattern = rf'\| {re.escape(card_id)} \| ([^\n]+)' + match = re.search(row_pattern, content) + + if match: + old_row = match.group(0) + + # Reconstruire la nouvelle ligne + critical_symbol = '⚠️' if card_info['critical'] else '' + new_row = ( + f"| {card_id} | {card_info['file']} | {card_info['difficulty']} | " + f"{card_info['frequency']} | {card_info['last_review']} | " + f"{card_info['success_rate']} | {card_info['times_failed']} | {critical_symbol} |" + ) + + content = content.replace(old_row, new_row) + + # Update "Dernière mise à jour" + content = re.sub( + r'\*\*Dernière mise à jour\*\* : \d{2}/\d{2}/\d{4}', + f'**Dernière mise à jour** : {today_str}', + content + ) + + return content + + +def calculate_streak(sessions_content): + """Calcule le streak actuel basé sur le fichier daily_sessions.md.""" + # Trouver toutes les sessions + session_pattern = r'### (\d{4}-\d{2}-\d{2})' + dates = re.findall(session_pattern, sessions_content) + + if not dates: + return 1 # Première session + + # Convertir en datetime + session_dates = [] + for date_str in dates: + try: + session_dates.append(datetime.strptime(date_str, '%Y-%m-%d')) + except ValueError: + continue + + if not session_dates: + return 1 + + # Trier par date décroissante + session_dates.sort(reverse=True) + + today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) + + # Calculer le streak + streak = 1 # Aujourd'hui compte + last_date = today + + for session_date in session_dates: + session_date = session_date.replace(hour=0, minute=0, second=0, microsecond=0) + + # Check si c'est le jour précédent + if (last_date - session_date).days == 1: + streak += 1 + last_date = session_date + elif session_date == last_date: + # Même jour, ignorer + continue + else: + # Gap détecté, arrêter + break + + return streak + + +def log_session(card_ids, scores, responses=None, feedback_notes=None, dry_run=False): + """ + Log une session complète et met à jour toutes les stats. + + Args: + card_ids: Liste des IDs de cartes (ex: ['CORE-001', 'ACTION-006']) + scores: Liste des scores (ex: ['✅', '⚠️', '❌']) + responses: (Optionnel) Liste des réponses données + feedback_notes: (Optionnel) Liste des feedbacks + dry_run: Si True, affiche ce qui serait fait sans modifier les fichiers + """ + if len(card_ids) != len(scores): + raise ValueError(f"Nombre de cartes ({len(card_ids)}) != nombre de scores ({len(scores)})") + + # Valider les scores + valid_scores = ['✅', '⚠️', '❌'] + for score in scores: + if score not in valid_scores: + raise ValueError(f"Score invalide: {score}. Utilise ✅, ⚠️ ou ❌") + + today = datetime.now() + today_str = today.strftime('%d/%m/%Y') + today_iso = today.strftime('%Y-%m-%d') + + # Parse card database + cards_dict = parse_card_database() + + # Vérifier que toutes les cartes existent + for card_id in card_ids: + if card_id not in cards_dict: + raise ValueError(f"Carte inconnue: {card_id}") + + print(f"📝 LOGGING SESSION - {today_str}") + print("=" * 60) + + # Update chaque carte + updated_cards = {} + for i, (card_id, score) in enumerate(zip(card_ids, scores)): + card = cards_dict[card_id] + print(f"\n🎯 Carte {i+1}: {card_id} → {score}") + + # Update le fichier de carte individuel + if not dry_run: + updated_content = update_card_file(card['file'], score, today_str) + card_path = CARDS_DIR / card['file'] + with open(card_path, 'w', encoding='utf-8') as f: + f.write(updated_content) + print(f" ✅ Fichier {card['file']} mis à jour") + else: + print(f" [DRY RUN] Mettrait à jour {card['file']}") + + # Re-parse le fichier pour obtenir les nouvelles stats + if not dry_run: + with open(CARDS_DIR / card['file'], 'r', encoding='utf-8') as f: + new_content = f.read() + + # Extraire les nouvelles stats + success_match = re.search(r'\*\*Success Rate\*\*: (.*)', new_content) + failed_match = re.search(r'\*\*Times Failed\*\*: (\d+)', new_content) + + card['success_rate'] = success_match.group(1).strip() if success_match else card['success_rate'] + card['times_failed'] = int(failed_match.group(1)) if failed_match else card['times_failed'] + card['last_review'] = today_str + + updated_cards[card_id] = card + else: + print(f" [DRY RUN] Stats seraient mises à jour") + + # Update card_database.md + if not dry_run: + db_content = update_card_database(updated_cards, today_str) + with open(CARD_DB_PATH, 'w', encoding='utf-8') as f: + f.write(db_content) + print(f"\n✅ card_database.md mis à jour") + else: + print(f"\n[DRY RUN] card_database.md serait mis à jour") + + # Calculer le score total + score_values = {'✅': 1, '⚠️': 0.5, '❌': 0} + total_score = sum(score_values[s] for s in scores) + max_score = len(scores) + + # Calculer le streak + if not dry_run: + with open(SESSIONS_LOG, 'r', encoding='utf-8') as f: + sessions_content = f.read() + streak = calculate_streak(sessions_content) + else: + streak = 1 + + # Créer l'entrée de log pour daily_sessions.md + log_entry = f""" +### {today_iso} [Time Unknown] + +**Triggered by** : User (manual "daily check") +**Duration** : ~5 minutes + +**Questions Asked** : +""" + + for i, (card_id, score) in enumerate(zip(card_ids, scores), 1): + card = cards_dict[card_id] + + # Charger la question depuis le fichier + with open(CARDS_DIR / card['file'], 'r', encoding='utf-8') as f: + content = f.read() + question_match = re.search(r'## Question\s*\n\s*\n(.*?)\n\s*\n---', content, re.DOTALL) + question = question_match.group(1).strip() if question_match else "Question non trouvée" + + response = responses[i-1] if responses and i-1 < len(responses) else "[Non enregistrée]" + feedback = feedback_notes[i-1] if feedback_notes and i-1 < len(feedback_notes) else "[Généré automatiquement]" + + log_entry += f"""{i}. [{card_id}] {question} → Score: {score} + - Ta réponse : "{response}" + - Feedback : {feedback} + +""" + + log_entry += f"""**Total Score** : {total_score}/{max_score} +**Streak** : {streak} jour{'s' if streak > 1 else ''} +**Notes** : Session loggée automatiquement via log_session.py +**Action Items** : +- [À compléter manuellement si nécessaire] + +--- + +""" + + # Append au fichier de sessions + if not dry_run: + with open(SESSIONS_LOG, 'a', encoding='utf-8') as f: + f.write(log_entry) + print(f"✅ Session loggée dans daily_sessions.md") + else: + print(f"[DRY RUN] Session serait loggée dans daily_sessions.md") + + print("=" * 60) + print(f"✅ SESSION COMPLÈTE") + print(f"Score: {total_score}/{max_score}") + print(f"Streak: {streak} jour{'s' if streak > 1 else ''}") + + return { + 'score': f"{total_score}/{max_score}", + 'streak': streak, + 'cards_updated': len(card_ids) + } + + +def interactive_mode(): + """Mode interactif pour logger une session.""" + print("=" * 60) + print("📝 MODE INTERACTIF - LOG SESSION") + print("=" * 60) + + # Demander les IDs de cartes + cards_input = input("\n🎯 IDs des cartes (séparées par virgules, ex: CORE-001,ACTION-006): ") + card_ids = [c.strip() for c in cards_input.split(',')] + + # Demander les scores + scores_input = input(f"📊 Scores pour {len(card_ids)} cartes (✅/⚠️/❌, séparés par virgules): ") + scores = [s.strip() for s in scores_input.split(',')] + + if len(card_ids) != len(scores): + print(f"❌ ERREUR: {len(card_ids)} cartes mais {len(scores)} scores") + return + + # Confirm + print(f"\n📋 RÉCAPITULATIF:") + for card_id, score in zip(card_ids, scores): + print(f" {card_id} → {score}") + + confirm = input("\n✅ Confirmer et logger ? (y/n): ") + if confirm.lower() != 'y': + print("❌ Annulé") + return + + # Log + log_session(card_ids, scores) + + +def main(): + parser = argparse.ArgumentParser(description='Log une session de daily check') + parser.add_argument('--cards', type=str, help='IDs de cartes séparées par virgules') + parser.add_argument('--scores', type=str, help='Scores (✅/⚠️/❌) séparés par virgules') + parser.add_argument('--interactive', action='store_true', help='Mode interactif') + parser.add_argument('--dry-run', action='store_true', help='Test sans modifier les fichiers') + + args = parser.parse_args() + + try: + if args.interactive: + interactive_mode() + elif args.cards and args.scores: + card_ids = [c.strip() for c in args.cards.split(',')] + scores = [s.strip() for s in args.scores.split(',')] + log_session(card_ids, scores, dry_run=args.dry_run) + else: + parser.print_help() + print("\n💡 Astuce: Utilise --interactive pour un usage facile") + + except Exception as e: + print(f"❌ ERREUR: {e}") + import traceback + traceback.print_exc() + import sys + sys.exit(1) + + +if __name__ == '__main__': + import sys + main()