import io, re, shutil, random from datetime import date import sys from openpyxl import load_workbook from io import BytesIO from openpyxl import Workbook from js import console def save_workbook_to_bytes(wb): buffer = io.BytesIO() wb.save(buffer) return buffer.getvalue() # Pull variables set by JS template_uint8 = globals().get("template_uint8") #get les id du html par le java txt_content = globals().get("txt_content") typeDoc = globals().get("typeDoc") nom_du_releveur = globals().get("nom_du_releveur") hauteur_bosch = globals().get("hauteur_bosch") # Convert template bytes into Python bytes template_bytes = bytes(template_uint8) # --- Start of your original dictionaries and logic (slightly adapted) --- cells = {} if typeDoc == "uds": cells = { "poteau": "B4", "projet": "K3", "révision": "O3", "travaux": "B3", "diametre": "H3", "adresse": "K4", "plan": "H4", "code_barre": "N6", "pro_poteau": "K7", "annee_inspection": "H5", "parc": "K5", "option_HQ":"N5", "longueur": "C6", "classe": "D6", "annee": "H6", "circonference": "K6", "p/r":"D7", "usage_commun:": "O7", "angle": "K13", "lclc": "K14", "nbe_transfo": "L15", "type_transfo": "K15", "equip": "K16", "gradation": "K17", "lampadaire":"K18", "las":"K19", "montage_HQ":"K20", "portee_lache":"K21", "portee_pre:": "K22", "portee_sui:": "N22", "malt":"N21", "reseau":"N20", "cabinet":"O19", "luminaire":"N18", "traverse":"O17", "las":"N16", "fosse": "O14", "hauteur_transfo": "O15", "hauteur_top": "A11", "portee_pre:": "B14", "portee_sui:": "C14", "hauteur_mt1": "A14", "conducteur_mt1": "C14", "phase_mt1": "B14", "deri_mt1": "D14", "hauteur_mt2": "A15", "conducteur_mt2": "C15", "phase_mt2": "B15", "deri_mt2": "D15", "hauteur_mt3:": "A16", "conducteur_mt3": "C16", "phase_mt3": "B16", "deri_mt3": "D16", "hauteur_bt1": "A23", "conducteur_bt1": "B23", "visee_bt1": "C23", "deri_bt1": "D23", "hauteur_bt2": "A22", "conducteur_bt2": "B22", "visee_bt2": "C22", "deri_bt2": "D22", "hauteur_bt3": "A21", "conducteur_mbt3": "B21", "visee_bt3": "C21", "deri_bt3": "D21", "hauteur_bt4": "A20", "conducteur_bt4": "B20", "visee_bt4": "C20", "deri_bt4": "D20", "hauteur_bt5": "A19", "conducteur_bt5": "B19", "visee_bt5": "C19", "deri_bt5": "D19", "hauteur_bt6": "A18", "conducteur_bt6:": "B18", "visee_bt6": "C18", "deri_bt6": "D18", "hauteur_toron1": "A27", "proprio_toron1": "B27", "toron1_existant": "C27", "deri":"D27", "type_toron1": "J27", "nbe_de_cable_toron1": "L27", "diametre_toron1": "K27", "rupture_toron1": "M27", "deg_sol_toron1": "N27", "ancre_toron1": "O27", "hauteur_toron2": "A28", "proprio_toron2": "B28", "existant_toron2": "C28", "deri_toron2": "D28", "type_toron2": "J28", "nbe_de_cable_toron2": "L28", "diametre_toron2": "K28", "rupture_toron2": "M28", "deg_sol_toron2": "N28", "ancre_toron2": "O28", "hauteur_toron3": "A29", "proprio_toron3": "B29", "existant_toron3": "C29", "deri_toron3": "D29", "type_toron3": "J29", "nbe_de_cable_toron3": "L29", "diametre_toron3": "K29", "rupture_toron3": "M29", "deg_sol_toron3": "N29", "ancre_toron3": "O29", "hauteur_toron4": "A30", "proprio_toron4": "B30", "existant_toron4": "C30", "deri_toron4": "D30", "type_toron4": "J30", "nbe_de_cable_toron4": "L30", "diametre_toron4": "K30", "rupture_toron4": "M30", "deg_sol_toron4": "N30", "ancre_toron4": "O30", "hauteur_toron5": "A31", "proprio_toron5": "B31", "existant_toron5": "C31", "deri_toron5": "D31", "type_toron5": "J31", "nbe_de_cable_toron5": "L31", "diametre_toron5": "K31", "rupture_toron5": "M31", "deg_sol_toron5": "N31", "ancre_toron5": "O31", "hauteur_toron6": "A32", "proprio_toron6": "B32", "existant_toron6": "C32", "deri_toron6": "D32", "type_toron6": "J32", "nbe_de_cable_toron6": "L32", "diametre_toron6": "K32", "rupture_toron6": "M32", "deg_sol_toron6": "N32", "ancre_toron6": "O32", "type_de_sol_ancre1": "K36", "capacite_ancre1": "K37", "angle_ancre1":"K38", "hauban1_ancre1": "K39", "hauban2_ancre1": "K40", "hauban3_ancre1": "K41", "hauban4_ancre1": "K42", "tige_ancre1":"K43", "cosse_ancre1": "K44", "ecart_ancre1": "K45", "type_ancre1": "K46", "devi_ancre1": "K47", "espace_dispo_ancre1": "K48", "etat_ancre1": "K49", "type_de_sol_ancre2": "M36", "capacite_ancre2": "M37", "angle_ancre2":"M38", "hauban1_ancre2": "M39", "hauban2_ancre2": "M40", "hauban3_ancre2": "M41", "hauban4_ancre2": "M42", "tige_ancre2":"M43", "cosse_ancre2": "M44", "ecart_ancre2": "M45", "type_ancre2": "M46", "devi_ancre2": "M47", "espace_dispo_ancre2": "M48", "etat_ancre2": "M49", "type_de_sol_ancre3": "N36", "capacite_ancre3": "N37", "angle_ancre3": "N38", "hauban1_ancre3": "N39", "hauban2_ancre3": "N40", "hauban3_ancre3": "N41", "hauban4_ancre3": "N42", "tige_ancre3": "N43", "cosse_ancre3": "N44", "ecart_ancre3": "N45", "type_ancre3": "N46", "devi_ancre3": "N47", "espace_dispo_ancre3": "N48", "etat_ancre3": "N49", "type_de_sol_ancre4": "O36", "capacite_ancre4": "O37", "angle_ancre4": "O38", "hauban1_ancre4": "O39", "hauban2_ancre4": "O40", "hauban3_ancre4": "O41", "hauban4_ancre4": "O42", "tige_ancre4": "O43", "cosse_ancre4": "O44", "ecart_ancre4": "O45", "type_ancre4": "O46", "devi_ancre4": "O47", "espace_dispo_ancre4": "O48", "etat_ancre4": "O49", "ligne_haute_tension": "K51", "element_sensible": "O51", "note": "A56", "date": "K62", } elif typeDoc == "rsa": cells = { "poteau": "B1", "projet": "F1", "révision": "I1", "travaux": "B2", "diametre": "D2", "classification_travaux":'F2', "anomalie_1": "B3", "anomalie_2": "B4", "anomalie_3": "B5", "probleme_1": "E3", "probleme_2": "E4", "probleme_3": "E5", "nom_poteau": "B6", "adresse": "D6", "plan": "G6", "code_barre": "I6", "pro_poteau": "B7", "usage_commun:": "D7", "parc": "F7", "lclc": "I7", "longueur": "B8", "classe": "D8", "annee": "F8", "nbe_transfo": "H8", "type_transfo": "I8", "annee_inspection": "B9", "modele_bell": "D9", "modele_HQ": "F9", "equip": "H9", "fosse": "B9", "hauteur_lampadaire": "D10", "cabinet": "F10", "hauteur_transfo": "H10", "hauteur_top": "A14", "portee_pre:": "B14", "portee_sui:": "C14", "portee_dero": "D14", "toron_ins": "E14", "milieu": "G13", "hauteur_mt1": "A16", "conducteur_mt1": "B16", "phase_mt1": "C16", "deri_mt1": "D16", "hauteur_mt2": "A17", "conducteur_mt2": "B17", "phase_mt2": "C17", "deri_mt2": "D17", "hauteur_mt3": "A18", "conducteur_mt3": "B18", "phase_mt3": "C18", "deri_mt3": "D18", "hauteur_mt4": "A19", "conducteur_mt4": "B19", "phase_mt4": "C19", "deri_mt4": "D19", "hauteur_mt5": "A20", "conducteur_mt5:": "B20", "phase_mt5": "C20", "deri_mt5": "D20", "hauteur_bt1": "A27", "conducteur_bt1": "B27", "visee_bt1": "C27", "deri_bt1": "D27", "hauteur_bt2": "A26", "conducteur_bt2": "B26", "visee_bt2": "C26", "deri_bt2": "D26", "hauteur_bt3": "A25", "conducteur_mbt3": "B25", "visee_bt3": "C25", "deri_bt3": "D25", "hauteur_bt4": "A24", "conducteur_bt4": "B24", "visee_bt4": "C24", "deri_bt4": "D24", "hauteur_bt5": "A23", "conducteur_bt5": "B23", "visee_bt5": "C23", "deri_bt5": "D23", "hauteur_bt6": "A22", "conducteur_bt6:": "B22", "visee_bt6": "C22", "deri_bt6": "D22", "hauteur_toron1": "A29", "proprio_toron1": "B29", "type_toron1": "C29", "nbe_de_cable_toron1": "D29", "diametre_toron1": "E29", "rupture_toron1": "F29", "deg_sol_toron1": "G29", "croisement_toron1": "H29", "ancre_toron1": "I29", "hauteur_toron2": "A30", "proprio_toron2": "B30", "type_toron2": "C30", "nbe_de_cable_toron2": "D30", "diametre_toron2": "E30", "rupture_toron2": "F30", "deg_sol_toron2": "G30", "croisement_toron2": "H30", "ancre_toron2": "I30", "hauteur_toron3": "A31", "proprio_toron3": "B31", "type_toron3": "C31", "nbe_de_cable_toron3": "D31", "diametre_toron3": "E31", "rupture_toron3": "F31", "deg_sol_toron3": "G31", "croisement_toron3": "H31", "ancre_toron3": "I31", "hauteur_toron4": "A32", "proprio_toron4": "B32", "type_toron4": "C32", "nbe_de_cable_toron4": "D32", "diametre_toron4": "E32", "rupture_toron4": "F32", "deg_sol_toron4": "G32", "croisement_toron4": "H32", "ancre_toron4": "I32", "hauteur_toron5": "A33", "proprio_toron5": "B33", "type_toron5": "C33", "nbe_de_cable_toron5": "D33", "diametre_toron5": "E33", "rupture_toron5": "F33", "deg_sol_toron5": "G33", "croisement_toron5": "H33", "ancre_toron5": "I33", "hauteur_toron6": "A34", "proprio_toron6": "B34", "type_toron6": "C34", "nbe_de_cable_toron6": "D34", "diametre_toron6": "E34", "rupture_toron6": "F34", "deg_sol_toron6": "G34", "croisement_toron6": "H34", "ancre_toron6": "I34", "type_de_sol_ancre1": "F17", "tige_ancre1": "F18", "cosse_ancre1": "F19", "type_ancre1": "F20", "ecart_ancre1": "F21", "hauban1_ancre1": "F22", "hauban2_ancre1": "F23", "hauban3_ancre1": "F24", "hauban4_ancre1": "F25", "etat_ancre1": "f26", "espace_dispo_ancre1": "F27", "type_de_sol_ancre2": "G17", "tige_ancre2": "G18", "cosse_ancre2": "G19", "type_ancre2": "G20", "ecart_ancre2": "G21", "hauban1_ancre2": "G22", "hauban2_ancre2": "G23", "hauban3_ancre2": "G24", "hauban4_ancre2": "G25", "etat_ancre2": "G26", "espace_dispo_ancre2": "G27", "type_de_sol_ancre3": "H17", "tige_ancre3": "H18", "cosse_ancre3": "H19", "type_ancre3": "H20", "ecart_ancre3": "H21", "hauban1_ancre3": "H22", "hauban2_ancre3": "H23", "hauban3_ancre3": "H24", "hauban4_ancre3": "H25", "etat_ancre3": "H26", "espace_dispo_ancre3": "H27", "type_de_sol_ancre4": "I17", "tige_ancre4": "I18", "cosse_ancre4": "I19", "type_ancre4": "I20", "ecart_ancre4": "I21", "hauban1_ancre4": "I22", "hauban2_ancre4": "I23", "hauban3_ancre4": "I24", "hauban4_ancre4": "I25", "etat_ancre4": "I26", "espace_dispo_ancre4": "I27" , "ligne_haute_tension": "A36", "dis_appro": "C36", "element_sensible": "D36", "coord": "G36", "note": "A38", "date": "F49", "releveur": "F47", } else: raise Exception("Erreur: typeDoc invalide (uds ou rsa requis)") # keep your type_poteaux & parc dictionaries exactly type_poteaux = { 74:(35, 5), 79:{'JP': (35, 5), 'SYP': (40, 5), 'LPP': (35, 5)}, 80:(35, 4), 81:(35, 5), 82:(45, 5), 83:{'LPP': (40, 5), 'WRC': (35, 5)}, 84:(40, 5), 86:{'RP': (40, 5), 'JP': (35, 4)}, 87:(45, 5), 88:{'RP': (35, 4), 'JP': (45, 5), 'WRC': (40, 5)}, 89:(45, 4), 90:{'RP': (45, 5), 'LPP': (40, 4), 'WRC': (35, 4)}, 91:(40, 4), 92:(45, 5), 93:{'RP': (40, 4), 'SYP': (35, 2)}, 94:(45, 4), 95:{'JP': (45, 4), 'WRC': (40, 4)}, 97:(45, 4), 98: {'SYP': (40, 2), 'LPP': (35, 2)}, 99:(35, 2), 100:(45, 4), 101:(35, 2), 103:{'SYP': (45, 2), 'WRC': (35, 2)}, 104:(40, 2), 105:(40, 2), 107:(40, 2), 109:(45, 2), 110:{'JP': (45, 2), 'WRC': (40, 2)}, 112:(45, 2), 115:(45, 2), } parc = { "304":("saint-remi","saint-michel","sherrington"), "339":("sainte-clotilde","saint-chrysostome","hemmingford","havelock"), "303":("franklin","ormstown","saint-antoine","hinchinbrooke","godmanchester","huntingdon","saint-anicet","dundee","elgin"), "306":("lacolle","napierville","saint-bernard-de-lacolle"), "363":("saint-barbe","saint-stanislas-de-kostka","saint-etienne-de-beauharnois","saint-louis-de-gonzague"), } # We'll parse the txt content similar to your script lines = txt_content.splitlines() valeurs = {} outputs = [] # list of tuples (filename, bytes) def create_excel_from_valeurs(valeurs_dict): # create a name and a workbook based on the uploaded template bytes nom_du_poteau = valeurs_dict.get('poteau', 'poteau').strip() + '.xlsx' # load a fresh workbook from template bytes bio = io.BytesIO(template_bytes) wb = load_workbook(filename=bio) # choose 'Grille' sheet if exists else active if 'Grille' in wb.sheetnames: ws = wb['Grille'] else: ws = wb.active for key, value in list(valeurs_dict.items()): try: champs = cells[key] ws[champs] = value except Exception: # ignore keys not present in cells continue out_bytes = save_workbook_to_bytes(wb) return nom_du_poteau, out_bytes # helper to safely convert floats when needed def safe_float(x): try: return float(x) except: return None # The main parsing loop (close to your original) for line in lines: if '---' in line: # finalize current record if 'poteau' in valeurs and valeurs.get('poteau','').strip() != '': fname, b = create_excel_from_valeurs(valeurs) outputs.append((fname, b)) console.log(f'Created output: {fname}') valeurs = {} continue if line.strip() == "": continue if ':' not in line: continue variable, value = line.split(":", 1) variable = variable.strip() value = value.rstrip("\n") # replicate your special handling rules if 'hauteur' in variable: if value.strip() == "": continue if value.strip() == 'tri': # need hauteur_top present first try: valeurs["hauteur_top"] = str(valeurs["hauteur_top"].replace(",", ".")) value = str(float(valeurs['hauteur_top']) + 0.3) #valeurs['hauteur_mt2'] = str(round(float(valeurs['hauteur_top']) - 0.15, 2)) except Exception: # if hauteur_top missing, skip console.log('marche pas') pass # compute with hauteur_bosch (string) try: c = float(value) a = 1 hb = float(hauteur_bosch) b = (c**2 - a**2)**0.5 + hb b = round(b, 2) value = str(b).replace(".", ",") except Exception as e: # if numeric conversion fails, keep original value console.log('hauteur calculation failed', e) pass if 'nom_poteau' in variable: # copy name from 'poteau' (first token) if 'poteau' in valeurs: value = valeurs["poteau"].split(" ", 1)[0] if 'adresse' in variable: # ================================================================= # Utilise re.sub() pour retirer le texte non numérique au début, # puis supprimer toute indication de type "+2" ou "-3" accolée # au numéro principal, en conservant le reste de l'adresse. # # Expression utilisée : r'^\D*(\d+)(?:[+-]\d+)?(.*)' # - ^ → début de la chaîne # - \D* → zéro ou plusieurs caractères qui NE sont PAS des chiffres # (supprime par exemple "PHD", "PHC", etc.) # - (\d+) → capture le numéro principal (un ou plusieurs chiffres) # - (?: ... ) → parenthèses non capturantes (pour regrouper sans créer un groupe séparé) # - [+-]\d+ → un signe "+" ou "-" suivi d'un ou plusieurs chiffres # (par ex. "+2" ou "-3") # - ? → rend la partie [+-]\d+ optionnelle # - (.*) → capture tout le reste de la chaîne (l'adresse après le numéro) # # Remplacement utilisé : r'\1\2' # - \1 → insère le numéro principal capturé # - \2 → insère le texte restant de l'adresse # # Exemple : # "PHD248+2 chemin de l'église" devient "248 chemin de l'église" # "PHC300-1 rue des lilas" devient "300 rue des lilas" # ================================================================= if 'poteau' in valeurs: value = re.sub(r'^\D*(\d+)(?:[+-]\d+)?(.*)', r'\1\2', valeurs["poteau"]) if 'date' in variable: if typeDoc == 'uds': value = str(nom_du_releveur + '\\n') + str(date.today()) else: value = str(date.today()) if 'longueur' in variable: value = value.strip() try: value_int = int(value) except ValueError: continue if value_int not in type_poteaux: valeurs[variable] = value continue type_poteaux_entre = type_poteaux[value_int] if isinstance(type_poteaux_entre, dict): bois = valeurs.get('bois', '').strip() if bois == '': value = next(iter(type_poteaux_entre.values()))[0] valeurs['classe'] = next(iter(type_poteaux_entre.values()))[1] valeurs[variable] = value #Créer une itérateur qui permet de parcourir les éléments une par une continue valeurs['classe'] = type_poteaux_entre[bois][1] value = type_poteaux_entre[bois][0] else: valeurs['classe'] = type_poteaux_entre[1] value = type_poteaux_entre[0] if "ville" in variable: # determine parc key covering the town name found = None for k,v in parc.items(): if value.strip() in v: found = k break valeurs['parc'] = found if "releveur" in variable: value = nom_du_releveur # finally store the variable valeurs[variable] = value # if file doesn't end with '---', create last record if valeurs and 'poteau' in valeurs and valeurs.get('poteau','').strip() != '': fname, b = create_excel_from_valeurs(valeurs) outputs.append((fname, b)) from js import Uint8Array, Blob, URL, document for fname, bbytes in outputs: u8 = Uint8Array.new(bbytes) # explicitly convert Python bytes to JS Uint8Array blob = Blob.new([u8], { "type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }) url = URL.createObjectURL(blob) a = document.createElement("a") a.href = url a.download = fname a.textContent = "[Télécharger] " + fname document.getElementById("downloads").appendChild(a) console.log("Prepared download for " + fname) # also print a summary to the page console element from js import console as js_console js_console.log(f"Created {len(outputs)} file(s).") print(f"Created {len(outputs)} file(s).") # visible in the log element too