Compare commits

..

No commits in common. "20753789c97a22214a7bb4cd3518a318664c0396" and "c7383ed6ef71d6f6ab886934ed0a8ea04efba307" have entirely different histories.

11 changed files with 31 additions and 222 deletions

View File

@ -34,14 +34,11 @@ Afin d'avoir une structure qui aura visuellement du sens pour l'autrice du livre
Votre livre peut contenir des médias, nous vous invitons à les placer dans le dossier "assets".
Le dossier "inspirations" est destiné à avoir des images, des médias, des documents divers, une bibliographie, c'est toujours utile de référencer ses inspirations pour clarifier ce que l'on aimerait raconter.
## Personnages
Donnez des alias à vos personnages dans la ligne prévue à cet effet afin de comptabiliser leurs mentions dans le script find_characters_in_book.py
## Intrigues
Les intrigues sont des arcs narratifs qui peuvent se superposer dans votre histoire.
Pour avoir cette vision des superpositions, le script `make_intrigues_to_csv.py` liste les entêtes et recherche si elles contiennent deux nombres séparés par un tiret.
Par exemple :
`** l'intrigue bidule chose 4-9`
** l'intrigue bidule chose 4-9
Indique que l'on souhaite que cette intrigue débute dans la partie 4 et se termine dans la partie 9.
Sans information de numérotation, on part du principe qu'une intrigue dure 1 partie de l'histoire, dans l'ordre des intrigues.
@ -55,8 +52,7 @@ Permettent de transformer votre livre en produit distribuable: ebook, html, pdf,
### Génération de plan de livre
`python structure_generator.py`
Génère un plan de chapitres selon les nombres de chapitres, de sous parties, et d'objectif de mots par section donnés.
Il ne reste plus qu'à copier le texte donné dans livre.org ou a utliser la sortie du script pour écrire dans un fichier.
Il ne reste plus qu'à copier le texte donné dans livre.org
### Conversion du livre
Conversion en epub, html, et pdf grâce à pandoc.
@ -81,18 +77,11 @@ Vous pouvez modifier cet objectif dans `stats_chapitres.py` puis lancer la mise
Un tag ajouté aux entêtes de chapitre permet de définir des objectifs de mots.
:target_500: définit une cible à 500 mots, :target_1200: défniit la cible à 1200. Cela permettra au générateur de statistiques d'affiner son avancée plus finement. Ce sont des indicateurs, dans la réalité les auteurs écrivent leurs chapitres avec des volumes très variables.
## 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.
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.
Le CSV contient les décomptes de mots pour livre.org, personnages.org, le nombre de personnages, de chapitres, et de sous chapitres.
# Licence
AGPLv3+

View File

@ -21,18 +21,14 @@
** Préface :title:
** Introduction :title:
** Chapitre 1 :title:
présentation de bob.
*** Chapitre 1 - Partie 1
*** Chapitre 1 - Partie 2
*** Chapitre 1 - Partie 3
** Chapitre 2 :title:
présentation de chuck norris.
présentation de bobette.
*** Chapitre 2 - Partie 1
*** Chapitre 2 - Partie 2
*** Chapitre 2 - Partie 3
** Chapitre 3 :title:
bob et bobette sont bien plus stylés que le roux.
*** Chapitre 3 - Partie 1
*** Chapitre 3 - Partie 2
*** Chapitre 3 - Partie 3

View File

@ -10,18 +10,15 @@
- objectifs:
- conflits:
- évolution:
- alias: Bob l'éponge, SpongeBob
** chuck norris
- nom:
- personnalité:
- objectifs:
- conflits:
- évolution:
- alias: le roux; celui dont on ne doit pas prononcer le nom
** bobette
- nom:
- personnalité:
- objectifs:
- conflits:
- évolution:
- alias:

View File

@ -1 +0,0 @@

View File

@ -4,68 +4,38 @@
# les personnages que l'on recherche dans le livre ne sont pas mentionnés dans la ligne d'entête; mais dans les lignes entre deux entêtes, dans les corps de texte
import csv
import re
import argparse
import os
# Ajouter un argument pour le chemin du dossier contenant le fichier livre.org
parser = argparse.ArgumentParser(description='Rechercher les occurrences de personnages dans un fichier Org-mode.')
parser.add_argument('dossier', nargs='?', help='Le chemin du dossier contenant le fichier livre.org. Si aucun dossier n\'est spécifié, le dossier courant sera utilisé.', default=os.getcwd())
args = parser.parse_args()
# Concaténer le chemin du dossier et le nom du fichier livre.org
fichier_livre = f"{args.dossier}/livre.org"
# Remplacer par les chemins vers les fichiers Org-mode
fichier_personnages = f"{args.dossier}personnages.org"
fichier_personnages = 'personnages.org'
fichier_livre = 'livre.org'
# Expressions régulières pour extraire les noms des personnages, les alias et les titres des chapitres
# Expressions régulières pour extraire les noms des personnages et les titres des chapitres
regex_personnage = r"\*\* (.*)"
regex_alias = r"\s*- alias:\s*(.*?)\s*$"
regex_chapitre = r'\*\* (.+)'
# Dictionnaire pour stocker les occurrences de personnages dans chaque chapitre
occurrences_personnages = {}
alias_separator=";"
def extract_character_info(character_line):
match = re.search(regex_personnage, character_line)
if match:
character = match.group(1)
aliases = []
# Ouvrir le fichier personnages.org et extraire les noms des personnages
with open(fichier_personnages, 'r', encoding='utf-8') as fichier_personnages:
personnages = [re.sub( "\*\* ","",ligne.strip()) for ligne in fichier_personnages if re.match(regex_personnage, ligne)]
# Extraire les alias du caractère
match_alias = re.search(regex_alias, character_line)
if match_alias:
aliases = [alias.strip() for alias in match_alias.group(1).split(alias_separator)]
return character, aliases
return None, []
# Ouvrir le fichier personnages.org et extraire les noms des personnages et leurs alias
print('personnages: ', personnages)
def contains_any_of_these_words(line: str, words: list[str]) -> bool:
for word in words:
if word in line:
return True
return False
with open(fichier_personnages, 'r', encoding='utf-8') as fichier_personnages:
personnages = {}
for ligne in fichier_personnages:
character, aliases = extract_character_info(ligne)
if character:
personnages[character] = aliases
print('personnages: ', personnages.keys())
# Ouvrir le fichier livre.org et le fichier CSV
with open(fichier_livre, 'r', encoding='utf-8') as livre, open(f"{args.dossier}/occurrences_personnages.csv", 'w', newline='', encoding='utf-8') as fichier_csv:
with open(fichier_livre, 'r', encoding='utf-8') as livre, open('occurrences_personnages.csv', 'w', newline='', encoding='utf-8') as fichier_csv:
content = livre.read()
csv_writer = csv.writer(fichier_csv)
# Écrire les en-têtes dans le fichier CSV
csv_writer.writerow(['Chapitre'] + list(personnages.keys()))
occurrences_chapitre = {personnage: 0 for personnage in personnages.keys()}
csv_writer.writerow(['Chapitre'] + personnages)
occurrences_chapitre = {personnage: 0 for personnage in personnages}
chapitre = '(chapitre not found)'
# Parcourir chaque ligne du fichier livre.org
@ -77,11 +47,12 @@ with open(fichier_livre, 'r', encoding='utf-8') as livre, open(f"{args.dossier}/
chapitre = re.sub( ":title:", "", chapitre)
print(chapitre)
# Initialiser le dictionnaire d'occurrences pour chaque chapitre
occurrences_chapitre = {personnage: 0 for personnage in personnages.keys()}
occurrences_chapitre = {personnage: 0 for personnage in personnages}
# Parcourir chaque personnage et rechercher son nom ou ses alias dans la ligne
for personnage, aliases in personnages.items():
if personnage.lower() in ligne.lower() or any(alias.lower() in ligne.lower() for alias in aliases):
# Parcourir chaque personnage et rechercher son nom dans la ligne
for personnage in personnages:
if personnage in ligne:
occurrences_chapitre[personnage] += 1
print(chapitre,' - ',personnage,' : ', ligne)
# Ajouter les occurrences du chapitre au dictionnaire global
@ -89,5 +60,4 @@ with open(fichier_livre, 'r', encoding='utf-8') as livre, open(f"{args.dossier}/
# Écrire les occurrences des personnages dans le fichier CSV
for chapitre, occurrences in occurrences_personnages.items():
csv_writer.writerow([chapitre] + [occurrences[personnage] for personnage in personnages.keys()])
csv_writer.writerow([chapitre] + [occurrences[personnage] for personnage in personnages])

View File

@ -1,102 +0,0 @@
# met à jour un fichier de suivi pour chaque livre
# le suivi se fait dans un fichier csv où chaque ligne est un compte rendu de statistiques du livre
# colonnes du csv: date; mots; intrigues; personnages; personnages_mots;
import csv
from datetime import date, timedelta, datetime
def mise_a_jour_suivi(fichier_csv, fichier_livre, fichier_personnages):
# Lire le fichier livre.org
with open(fichier_livre, 'r') as f:
contenu_livre = f.read()
mots_livre = len(contenu_livre.split())
chapitres = contenu_livre.count('* ')
sous_chapitres = contenu_livre.count('** ') + contenu_livre.count('*** ') + contenu_livre.count('**** ')
# Lire le fichier personnages.org
with open(fichier_personnages, 'r') as f:
contenu_personnages = f.read()
personnages_mots = len(contenu_personnages.split())
personnages = contenu_personnages.count('* ')
# Récupérer les valeurs pour les autres colonnes
intrigues = 5
# Mettre à jour le fichier de suivi
with open(fichier_csv, 'a', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter=';')
now = datetime.now()
ligne = [now.isoformat(), mots_livre, intrigues, personnages, personnages_mots, chapitres, sous_chapitres]
writer.writerow(ligne)
# Exemple d'utilisation
fichier_csv ='suivi_livre.csv'
fichier_livre = 'livre.org'
fichier_personnages = 'personnages.org'
def analyse_csv(fichier_csv):
with open(fichier_csv, 'r') as csvfile:
reader = csv.reader(csvfile, delimiter=';')
donnees = list(reader)
# Récupérer les dates et les nombres de mots
dates = [datetime.fromisoformat(donnee[0]).date() for donnee in donnees]
mots = [int(donnee[1]) for donnee in donnees]
# Récupérer la date du jour
aujourd_hui = date.today()
oldest_count=0
hier = aujourd_hui - timedelta(days=1)
semaine_derniere = aujourd_hui - timedelta(days=7)
mois_dernier = date(aujourd_hui.year, aujourd_hui.month - 1, aujourd_hui.day)
# Récupérer la valeur des mots la plus récente parmi celles de la date du jour
mots_aujourd_hui = 0
mots_aujourd_hui_start = 0
most_recent = 0
# print("suivis: ",len(dates))
most_recent = mots[len(dates)-1]
for i, date_ in enumerate(dates):
# trouver le premier décompte supérieur à 0
if mots[i] > 0 and oldest_count == 0:
oldest_count = mots[i]
# print('oldest: ',oldest_count, " mots")
if date_ == aujourd_hui:
if mots_aujourd_hui_start == 0:
mots_aujourd_hui_start = mots[i]
print('au début du jour:' , mots_aujourd_hui_start)
if date_ == aujourd_hui:
mots_aujourd_hui = mots[i]
# Récupérer la valeur des mots la plus récente du jour précédent
mots_hier = 0
for i, date_ in enumerate(dates):
if date_ == hier:
mots_hier = mots[i]
break
# Récupérer la valeur des mots la plus récente de la semaine dernière
mots_semaine_derniere = 0
for i, date_ in enumerate(dates):
if semaine_derniere <= date_ < aujourd_hui:
mots_semaine_derniere = mots[i]
break
# Compter le nombre de mots changés aujourd'hui
mots_changés_aujourd_hui = most_recent - mots_aujourd_hui_start
# Compter le nombre de mots changés depuis la date la plus récente dans la semaine dernière
mots_changés_semaine_derniere = mots_aujourd_hui_start - mots_semaine_derniere
# Afficher le résultat
print("Nombres de mots changés aujourd'hui : ", mots_changés_aujourd_hui)
print("Nombres de mots changés depuis la date la plus récente dans la semaine dernière : ", mots_changés_semaine_derniere)
print("Total : ", most_recent," mots")
mise_a_jour_suivi(fichier_csv, fichier_livre, fichier_personnages)
analyse_csv(fichier_csv)

View File

@ -10,22 +10,6 @@
extension="org" # ou md
fi
add_path_to_config() {
local path=$1
local config_file="config/books_path.txt"
if [ -f "$config_file" ]; then
if grep -q "^${path}$" "$config_file"; then
echo "Le chemin '${path}' existe déjà dans le fichier de configuration."
else
echo "$(pwd)/$path" >> "$config_file"
echo "Le chemin '${path}' a été ajouté au fichier de configuration."
fi
else
echo "Le fichier de configuration '${config_file}' n'existe pas."
touch $config_file
fi
}
function generate_uuid() {
uuid=$(cat /proc/sys/kernel/random/uuid)
echo "$uuid";
@ -72,8 +56,5 @@
echo $nom_du_livre | xargs -I{} sed -i 's|BOOK_TITLE|{}|g' $nom_du_livre/taches_$nom_du_livre.org
exa -l $nom_du_livre
add_path_to_config $nom_du_livre
echo "fichiers du livre $nom_du_livre créé"
exit 0

View File

@ -1,5 +1,4 @@
#!/bin/bash
# ajout du décompte des informations pour chaque livre
#sauvegarde de tous les changements dans le dossier actuel
# sauvegarde de tous les changements dans le dossier actuel
git add .
git commit -m ":zap: - sauvegarde automatique de l'avancement du livre"

View File

@ -1,17 +1,5 @@
#####################
# génère une structure à copier dans un nouveau fichier livre.org
# ce script ne remplit pas directement un fichier pour éviter les écrasements trop soudains.
# Exemple d'exécution:
#
# python structure_generator.py --number_chapters 7 --number_parts 2 --objective_words 600 --objective_chapter 1800
#
#####################
#
# Si vous voulez créer directement un fichier livre sans le reste de ce que fabriquerait generate_book.sh:
#
# python structure_generator.py > mon_livre_généré.org
#
#####################
# python script.py --number_chapters 7 --number_parts 2 --objective_words 600 --objective_chapter 1800
import argparse
parser = argparse.ArgumentParser()

View File

@ -5,4 +5,3 @@ python3 find_characters_in_book.py
python3 stats_chapitres.py
python3 make_intrigues_to_csv.py
python3 gantt_parser.py
python3 follow_progress.py

View File

@ -8,22 +8,15 @@ echo "mise à jour du dossier $1 sans modifier les contenus Org"
dossier=$1
if ! [ -d $dossier ]; then
echo "le dossier $dossier n'existe pas, oh noes! ajoutez le en argument à ce script: \n bash update_ebook.sh /$USER/Nextcloud/textes/livre_bidule"
else
# on supprime les scripts existants
rm "$dossier/*.py"
rm "$dossier/*.sh"
rm "$dossier/*.css"
# on met les nouvelles versions
cp Makefile "$dossier/"
if ! [ -d $dossier ]; then
echo "le dossier $dossier n'existe pas, oh noes!"
else
cp *.py "$dossier/"
cp *.sh "$dossier/"
cp *.css "$dossier/"
cp README.md "$dossier/"
cp LICENSE "$dossier/"
if ! [ -d $dossier/.git ]; then
cd $dossier
git init