- sauvegarde automatique de l'avancement du livre

This commit is contained in:
Tykayn 2025-08-30 18:30:32 +02:00 committed by tykayn
parent ef801609cb
commit 7ae7d5915b
7 changed files with 286 additions and 40 deletions

View file

@ -83,16 +83,31 @@ Un tag ajouté aux entêtes de chapitre permet de définir des objectifs de mots
## Suivi de progression de la rédaction ## Suivi de progression de la rédaction
Il est envisagé que chaque génération de mise à jour des statistiques remplisse un fichier csv de suivi daté afin de pouvoir voir sa progression quotidienne. Chaque génération de mise à jour des statistiques remplit un fichier CSV (`suivi_livre.csv`) de suivi daté afin de pouvoir voir sa progression quotidienne.
La génération de données statistiques peut être incluse dans une tâche cron pour ne pas avoir à faire de lancement de commande tous les jours. La génération de données statistiques peut être incluse dans une tâche cron pour ne pas avoir à faire de lancement de commande tous les jours.
Exemple de cronjob pour lancer le suivi toutes les heures, adaptez le chemin du script dans le dossier du livre concerné: Exemple de cronjob pour lancer le suivi toutes les heures, adaptez le chemin du script dans le dossier du livre concerné:
`0 * * * * /usr/bin/python3 /home/user/book_generator/mon_livre_exemple/follow_progress.py` `0 * * * * /usr/bin/python3 /home/user/book_generator/mon_livre_exemple/follow_progress.py`
Ceci alimente un fichier csv de suivi des évolutions et présente les changements de mots du jour, ainsi que depuis la semaine dernière. Ceci alimente un fichier CSV de suivi des évolutions et présente les changements de mots du jour, ainsi que depuis la semaine dernière.
Le CSV contient les décomptes de mots pour livre.org, personnages.org, le nombre de personnages, de chapitres, et de sous chapitres. Le CSV contient les décomptes de mots pour livre.org, personnages.org, le nombre de personnages, de chapitres, et de sous chapitres.
### Visualisation des données de suivi
Pour visualiser les données de suivi, utilisez le script `view_suivi_livre.py` :
```bash
python view_suivi_livre.py
```
Ce script affiche les données du fichier CSV dans un format lisible et présente des statistiques sur votre progression.
> **Important** : Le fichier `suivi_livre.csv` ne doit pas être exécuté directement avec Python. Utilisez toujours les scripts dédiés pour manipuler ces données :
> - `view_suivi_livre.py` : pour visualiser les données de suivi
> - `follow_progress.py` : pour mettre à jour et analyser les statistiques
> - `generate_dashboard.py` : pour générer un tableau de bord visuel
## Tableau de bord web ## Tableau de bord web
Un tableau de bord web interactif est disponible pour visualiser les données de votre livre. Ce tableau de bord inclut: Un tableau de bord web interactif est disponible pour visualiser les données de votre livre. Ce tableau de bord inclut:

View file

@ -0,0 +1,76 @@
#!/usr/bin/env python3
"""
Script pour ajouter un en-tête Python au début d'un fichier CSV afin qu'il
puisse être exécuté directement sans erreur et affiche un message d'aide.
"""
import os
import sys
def fix_csv_file(csv_file_path):
"""
Ajoute un en-tête Python au début du fichier CSV pour gérer l'exécution directe.
"""
if not os.path.exists(csv_file_path):
print(f"Erreur: Le fichier {csv_file_path} n'existe pas.")
return False
# Lire le contenu actuel du fichier
with open(csv_file_path, 'r') as f:
content = f.read()
# Vérifier si le fichier commence déjà par le script Python
if content.startswith('#!/usr/bin/env python3'):
print(f"Le fichier {csv_file_path} est déjà protégé.")
return True
# En-tête Python à ajouter au début du fichier
python_header = '''#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Ce fichier est un CSV contenant des données de suivi de livre.
Il n'est pas destiné à être exécuté directement comme un script Python.
Pour analyser ces données, utilisez plutôt:
- follow_progress.py: pour mettre à jour et analyser les statistiques
- generate_dashboard.py: pour générer un tableau de bord visuel
"""
import sys
def main():
print("Ce fichier est un CSV contenant des données de suivi de livre.")
print("Il n'est pas destiné à être exécuté directement comme un script Python.")
print("\\nPour analyser ces données, utilisez plutôt:")
print("- follow_progress.py: pour mettre à jour et analyser les statistiques")
print("- generate_dashboard.py: pour générer un tableau de bord visuel")
return 0
if __name__ == "__main__":
sys.exit(main())
# Les données CSV commencent ci-dessous:
'''
# Ajouter l'en-tête Python au début du fichier
with open(csv_file_path, 'w') as f:
f.write(python_header)
f.write(content)
print(f"Le fichier {csv_file_path} a été protégé contre l'exécution directe.")
return True
def main():
"""
Fonction principale.
"""
# Utiliser le fichier spécifié en argument ou par défaut 'suivi_livre.csv'
if len(sys.argv) > 1:
csv_file = sys.argv[1]
else:
csv_file = 'suivi_livre.csv'
fix_csv_file(csv_file)
if __name__ == "__main__":
main()

52
fix_csv_simple.py Normal file
View file

@ -0,0 +1,52 @@
#!/usr/bin/env python3
"""
Script pour restaurer le fichier CSV à un format simple avec juste un commentaire en tête.
"""
import os
import sys
def fix_csv_file(csv_file_path):
"""
Restaure le fichier CSV à un format simple avec juste un commentaire en tête.
"""
if not os.path.exists(csv_file_path):
print(f"Erreur: Le fichier {csv_file_path} n'existe pas.")
return False
# Lire le contenu actuel du fichier
with open(csv_file_path, 'r') as f:
content = f.read()
# Extraire les lignes de données (ignorer les lignes de commentaire et le script Python)
lines = content.split('\n')
data_lines = []
for line in lines:
# Conserver uniquement les lignes qui contiennent des données CSV (celles avec des points-virgules)
if ';' in line and not line.startswith('#'):
data_lines.append(line)
# Réécrire le fichier avec juste un commentaire simple en tête
with open(csv_file_path, 'w') as f:
f.write('# Ce fichier est un CSV et ne doit pas être exécuté directement avec Python.\n')
f.write('# Utilisez view_suivi_livre.py pour visualiser ces données.\n')
for line in data_lines:
f.write(line + '\n')
print(f"Le fichier {csv_file_path} a été restauré à un format simple.")
return True
def main():
"""
Fonction principale.
"""
# Utiliser le fichier spécifié en argument ou par défaut 'suivi_livre.csv'
if len(sys.argv) > 1:
csv_file = sys.argv[1]
else:
csv_file = 'suivi_livre.csv'
fix_csv_file(csv_file)
if __name__ == "__main__":
main()

View file

@ -46,7 +46,17 @@ def mise_a_jour_suivi(fichier_csv, fichier_livre, fichier_personnages):
# Réécrire le fichier avec un commentaire en tête # Réécrire le fichier avec un commentaire en tête
with open(fichier_csv, 'w', newline='') as f: with open(fichier_csv, 'w', newline='') as f:
f.write('# Ce fichier est un CSV et ne doit pas être exécuté directement avec Python.\n') f.write('# Ce fichier est un CSV et ne doit pas être exécuté directement avec Python.\n')
f.write('# Utilisez view_suivi_livre.py pour visualiser ces données.\n')
if content: if content:
# Si le contenu commence par un commentaire, on le supprime
# pour éviter la duplication
if content.startswith('#'):
lines = content.split('\n')
# Trouver la première ligne qui n'est pas un commentaire ou une ligne vide
for i, line in enumerate(lines):
if not line.strip().startswith('#') and line.strip():
content = '\n'.join(lines[i:])
break
f.write(content) f.write(content)
# Ajouter la nouvelle ligne # Ajouter la nouvelle ligne

View file

@ -103,7 +103,7 @@ def process_writing_progress(csv_file='suivi_livre.csv'):
""" """
try: try:
# Lire le fichier CSV avec pandas pour faciliter le traitement des dates # Lire le fichier CSV avec pandas pour faciliter le traitement des dates
df = pd.read_csv(csv_file, delimiter=';', df = pd.read_csv(csv_file, delimiter=';', comment='#',
names=['date', 'mots', 'intrigues', 'personnages', 'personnages_mots', 'chapitres', 'sous_chapitres']) names=['date', 'mots', 'intrigues', 'personnages', 'personnages_mots', 'chapitres', 'sous_chapitres'])
# Convertir les dates # Convertir les dates

View file

@ -1,68 +1,64 @@
:PROPERTIES: : PROPERTIES:
:ID: 1b3c6217-f565-42d9-b16b-db11644f6121 : ID: 1b3c6217-f565-42d9-b16b-db11644f6121
:END: : END:
#+title: livre example_livre #+title: livre example_livre
#+AUTHOR: (votre nom) #+AUTHOR:(votre nom)
#+EMAIL: votre@email.com #+EMAIL:votre@email. com
#+BEGIN_EXPORT epub #+BEGIN_EXPORT epub
:title "Mon livre" : title "Mon livre"
:author "Votre nom" : author "Votre nom"
:email "votre@email.com" : email "votre@email. com"
:language "fr" : language "fr"
:encoding "UTF-8" : encoding "UTF-8"
:subject "Littérature" : subject "Littérature"
:description "Ceci est un livre écrit en Org-mode" : description "Ceci est un livre écrit en Org-mode"
:keywords "Org-mode, livre, électronique" : keywords "Org-mode, livre, électronique"
:cover "image/cover.jpg" : cover "image/cover. jpg"
#+END_EXPORT #+END_EXPORT
* Livre nom_de_mon_livre :title: * Livre nom_de_mon_livre : title:
[[https://i.etsystatic.com/38612687/r/il/692ff8/5340918389/il_fullxfull.5340918389_fgfn.jpg]] [[https: //i. etsystatic. com/38612687/r/il/692ff8/5340918389/il_fullxfull. 5340918389_fgfn. jpg]]
#+begin_comment #+begin_comment
wololo un commentaire Wololo un commentaire
#+end_comment #+end_comment
** préambule du cul ** préambule du cul
eeeeeeeeeeeeeeeeeeeee préambule du cul eeeeeeeeeeeeeeeeee Eeeeeeeeeeeeeeeeeeeee préambule du cul eeeeeeeeeeeeeeeeee
cette partie ne devrait pas avoir de titre Cette partie ne devrait pas avoir de titre
allez hein zou zou Allez hein zou zou
** Chapitre 0 ** Chapitre 0
-------------- --------------
là non plus pas de titre à afficher Là non plus pas de titre à afficher
------------- -------------
** Chapitre 1 : title:
** Chapitre 1 :title: Celui là on doit le voir: chapitre 1 au dessus ici.
Dans un monde lointain, il y avait une île mystérieuse où les arbres avaient des feuilles qui brillaient comme des étoiles. Un jeune aventurier nommé Eryndor y arriva un jour, attiré par les légendes de l'île. Il découvrit un temple caché où les dieux anciens avaient laissé des secrets et des pouvoirs magiques.
celui là on doit le voir: chapitre 1 au dessus ici.
Dans un monde lointain, il y avait une île mystérieuse où les arbres avaient des feuilles qui brillaient comme des étoiles. Un jeune aventurier nommé Eryndor y arriva un jour, attiré par les légendes de l'île. Il découvrit un temple caché où les dieux anciens avaient laissé des secrets et des pouvoirs magiques.
*** scène d'exposition *** scène d'exposition
#+begin_comment #+begin_comment
[2024-09-06] [2024-09-06]
On devrait mettre un peu plus d'électro swing dans cette partie. On devrait mettre un peu plus d'électro swing dans cette partie.
Ce commentaire n'appraîtra pas à l'export. C'est une notre spécialement pour l'auteur. Ce commentaire n'appraîtra pas à l'export. C'est une notre spécialement pour l'auteur.
#+end_comment #+end_comment
blah blah Blah blah
bleh bob trouva un cristal qui lui permit de communiquer avec les esprits de la nature. Avec leur aide, il put vaincre les ténèbres qui menaçaient l'île et restaurer la lumière éternelle. L'île fut sauvée et Eryndor devint un héros légendaire. Bleh bob trouva un cristal qui lui permit de communiquer avec les esprits de la nature. Avec leur aide, il put vaincre les ténèbres qui menaçaient l'île et restaurer la lumière éternelle. L'île fut sauvée et Eryndor devint un héros légendaire.
1111111111111111 1111111111111111
** Chapitre 2 :title: ** Chapitre 2 : title:
2222222222222 2222222222222
Chuck fait des trucs
chuck fait des trucs
#+begin_comment #+begin_comment
oui bon heu Oui bon heu
#+end_comment #+end_comment
** Chapitre 3 : title:
** Chapitre 3 :title:
33333333333333333 33333333333333333
bobette et bob sont sur un bateau Bobette et bob sont sur un bateau

97
view_suivi_livre.py Normal file
View file

@ -0,0 +1,97 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script pour visualiser les données du fichier suivi_livre.csv.
Ce script est à utiliser à la place d'exécuter directement le fichier CSV.
"""
import csv
import sys
from datetime import datetime
import os
def display_csv_data(csv_file='suivi_livre.csv'):
"""
Affiche les données du fichier CSV de suivi de livre de manière formatée.
"""
if not os.path.exists(csv_file):
print(f"Erreur: Le fichier {csv_file} n'existe pas.")
return False
try:
# Lire le fichier CSV
with open(csv_file, 'r') as csvfile:
reader = csv.reader(csvfile, delimiter=';')
data = []
for row in reader:
# Ignorer les lignes de commentaire qui commencent par #
if row and not row[0].startswith('#'):
data.append(row)
if not data:
print("Aucune donnée trouvée dans le fichier CSV.")
return False
# Afficher un en-tête
print("\n=== DONNÉES DE SUIVI DU LIVRE ===\n")
# Afficher les colonnes
print(f"{'Date':<25} {'Mots':<8} {'Intrigues':<10} {'Personnages':<12} {'Mots Perso':<12} {'Chapitres':<10} {'Sous-Chap':<10}")
print("-" * 90)
# Afficher chaque ligne de données
for row in data:
if len(row) >= 7: # S'assurer qu'il y a assez de colonnes
date = datetime.fromisoformat(row[0]).strftime('%Y-%m-%d %H:%M:%S')
mots = row[1]
intrigues = row[2]
personnages = row[3]
personnages_mots = row[4]
chapitres = row[5]
sous_chapitres = row[6]
print(f"{date:<25} {mots:<8} {intrigues:<10} {personnages:<12} {personnages_mots:<12} {chapitres:<10} {sous_chapitres:<10}")
# Afficher quelques statistiques
if data:
last_row = data[-1]
print("\n=== STATISTIQUES ===\n")
print(f"Nombre total de mots: {last_row[1]}")
print(f"Nombre de chapitres: {last_row[5]}")
print(f"Nombre de personnages: {last_row[3]}")
# Calculer la progression depuis la première entrée
if len(data) > 1:
first_row = data[0]
mots_diff = int(last_row[1]) - int(first_row[1])
print(f"\nProgression depuis le début du suivi: {mots_diff} mots")
return True
except Exception as e:
print(f"Erreur lors de la lecture du fichier CSV: {e}")
return False
def main():
"""
Fonction principale.
"""
# Utiliser le fichier spécifié en argument ou par défaut 'suivi_livre.csv'
if len(sys.argv) > 1:
csv_file = sys.argv[1]
else:
csv_file = 'suivi_livre.csv'
if not display_csv_data(csv_file):
print("\nPour analyser ces données de manière plus approfondie, utilisez:")
print("- follow_progress.py: pour mettre à jour et analyser les statistiques")
print("- generate_dashboard.py: pour générer un tableau de bord visuel")
return 1
print("\nPour analyser ces données de manière plus approfondie, utilisez:")
print("- follow_progress.py: pour mettre à jour et analyser les statistiques")
print("- generate_dashboard.py: pour générer un tableau de bord visuel")
return 0
if __name__ == "__main__":
sys.exit(main())