Modification de la détection de l'environnement

This commit is contained in:
Stéphan Peccini 2025-05-15 07:40:04 +02:00
parent 9491dd076f
commit 4ae0fbfdb3
6 changed files with 250 additions and 14 deletions

1
.env
View File

@ -1,4 +1,3 @@
ENV = "dev"
ENV_CODE = "dev" ENV_CODE = "dev"
PORT=8502 PORT=8502
DOT_FILE = "schema.txt" DOT_FILE = "schema.txt"

2
.gitignore vendored
View File

@ -23,6 +23,8 @@ HTML/
# Ignorer données Fiches (adapté à ton projet) # Ignorer données Fiches (adapté à ton projet)
Instructions.md Instructions.md
Fiches/ Fiches/
HTML/
static/Fiches/
# Autres spécifiques si besoin # Autres spécifiques si besoin
.DS_Store .DS_Store

View File

@ -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] : Pour l'environnement de pré-production, (https://fabnum-dev.peccini.fr)[https://fabnum-dev.peccini.fr] :
ENV=dev ENV_CODE = "dev"
PORT=8502 PORT=8502
DOT_FILE = "schema.txt"
GITEA_URL = "https://fabnum-git.peccini.fr/api/v1" GITEA_URL = "https://fabnum-git.peccini.fr/api/v1"
ORGANISATION = "fabnum" ORGANISATION = "fabnum"
DEPOT_FICHES = "fiches" 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 : Pour l'environnement de production, (https://fabnum.peccini.fr)[https://fabnum.peccini.fr], le fichier est identique sauf pour :
ENV=public
PORT=8501 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. dev et public sont les deux branches officielles du dépôt.
L'application se lance simplement sous la forme : L'application se lance simplement sous la forme :
@ -66,12 +82,10 @@ Pour automatiser le lancement, il est intégré dans systemd :
[Service] [Service]
User=fabnum User=fabnum
WorkingDirectory=/home/fabnum/fabnum-dev WorkingDirectory=/home/fabnum/fabnum-dev
ExecStart=/home/fabnum/fabnum-dev/venv/bin/streamlit run /home/fabnum/fabnum-dev/fa ExecStart=/home/fabnum/fabnum-dev/venv/bin/streamlit run /home/fabnum/fabnum-dev/fabnum.py --server.port 8502
bnum.py
Restart=always Restart=always
RestartSec=5 RestartSec=5
Environment=PYTHONUNBUFFERED=1 Environment=PYTHONUNBUFFERED=1
SELinuxContext=system_u:system_r:httpd_t:s0
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

200
batch_generate_fiches.py Normal file
View 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()

View File

@ -1,15 +1,35 @@
import os import os
import streamlit as st
from dotenv import load_dotenv from dotenv import load_dotenv
load_dotenv(".env") load_dotenv(".env")
load_dotenv(".env.local", override=True) 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_URL = os.getenv("GITEA_URL", "https://fabnum-git.peccini.fr/api/v1")
GITEA_TOKEN = os.getenv("GITEA_TOKEN", "") GITEA_TOKEN = os.getenv("GITEA_TOKEN", "")
ORGANISATION = os.getenv("ORGANISATION", "fabnum") ORGANISATION = os.getenv("ORGANISATION", "fabnum")
DEPOT_FICHES = os.getenv("DEPOT_FICHES", "fiches") DEPOT_FICHES = os.getenv("DEPOT_FICHES", "fiches")
DEPOT_CODE = os.getenv("DEPOT_CODE", "code") DEPOT_CODE = os.getenv("DEPOT_CODE", "code")
ENV = os.getenv("ENV")
ENV_CODE = os.getenv("ENV_CODE") ENV_CODE = os.getenv("ENV_CODE")
DOT_FILE = os.getenv("DOT_FILE") DOT_FILE = os.getenv("DOT_FILE")
INSTRUCTIONS = os.getenv("INSTRUCTIONS", "Instructions.md") INSTRUCTIONS = os.getenv("INSTRUCTIONS", "Instructions.md")

View File

@ -1,4 +1,12 @@
import streamlit as st 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 import re
# Configuration Gitea # Configuration Gitea
@ -69,13 +77,6 @@ from app.visualisations import interface_visualisations
from app.personnalisation import interface_personnalisation from app.personnalisation import interface_personnalisation
from app.analyse import interface_analyse 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) # Initialisation des traductions (langue française par défaut)
init_translations() init_translations()