⚡ - sauvegarde automatique de l'avancement du livre
This commit is contained in:
parent
ef801609cb
commit
7ae7d5915b
7 changed files with 286 additions and 40 deletions
19
README.md
19
README.md
|
@ -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
|
||||
|
||||
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.
|
||||
|
||||
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`
|
||||
|
||||
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.
|
||||
|
||||
### 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
|
||||
|
||||
Un tableau de bord web interactif est disponible pour visualiser les données de votre livre. Ce tableau de bord inclut:
|
||||
|
|
76
fix_csv_execution_improved.py
Normal file
76
fix_csv_execution_improved.py
Normal 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
52
fix_csv_simple.py
Normal 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()
|
|
@ -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
|
||||
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('# Utilisez view_suivi_livre.py pour visualiser ces données.\n')
|
||||
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)
|
||||
|
||||
# Ajouter la nouvelle ligne
|
||||
|
|
|
@ -103,7 +103,7 @@ def process_writing_progress(csv_file='suivi_livre.csv'):
|
|||
"""
|
||||
try:
|
||||
# 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'])
|
||||
|
||||
# Convertir les dates
|
||||
|
|
70
livre.org
70
livre.org
|
@ -1,68 +1,64 @@
|
|||
:PROPERTIES:
|
||||
:ID: 1b3c6217-f565-42d9-b16b-db11644f6121
|
||||
:END:
|
||||
: PROPERTIES:
|
||||
: ID: 1b3c6217-f565-42d9-b16b-db11644f6121
|
||||
: END:
|
||||
#+title: livre example_livre
|
||||
#+AUTHOR: (votre nom)
|
||||
#+EMAIL: votre@email.com
|
||||
#+AUTHOR:(votre nom)
|
||||
#+EMAIL:votre@email. com
|
||||
#+BEGIN_EXPORT epub
|
||||
:title "Mon livre"
|
||||
:author "Votre nom"
|
||||
:email "votre@email.com"
|
||||
:language "fr"
|
||||
:encoding "UTF-8"
|
||||
:subject "Littérature"
|
||||
:description "Ceci est un livre écrit en Org-mode"
|
||||
:keywords "Org-mode, livre, électronique"
|
||||
:cover "image/cover.jpg"
|
||||
: title "Mon livre"
|
||||
: author "Votre nom"
|
||||
: email "votre@email. com"
|
||||
: language "fr"
|
||||
: encoding "UTF-8"
|
||||
: subject "Littérature"
|
||||
: description "Ceci est un livre écrit en Org-mode"
|
||||
: keywords "Org-mode, livre, électronique"
|
||||
: cover "image/cover. jpg"
|
||||
#+END_EXPORT
|
||||
|
||||
* Livre nom_de_mon_livre :title:
|
||||
[[https://i.etsystatic.com/38612687/r/il/692ff8/5340918389/il_fullxfull.5340918389_fgfn.jpg]]
|
||||
* Livre nom_de_mon_livre : title:
|
||||
[[https: //i. etsystatic. com/38612687/r/il/692ff8/5340918389/il_fullxfull. 5340918389_fgfn. jpg]]
|
||||
|
||||
#+begin_comment
|
||||
wololo un commentaire
|
||||
Wololo un commentaire
|
||||
#+end_comment
|
||||
|
||||
** préambule du cul
|
||||
eeeeeeeeeeeeeeeeeeeee préambule du cul eeeeeeeeeeeeeeeeee
|
||||
cette partie ne devrait pas avoir de titre
|
||||
allez hein zou zou
|
||||
|
||||
Eeeeeeeeeeeeeeeeeeeee préambule du cul eeeeeeeeeeeeeeeeee
|
||||
Cette partie ne devrait pas avoir de titre
|
||||
Allez hein zou zou
|
||||
|
||||
** 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
|
||||
#+begin_comment
|
||||
[2024-09-06]
|
||||
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.
|
||||
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.
|
||||
#+end_comment
|
||||
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.
|
||||
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.
|
||||
|
||||
1111111111111111
|
||||
** Chapitre 2 :title:
|
||||
** Chapitre 2 : title:
|
||||
2222222222222
|
||||
|
||||
|
||||
chuck fait des trucs
|
||||
Chuck fait des trucs
|
||||
|
||||
|
||||
#+begin_comment
|
||||
oui bon heu
|
||||
Oui bon heu
|
||||
#+end_comment
|
||||
|
||||
|
||||
** Chapitre 3 :title:
|
||||
** Chapitre 3 : title:
|
||||
33333333333333333
|
||||
bobette et bob sont sur un bateau
|
||||
Bobette et bob sont sur un bateau
|
||||
|
|
97
view_suivi_livre.py
Normal file
97
view_suivi_livre.py
Normal 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())
|
Loading…
Add table
Add a link
Reference in a new issue