mirror of
https://forge.chapril.org/tykayn/book_generator
synced 2025-06-20 01:34:43 +02:00
ajout app flask pour prévisualiser le livre
This commit is contained in:
parent
375fbb3a7a
commit
9f1b265a21
29 changed files with 4533 additions and 137 deletions
393
app.py
393
app.py
|
@ -1,80 +1,359 @@
|
|||
from flask import Flask, render_template, request, jsonify, url_for
|
||||
from flask import Flask, render_template, request, jsonify
|
||||
import os
|
||||
from datetime import datetime
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
import re
|
||||
|
||||
app = Flask(__name__, static_folder='static')
|
||||
|
||||
def count_words_in_text(text):
|
||||
# Supprime les lignes commençant par * (titres org)
|
||||
text = re.sub(r'^\*+.*$', '', text, flags=re.MULTILINE)
|
||||
# Supprime les lignes commençant par # (commentaires)
|
||||
text = re.sub(r'^#.*$', '', text, flags=re.MULTILINE)
|
||||
# Compte les mots (séquences de caractères non-espaces)
|
||||
words = re.findall(r'\S+', text)
|
||||
def load_org_file(filename):
|
||||
if os.path.exists(filename):
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
return f.read()
|
||||
return ""
|
||||
|
||||
def save_org_file(filename, content):
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
def extract_characters(content):
|
||||
characters = []
|
||||
current_character = None
|
||||
current_content = []
|
||||
|
||||
for line in content.split('\n'):
|
||||
if line.startswith('** '):
|
||||
if current_character:
|
||||
characters.append({
|
||||
'name': current_character,
|
||||
'content': '\n'.join(current_content)
|
||||
})
|
||||
current_character = line[3:].strip()
|
||||
current_content = []
|
||||
elif current_character:
|
||||
current_content.append(line)
|
||||
|
||||
if current_character:
|
||||
characters.append({
|
||||
'name': current_character,
|
||||
'content': '\n'.join(current_content)
|
||||
})
|
||||
|
||||
return characters
|
||||
|
||||
def extract_plots(content):
|
||||
plots = []
|
||||
current_plot = None
|
||||
current_content = []
|
||||
current_level = 0
|
||||
|
||||
for line in content.split('\n'):
|
||||
if line.startswith('*'):
|
||||
if current_plot:
|
||||
current_plot['content'] = '\n'.join(current_content)
|
||||
plots.append(current_plot)
|
||||
|
||||
level = len(line) - len(line.lstrip('*'))
|
||||
current_plot = {
|
||||
'name': line.lstrip('*').strip(),
|
||||
'level': level,
|
||||
'content': '',
|
||||
'subplots': []
|
||||
}
|
||||
current_content = []
|
||||
elif current_plot:
|
||||
current_content.append(line)
|
||||
|
||||
if current_plot:
|
||||
current_plot['content'] = '\n'.join(current_content)
|
||||
plots.append(current_plot)
|
||||
|
||||
# Organiser les intrigues en hiérarchie
|
||||
hierarchical_plots = []
|
||||
plot_stack = []
|
||||
|
||||
for plot in plots:
|
||||
while plot_stack and plot['level'] <= plot_stack[-1]['level']:
|
||||
plot_stack.pop()
|
||||
|
||||
if plot_stack:
|
||||
plot_stack[-1]['subplots'].append(plot)
|
||||
else:
|
||||
hierarchical_plots.append(plot)
|
||||
|
||||
plot_stack.append(plot)
|
||||
|
||||
return hierarchical_plots
|
||||
|
||||
def update_data_json():
|
||||
data = load_data()
|
||||
|
||||
# Charger et traiter les personnages
|
||||
characters_content = load_org_file('personnages.org')
|
||||
characters = extract_characters(characters_content)
|
||||
data['characters'] = characters
|
||||
|
||||
# Charger et traiter les intrigues
|
||||
plots_content = load_org_file('intrigues.org')
|
||||
plots = extract_plots(plots_content)
|
||||
data['plots'] = plots
|
||||
|
||||
save_data(data)
|
||||
return data
|
||||
|
||||
def count_words(text):
|
||||
# Ignorer les lignes de propriétés et d'export
|
||||
lines = text.split('\n')
|
||||
filtered_lines = [line for line in lines if not any(line.startswith(prefix) for prefix in
|
||||
[':PROPERTIES:', ':ID:', ':END:', '#+BEGIN_EXPORT', '#+END_EXPORT', '#+'])]
|
||||
|
||||
# Compter les mots dans les lignes filtrées
|
||||
words = ' '.join(filtered_lines).split()
|
||||
return len(words)
|
||||
|
||||
def read_org_file():
|
||||
with open('livre.org', 'r', encoding='utf-8') as f:
|
||||
return f.read()
|
||||
|
||||
def update_word_count():
|
||||
try:
|
||||
def load_data():
|
||||
if os.path.exists('data.json'):
|
||||
with open('data.json', 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
except FileNotFoundError:
|
||||
data = {}
|
||||
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
content = read_org_file()
|
||||
current_words = count_words_in_text(content)
|
||||
|
||||
# Si on a déjà un compteur pour aujourd'hui, on calcule la différence
|
||||
if today in data:
|
||||
previous_words = data[today]
|
||||
if current_words > previous_words:
|
||||
data[today] = current_words - previous_words
|
||||
else:
|
||||
data[today] = 0
|
||||
else:
|
||||
data[today] = current_words
|
||||
|
||||
return json.load(f)
|
||||
return {}
|
||||
|
||||
def save_data(data):
|
||||
with open('data.json', 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
return data[today]
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
def count_words_today():
|
||||
try:
|
||||
with open('data.json', 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
return data.get(today, 0)
|
||||
except FileNotFoundError:
|
||||
return update_word_count()
|
||||
def get_words_today():
|
||||
data = load_data()
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d')
|
||||
|
||||
# Si on n'a pas de données pour aujourd'hui, on crée une entrée
|
||||
if today not in data:
|
||||
data[today] = {
|
||||
'words': 0,
|
||||
'last_update': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
}
|
||||
save_data(data)
|
||||
|
||||
# Trouver le jour précédent le plus proche qui a des données
|
||||
previous_day = None
|
||||
previous_words = 0
|
||||
current_date = datetime.now() - timedelta(days=1)
|
||||
while current_date >= datetime.strptime('2000-01-01', '%Y-%m-%d'):
|
||||
date_str = current_date.strftime('%Y-%m-%d')
|
||||
if date_str in data:
|
||||
previous_day = date_str
|
||||
previous_words = data[date_str]['words']
|
||||
break
|
||||
current_date -= timedelta(days=1)
|
||||
|
||||
# Si on n'a pas trouvé de jour précédent, on utilise le nombre de mots actuel comme référence
|
||||
if not previous_day:
|
||||
with open('livre.org', 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
previous_words = count_words(content)
|
||||
data[yesterday] = {
|
||||
'words': previous_words,
|
||||
'last_update': (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')
|
||||
}
|
||||
save_data(data)
|
||||
|
||||
# Calculer la progression en différence avec le jour précédent
|
||||
words_today = data[today]['words']
|
||||
progress = max(0, words_today - previous_words)
|
||||
|
||||
return progress
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
content = read_org_file()
|
||||
words_today = count_words_today()
|
||||
return render_template('index.html', content=content, words_today=words_today)
|
||||
with open('livre.org', 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
words_today = get_words_today()
|
||||
data = update_data_json()
|
||||
return render_template('index.html', content=content, words_today=words_today,
|
||||
characters=data.get('characters', []), plots=data.get('plots', []))
|
||||
|
||||
@app.route('/update', methods=['POST'])
|
||||
def update():
|
||||
new_content = request.form.get('content')
|
||||
with open('livre.org', 'w', encoding='utf-8') as f:
|
||||
f.write(new_content)
|
||||
content = request.form.get('content', '')
|
||||
editor_title = request.form.get('editor_title', '')
|
||||
|
||||
# Met à jour le compteur de mots
|
||||
words_today = update_word_count()
|
||||
return jsonify({'status': 'success', 'words_today': words_today})
|
||||
# Déterminer le fichier de destination en fonction du titre de l'éditeur
|
||||
if 'Personnage:' in editor_title:
|
||||
current_file = 'personnages.org'
|
||||
elif 'Intrigue:' in editor_title:
|
||||
current_file = 'intrigues.org'
|
||||
elif editor_title == 'Intrigues':
|
||||
current_file = 'intrigues.org'
|
||||
else:
|
||||
current_file = 'livre.org'
|
||||
|
||||
with open(current_file, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
# Mettre à jour le nombre de mots pour aujourd'hui si c'est le fichier principal
|
||||
if current_file == 'livre.org':
|
||||
data = load_data()
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
data[today] = {
|
||||
'words': count_words(content),
|
||||
'last_update': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
}
|
||||
save_data(data)
|
||||
|
||||
return jsonify({'words_today': get_words_today()})
|
||||
|
||||
@app.route('/words_today')
|
||||
def get_words_today():
|
||||
return jsonify({'words': count_words_today()})
|
||||
def words_today():
|
||||
return jsonify({'words': get_words_today()})
|
||||
|
||||
@app.route('/progress_data')
|
||||
def progress_data():
|
||||
data = load_data()
|
||||
# Trier les dates
|
||||
dates = sorted(data.keys(), reverse=True)
|
||||
# Prendre les 7 derniers jours
|
||||
dates = dates[:7]
|
||||
|
||||
# Préparer les données pour le graphique
|
||||
chart_data = {
|
||||
'labels': [],
|
||||
'words': [],
|
||||
'progress': []
|
||||
}
|
||||
|
||||
for date in dates:
|
||||
chart_data['labels'].append(date)
|
||||
if date in data and 'words' in data[date]:
|
||||
chart_data['words'].append(data[date]['words'])
|
||||
else:
|
||||
chart_data['words'].append(0)
|
||||
|
||||
# Calculer la progression entre chaque jour
|
||||
for i in range(len(chart_data['words'])):
|
||||
if i < len(chart_data['words']) - 1:
|
||||
progress = max(0, chart_data['words'][i] - chart_data['words'][i + 1])
|
||||
else:
|
||||
progress = 0
|
||||
chart_data['progress'].append(progress)
|
||||
|
||||
return jsonify(chart_data)
|
||||
|
||||
@app.route('/update_character', methods=['POST'])
|
||||
def update_character():
|
||||
name = request.form.get('name')
|
||||
content = request.form.get('content')
|
||||
|
||||
characters_content = load_org_file('personnages.org')
|
||||
characters = extract_characters(characters_content)
|
||||
|
||||
# Mettre à jour ou ajouter le personnage
|
||||
found = False
|
||||
for char in characters:
|
||||
if char['name'] == name:
|
||||
char['content'] = content
|
||||
found = True
|
||||
break
|
||||
|
||||
if not found:
|
||||
characters.append({
|
||||
'name': name,
|
||||
'content': content
|
||||
})
|
||||
|
||||
# Sauvegarder le fichier
|
||||
new_content = []
|
||||
for char in characters:
|
||||
new_content.append(f"* {char['name']}")
|
||||
new_content.append(char['content'])
|
||||
|
||||
save_org_file('personnages.org', '\n'.join(new_content))
|
||||
update_data_json()
|
||||
|
||||
return jsonify({'status': 'success'})
|
||||
|
||||
@app.route('/update_plot', methods=['POST'])
|
||||
def update_plot():
|
||||
name = request.form.get('name')
|
||||
content = request.form.get('content')
|
||||
|
||||
plots_content = load_org_file('intrigues.org')
|
||||
plots = extract_plots(plots_content)
|
||||
|
||||
# Mettre à jour ou ajouter l'intrigue
|
||||
found = False
|
||||
for plot in plots:
|
||||
if plot['name'] == name:
|
||||
plot['content'] = content
|
||||
found = True
|
||||
break
|
||||
|
||||
if not found:
|
||||
plots.append({
|
||||
'name': name,
|
||||
'content': content
|
||||
})
|
||||
|
||||
# Sauvegarder le fichier
|
||||
new_content = []
|
||||
for plot in plots:
|
||||
new_content.append(f"* {plot['name']}")
|
||||
new_content.append(plot['content'])
|
||||
|
||||
save_org_file('intrigues.org', '\n'.join(new_content))
|
||||
update_data_json()
|
||||
|
||||
return jsonify({'status': 'success'})
|
||||
|
||||
@app.route('/get_character', methods=['POST'])
|
||||
def get_character():
|
||||
name = request.form.get('name')
|
||||
characters_content = load_org_file('personnages.org')
|
||||
characters = extract_characters(characters_content)
|
||||
|
||||
for char in characters:
|
||||
if char['name'] == name:
|
||||
return jsonify({
|
||||
'content': f"* {char['name']}\n{char['content']}"
|
||||
})
|
||||
|
||||
return jsonify({'error': 'Personnage non trouvé'}), 404
|
||||
|
||||
@app.route('/get_plot', methods=['POST'])
|
||||
def get_plot():
|
||||
name = request.form.get('name')
|
||||
plots_content = load_org_file('intrigues.org')
|
||||
plots = extract_plots(plots_content)
|
||||
|
||||
for plot in plots:
|
||||
if plot['name'] == name:
|
||||
return jsonify({
|
||||
'content': f"* {plot['name']}\n{plot['content']}"
|
||||
})
|
||||
|
||||
return jsonify({'error': 'Intrigue non trouvée'}), 404
|
||||
|
||||
@app.route('/get_book')
|
||||
def get_book():
|
||||
content = load_org_file('livre.org')
|
||||
return jsonify({'content': content})
|
||||
|
||||
@app.route('/get_plots_file')
|
||||
def get_plots_file():
|
||||
try:
|
||||
with open('intrigues.org', 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
return jsonify({'content': content})
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/get_characters_file')
|
||||
def get_characters_file():
|
||||
try:
|
||||
with open('personnages.org', 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
return jsonify({'content': content})
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Initialise le compteur de mots au démarrage si nécessaire
|
||||
count_words_today()
|
||||
app.run(debug=True)
|
Loading…
Add table
Add a link
Reference in a new issue