Modification de la détection de l'environnement
This commit is contained in:
parent
9491dd076f
commit
4ae0fbfdb3
2
.gitignore
vendored
2
.gitignore
vendored
@ -23,6 +23,8 @@ HTML/
|
||||
# Ignorer données Fiches (adapté à ton projet)
|
||||
Instructions.md
|
||||
Fiches/
|
||||
HTML/
|
||||
static/Fiches/
|
||||
|
||||
# Autres spécifiques si besoin
|
||||
.DS_Store
|
||||
|
||||
24
README.md
24
README.md
@ -34,17 +34,33 @@ Le fichier **.env.local** qui contient GITEA_TOKEN n'est pas dans le dépôt car
|
||||
|
||||
Pour l'environnement de pré-production, (https://fabnum-dev.peccini.fr)[https://fabnum-dev.peccini.fr] :
|
||||
|
||||
ENV=dev
|
||||
ENV_CODE = "dev"
|
||||
PORT=8502
|
||||
DOT_FILE = "schema.txt"
|
||||
GITEA_URL = "https://fabnum-git.peccini.fr/api/v1"
|
||||
ORGANISATION = "fabnum"
|
||||
DEPOT_FICHES = "fiches"
|
||||
DEPOT_CODE = "code"
|
||||
ID_PROJET = "3"
|
||||
INSTRUCTIONS = "Instructions.md"
|
||||
FICHE_IHH = "Fiches/Criticités/Fiche technique IHH.md"
|
||||
FICHE_ICS = "Fiches/Criticités/Fiche technique ICS.md"
|
||||
FICHE_ISG = "Fiches/Criticités/Fiche technique ISG.md"
|
||||
FICHE_IVC = "Fiches/Criticités/Fiche technique IVC.md"
|
||||
|
||||
Pour l'environnement de production, (https://fabnum.peccini.fr)[https://fabnum.peccini.fr], le fichier est identique sauf pour :
|
||||
|
||||
ENV=public
|
||||
PORT=8501
|
||||
|
||||
La différence entre les deux environnements se fait au travers de la configuration du proxy Nginx (ici celle de dev ; il suffit de changer dev en public pour l'environnement de production) :
|
||||
|
||||
# Ajout d'un en-tête personnalisé pour indiquer l'environnement
|
||||
add_header X-Environment "dev" always;
|
||||
# Transmettre l'en-tête d'environnement au backend
|
||||
proxy_set_header X-Environment "dev";
|
||||
|
||||
Cette configuration est utilisée par config.py.
|
||||
|
||||
dev et public sont les deux branches officielles du dépôt.
|
||||
|
||||
L'application se lance simplement sous la forme :
|
||||
@ -66,12 +82,10 @@ Pour automatiser le lancement, il est intégré dans systemd :
|
||||
[Service]
|
||||
User=fabnum
|
||||
WorkingDirectory=/home/fabnum/fabnum-dev
|
||||
ExecStart=/home/fabnum/fabnum-dev/venv/bin/streamlit run /home/fabnum/fabnum-dev/fa
|
||||
bnum.py
|
||||
ExecStart=/home/fabnum/fabnum-dev/venv/bin/streamlit run /home/fabnum/fabnum-dev/fabnum.py --server.port 8502
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
SELinuxContext=system_u:system_r:httpd_t:s0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
200
batch_generate_fiches.py
Normal file
200
batch_generate_fiches.py
Normal file
@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import re
|
||||
import yaml
|
||||
import requests
|
||||
import argparse
|
||||
import logging
|
||||
|
||||
# Import des fonctions de génération
|
||||
from app.fiches.generer import (
|
||||
generer_fiche
|
||||
)
|
||||
from app.fiches.utils.fiche_utils import load_seuils
|
||||
from utils.gitea import charger_arborescence_fiches
|
||||
from config import GITEA_TOKEN, FICHES_CRITICITE
|
||||
|
||||
# Configuration du logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler("batch_generation.log"),
|
||||
logging.StreamHandler()
|
||||
]
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def get_fiche_type(md_source):
|
||||
"""Extrait le type de fiche depuis le frontmatter YAML."""
|
||||
front_match = re.match(r"(?s)^---\n(.*?)\n---\n", md_source)
|
||||
if not front_match:
|
||||
return "autre"
|
||||
|
||||
context = yaml.safe_load(front_match.group(1))
|
||||
return context.get("type_fiche", "autre")
|
||||
|
||||
def get_indice_court(md_source):
|
||||
"""Extrait l'indice court depuis le frontmatter YAML."""
|
||||
front_match = re.match(r"(?s)^---\n(.*?)\n---\n", md_source)
|
||||
if not front_match:
|
||||
return None
|
||||
|
||||
context = yaml.safe_load(front_match.group(1))
|
||||
return context.get("indice_court")
|
||||
|
||||
def batch_generate_fiches(output_dir="", force_regenerate=False):
|
||||
"""Génère toutes les fiches en batch en suivant un ordre de priorité."""
|
||||
# Assurer que les répertoires de sortie existent
|
||||
if output_dir:
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
# Toujours créer les répertoires nécessaires
|
||||
os.makedirs(os.path.join("Fiches"), exist_ok=True)
|
||||
os.makedirs(os.path.join("HTML"), exist_ok=True)
|
||||
os.makedirs(os.path.join("static", "Fiches"), exist_ok=True)
|
||||
|
||||
# Charger les seuils
|
||||
try:
|
||||
seuils = load_seuils("assets/config.yaml")
|
||||
logger.info("Seuils chargés avec succès")
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors du chargement des seuils: {e}")
|
||||
return
|
||||
|
||||
# Charger l'arborescence des fiches
|
||||
try:
|
||||
arborescence = charger_arborescence_fiches()
|
||||
logger.info(f"Arborescence chargée: {len(arborescence)} dossiers trouvés")
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors du chargement de l'arborescence: {e}")
|
||||
return
|
||||
|
||||
# Créer une liste de toutes les fiches avec leurs informations
|
||||
toutes_fiches = []
|
||||
for dossier, fiches in arborescence.items():
|
||||
for fiche in fiches:
|
||||
toutes_fiches.append({
|
||||
"dossier": dossier,
|
||||
"nom": fiche["nom"],
|
||||
"download_url": fiche["download_url"],
|
||||
"type": fiche.get("type", "autre")
|
||||
})
|
||||
|
||||
logger.info(f"Total de {len(toutes_fiches)} fiches à traiter")
|
||||
|
||||
# Organisation des fiches par type pour respecter l'ordre de priorité
|
||||
fiches_par_type = {
|
||||
"criticite": [],
|
||||
"assemblage": [],
|
||||
"fabrication": [],
|
||||
"minerai": [],
|
||||
"autre": []
|
||||
}
|
||||
|
||||
# Télécharger et catégoriser les fiches
|
||||
headers = {"Authorization": f"token {GITEA_TOKEN}"}
|
||||
|
||||
# Création des listes spécifiques pour faciliter le traitement ordonné
|
||||
fiches_criticite = []
|
||||
autres_fiches = []
|
||||
|
||||
# Première étape : identifier les fiches de criticité
|
||||
logger.info("Identification des fiches de criticité...")
|
||||
for fiche in toutes_fiches:
|
||||
# Vérifier si c'est une fiche de criticité par deux méthodes
|
||||
est_criticite = False
|
||||
|
||||
# Méthode 1: vérifier par le nom du fichier
|
||||
if fiche["nom"] in FICHES_CRITICITE:
|
||||
est_criticite = True
|
||||
logger.info(f"Fiche de criticité identifiée par nom: {fiche['nom']}")
|
||||
|
||||
# Méthode 2: vérifier par le dossier
|
||||
elif fiche["dossier"] == "Criticités":
|
||||
est_criticite = True
|
||||
logger.info(f"Fiche de criticité identifiée par dossier: {fiche['nom']}")
|
||||
|
||||
if est_criticite:
|
||||
fiches_criticite.append(fiche)
|
||||
else:
|
||||
autres_fiches.append(fiche)
|
||||
|
||||
# Traiter d'abord les fiches de criticité
|
||||
logger.info(f"Traitement prioritaire des fiches de criticité ({len(fiches_criticite)} fiches)")
|
||||
criticite_count = 0
|
||||
|
||||
for fiche in fiches_criticite:
|
||||
try:
|
||||
# Télécharger la fiche de criticité
|
||||
reponse = requests.get(fiche["download_url"], headers=headers)
|
||||
reponse.raise_for_status()
|
||||
md_source = reponse.text
|
||||
|
||||
# Générer immédiatement la fiche de criticité
|
||||
logger.info(f"Génération prioritaire de la fiche de criticité: {fiche['dossier']}/{fiche['nom']}")
|
||||
generer_fiche(md_source, fiche["dossier"], fiche["nom"], seuils)
|
||||
|
||||
# Ajouter à la liste pour le décompte
|
||||
fiches_par_type["criticite"].append(fiche)
|
||||
criticite_count += 1
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors de la génération de la fiche de criticité {fiche['nom']}: {e}")
|
||||
|
||||
logger.info(f"{criticite_count} fiches de criticité générées")
|
||||
|
||||
# Maintenant catégoriser et traiter les fiches restantes (non-criticité)
|
||||
for fiche in autres_fiches:
|
||||
try:
|
||||
# Télécharger le contenu pour déterminer le type
|
||||
reponse = requests.get(fiche["download_url"], headers=headers)
|
||||
reponse.raise_for_status()
|
||||
md_source = reponse.text
|
||||
|
||||
# Déterminer le type
|
||||
type_fiche = get_fiche_type(md_source)
|
||||
if type_fiche in fiches_par_type:
|
||||
fiches_par_type[type_fiche].append({**fiche, "md_source": md_source})
|
||||
else:
|
||||
fiches_par_type["autre"].append({**fiche, "md_source": md_source})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors du traitement de {fiche['nom']}: {e}")
|
||||
|
||||
# Ordre de traitement pour les fiches restantes
|
||||
ordre_types = ["assemblage", "fabrication", "minerai", "autre"]
|
||||
|
||||
# Générer les fiches restantes dans l'ordre spécifié
|
||||
for type_fiche in ordre_types:
|
||||
logger.info(f"Traitement des fiches de type '{type_fiche}' ({len(fiches_par_type[type_fiche])} fiches)")
|
||||
|
||||
for fiche in fiches_par_type[type_fiche]:
|
||||
try:
|
||||
md_source = fiche["md_source"]
|
||||
dossier = fiche["dossier"]
|
||||
nom_fichier = fiche["nom"]
|
||||
|
||||
# Vérifier si la génération est nécessaire
|
||||
html_path = os.path.join("HTML", dossier, os.path.splitext(nom_fichier)[0] + ".html")
|
||||
if force_regenerate or not os.path.exists(html_path):
|
||||
logger.info(f"Génération de {dossier}/{nom_fichier}")
|
||||
generer_fiche(md_source, dossier, nom_fichier, seuils)
|
||||
else:
|
||||
logger.info(f"Ignoré (déjà généré): {dossier}/{nom_fichier}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors de la génération de {fiche['nom']}: {e}")
|
||||
|
||||
logger.info("Génération batch terminée")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Générateur batch de fiches")
|
||||
parser.add_argument("--output", "-o", default="", help="Répertoire de sortie (laissez vide pour utiliser les dossiers de l'application)")
|
||||
parser.add_argument("--force", "-f", action="store_true", help="Forcer la régénération de toutes les fiches")
|
||||
args = parser.parse_args()
|
||||
|
||||
logger.info(f"Démarrage de la génération batch (output: {args.output if args.output else 'dossiers par défaut'}, force: {args.force})")
|
||||
batch_generate_fiches(output_dir=args.output, force_regenerate=args.force)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
22
config.py
22
config.py
@ -1,15 +1,35 @@
|
||||
import os
|
||||
import streamlit as st
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv(".env")
|
||||
load_dotenv(".env.local", override=True)
|
||||
|
||||
# Fonction pour déterminer l'environnement à partir de l'en-tête X-Environment
|
||||
def determine_environment():
|
||||
# Valeur par défaut (si aucun en-tête n'est détecté)
|
||||
environment = "dev"
|
||||
|
||||
# Si nous sommes dans une session Streamlit
|
||||
if hasattr(st, 'context') and hasattr(st.context, 'headers'):
|
||||
try:
|
||||
# Lire directement l'en-tête X-Environment défini par Nginx : dev/public
|
||||
nginx_env = st.context.headers.get("x-environment")
|
||||
|
||||
if nginx_env:
|
||||
environment = nginx_env.lower()
|
||||
except Exception as e:
|
||||
st.error(f"Erreur lors de la lecture de l'en-tête X-Environment: {e}\nEnvironnement dev par défaut")
|
||||
|
||||
return environment
|
||||
|
||||
ENV = determine_environment()
|
||||
|
||||
GITEA_URL = os.getenv("GITEA_URL", "https://fabnum-git.peccini.fr/api/v1")
|
||||
GITEA_TOKEN = os.getenv("GITEA_TOKEN", "")
|
||||
ORGANISATION = os.getenv("ORGANISATION", "fabnum")
|
||||
DEPOT_FICHES = os.getenv("DEPOT_FICHES", "fiches")
|
||||
DEPOT_CODE = os.getenv("DEPOT_CODE", "code")
|
||||
ENV = os.getenv("ENV")
|
||||
ENV_CODE = os.getenv("ENV_CODE")
|
||||
DOT_FILE = os.getenv("DOT_FILE")
|
||||
INSTRUCTIONS = os.getenv("INSTRUCTIONS", "Instructions.md")
|
||||
|
||||
15
fabnum.py
15
fabnum.py
@ -1,4 +1,12 @@
|
||||
import streamlit as st
|
||||
|
||||
st.set_page_config(
|
||||
page_title="Fabnum – Analyse de chaîne",
|
||||
page_icon="assets/weakness.png", # ajout
|
||||
layout="centered",
|
||||
initial_sidebar_state="expanded"
|
||||
)
|
||||
|
||||
import re
|
||||
|
||||
# Configuration Gitea
|
||||
@ -69,13 +77,6 @@ from app.visualisations import interface_visualisations
|
||||
from app.personnalisation import interface_personnalisation
|
||||
from app.analyse import interface_analyse
|
||||
|
||||
st.set_page_config(
|
||||
page_title="Fabnum – Analyse de chaîne",
|
||||
page_icon="assets/weakness.png", # ajout
|
||||
layout="centered",
|
||||
initial_sidebar_state="expanded"
|
||||
)
|
||||
|
||||
# Initialisation des traductions (langue française par défaut)
|
||||
init_translations()
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user