import xml.etree.ElementTree as ET import pandas as pd import json import gradio as gr def get_clients_from_xml(xml_file): """Extract all clients from XML file and return a list of tuples (id, name)""" try: tree = ET.parse(xml_file.name) root = tree.getroot() clients = [] for client in root.findall(".//client"): client_id = client.get("id") nom = client.get("nom") if client.get("nom") is not None else "" prenom = client.get("prenom") if client.get("prenom") is not None else "" clients.append((client_id, f"{prenom} {nom} (ID: {client_id})")) return clients except Exception as e: print(e) return [] def client_to_json(xml_file, client_id): tree = ET.parse(xml_file) root = tree.getroot() # Find the specific client client = root.find(f".//client[@id='{client_id}']") if client is None: return json.dumps({"error": f"Client ID {client_id} not found"}) def element_to_dict(element): result = {} # Add attributes if element.attrib: result.update(element.attrib) # Add text content if it exists and isn't empty if element.text and element.text.strip(): result["_text"] = element.text.strip() # Process child elements for child in element: child_data = element_to_dict(child) if child.tag in result: # If the key already exists, convert it to a list if it isn't already if not isinstance(result[child.tag], list): result[child.tag] = [result[child.tag]] result[child.tag].append(child_data) else: result[child.tag] = child_data return result # Convert client data to dictionary client_data = element_to_dict(client) # Convert to JSON with pretty printing return json.dumps(client_data, indent=2, ensure_ascii=False) def display_nested_json(json_data): # If input is a string, parse it to dict if isinstance(json_data, str): data = json.loads(json_data) else: data = json_data # 1. Basic Client Information basic_info = pd.DataFrame( [ { "ID": data.get("id"), "Nom": data.get("nom"), "Prénom": data.get("prenom"), "Civilité": data.get("civilite"), "Date Creation": data.get("date_creation"), } ] ) # 2. Accounts Table accounts_df = extract_accounts(data) # 3. Contact Information contacts_df = extract_contacts(data) # 4. Real Estate (Immobilier) Information immobilier_df = extract_immobilier(data) # 5. Patrimoine Information patrimoine_df = extract_patrimoine(data) # 6. Budget Information budget_df = extract_budget(data) return { "basic_info": basic_info, "accounts": accounts_df, "contacts": contacts_df, "immobilier": immobilier_df, "patrimoine": patrimoine_df, "budget": budget_df, } def extract_accounts(data): if "comptes" in data and "compte" in data["comptes"]: accounts = data["comptes"]["compte"] if isinstance(accounts, dict): accounts = [accounts] accounts_data = [] for account in accounts: situations = account.get("situations", {}) situation_data = situations.get("situation", []) if isinstance(situation_data, dict): situation_data = [situation_data] for situation in situation_data: row = { "Account ID": account.get("id"), "Account Name": account.get("intitule"), "Opening Date": account.get("date_ouverture"), "Valuation Date": situations.get("date_valorisation"), "Valuation Type": situations.get("type_valorisation"), "Support ID": situation.get("support_id"), "Quantity": situation.get("quantite"), "Price": situation.get("cours"), "Value (EUR)": situation.get("valeur_euro"), "Weight (%)": situation.get("poids_ligne"), "PMV (EUR)": situation.get("pmv_euro"), "PMV (%)": situation.get("pmv_pourcentage"), } accounts_data.append(row) accounts_df = pd.DataFrame(accounts_data) numeric_columns = [ "Quantity", "Price", "Value (EUR)", "Weight (%)", "PMV (EUR)", "PMV (%)", ] for col in numeric_columns: if col in accounts_df.columns: try: accounts_df[col] = pd.to_numeric(accounts_df[col]) except ValueError: print(f"Warning: Could not convert column {col} to numeric.") else: accounts_df = pd.DataFrame() return accounts_df def extract_contacts(data): if "modes_contacts" in data: contacts = data["modes_contacts"] contacts_df = pd.DataFrame( [ { "Email": contacts.get("email_personnel"), "Mobile": contacts.get("telephone_mobile"), } ] ) else: contacts_df = pd.DataFrame() return contacts_df def extract_immobilier(data): if "immobiliers" in data and "immobilier" in data["immobiliers"]: immobilier = data["immobiliers"]["immobilier"] if isinstance(immobilier, dict): immobilier = [immobilier] immobilier_data = [] for item in immobilier: row = { "ID": item.get("id"), "Designation": item.get("designation"), "Address": item.get("adresse", {}).get("adresse"), "City": item.get("adresse", {}).get("ville"), "Postal Code": item.get("adresse", {}).get("code_postal"), "Country": item.get("adresse", {}).get("pays"), "Value": item.get("valeur", {}).get("totale"), "Revenues": item.get("revenus", {}).get("montant"), "Charges": item.get("charges", {}).get("montant"), } immobilier_data.append(row) immobilier_df = pd.DataFrame(immobilier_data) else: immobilier_df = pd.DataFrame() return immobilier_df def extract_patrimoine(data): patrimoine_data = {"actifs": pd.DataFrame(), "passifs": pd.DataFrame()} if "patrimoine" in data: # Extract Actifs if "actifs" in data["patrimoine"]: actifs_items = data["patrimoine"]["actifs"].get("actif", []) if isinstance(actifs_items, dict): actifs_items = [actifs_items] if actifs_items: actifs_data = [] for item in actifs_items: row = { "UUID": item.get("uuid"), "Libellé": item.get("libelle"), "Patrimoine ID": item.get("patrimoine_id"), "Montant (EUR)": item.get("montant_euro"), "Système": item.get("system_origine"), "Détenteur": item.get("detention", {}).get("detenteur"), "Mode": item.get("detention", {}).get("mode"), } # Extract external references ref_externes = item.get("ref_externes", {}).get("ref_externe", []) if isinstance(ref_externes, dict): ref_externes = [ref_externes] if ref_externes: systems = [ref.get("system") for ref in ref_externes] row["Systèmes Externes"] = ", ".join(filter(None, systems)) actifs_data.append(row) actifs_df = pd.DataFrame(actifs_data) if "Montant (EUR)" in actifs_df.columns: try: actifs_df["Montant (EUR)"] = pd.to_numeric( actifs_df["Montant (EUR)"] ) except ValueError: print( "Warning: Could not convert some actifs montants to numeric" ) patrimoine_data["actifs"] = actifs_df # Extract Passifs if "passifs" in data["patrimoine"]: passifs_items = data["patrimoine"]["passifs"].get("passif", []) if isinstance(passifs_items, dict): passifs_items = [passifs_items] if passifs_items: passifs_data = [] for item in passifs_items: row = { "UUID": item.get("uuid"), "Libellé": item.get("libelle"), "Patrimoine ID": item.get("patrimoine_id"), "Système": item.get("system_origine"), "Souscripteur": item.get("souscripteur"), "Périodicité": item.get("periodicite"), "Taux HA": item.get("caracteristiques", {}).get("taux_HA"), "Assurance Taux": item.get("assurance", {}).get("taux"), "Capital Restant Dû (EUR)": item.get( "capital_restant_du", {} ).get("montant_euro"), "Date Capital Restant Dû": item.get( "capital_restant_du", {} ).get("date"), } # Extract external references ref_externes = item.get("ref_externes", {}).get("ref_externe", []) if isinstance(ref_externes, dict): ref_externes = [ref_externes] if ref_externes: systems = [ref.get("system") for ref in ref_externes] row["Systèmes Externes"] = ", ".join(filter(None, systems)) passifs_data.append(row) passifs_df = pd.DataFrame(passifs_data) if "Capital Restant Dû (EUR)" in passifs_df.columns: try: passifs_df["Capital Restant Dû (EUR)"] = pd.to_numeric( passifs_df["Capital Restant Dû (EUR)"] ) except ValueError: print( "Warning: Could not convert some passifs capital restant dû to numeric" ) patrimoine_data["passifs"] = passifs_df return patrimoine_data def extract_budget(data): budget_data = {"revenus": pd.DataFrame(), "charges": pd.DataFrame()} if "budget" in data: # Extract Revenus if "revenus" in data["budget"]: revenus_items = data["budget"]["revenus"].get("revenu", []) if isinstance(revenus_items, dict): revenus_items = [revenus_items] if revenus_items: revenus_data = [] for item in revenus_items: row = { "ID": item.get("id"), "Budget ID": item.get("budget_id"), "Libellé": item.get("libelle"), "Montant (EUR)": item.get("montant_euro"), "Périodicité": item.get("periodicite"), "Bénéficiaire": item.get("beneficiaire"), "UUID": item.get("uuid"), "Système": item.get("system_origine"), "Date Terme": item.get("date_terme", ""), } # Extract external references if needed ref_externes = item.get("ref_externes", {}).get("ref_externe", []) if isinstance(ref_externes, dict): ref_externes = [ref_externes] if ref_externes: systems = [ref.get("system") for ref in ref_externes] row["Systèmes Externes"] = ", ".join(filter(None, systems)) revenus_data.append(row) revenus_df = pd.DataFrame(revenus_data) if "Montant (EUR)" in revenus_df.columns: try: revenus_df["Montant (EUR)"] = pd.to_numeric( revenus_df["Montant (EUR)"] ) except ValueError: print( "Warning: Could not convert some revenus montants to numeric" ) budget_data["revenus"] = revenus_df # Extract Charges if "charges" in data["budget"]: charges_items = data["budget"]["charges"].get("charge", []) if isinstance(charges_items, dict): charges_items = [charges_items] if charges_items: charges_data = [] for item in charges_items: row = { "ID": item.get("id"), "Budget ID": item.get("budget_id"), "Libellé": item.get("libelle"), "Montant (EUR)": item.get("montant_euro"), "Périodicité": item.get("periodicite"), "Débiteur": item.get("debiteur"), "UUID": item.get("uuid"), "Système": item.get("system_origine"), } # Extract external references if needed ref_externes = item.get("ref_externes", {}).get("ref_externe", []) if isinstance(ref_externes, dict): ref_externes = [ref_externes] if ref_externes: systems = [ref.get("system") for ref in ref_externes] row["Systèmes Externes"] = ", ".join(filter(None, systems)) charges_data.append(row) charges_df = pd.DataFrame(charges_data) if "Montant (EUR)" in charges_df.columns: try: charges_df["Montant (EUR)"] = pd.to_numeric( charges_df["Montant (EUR)"] ) except ValueError: print( "Warning: Could not convert some charges montants to numeric" ) budget_data["charges"] = charges_df return budget_data def format_client_info(xml_file, client_id): # Get JSON data using your previous function json_data = client_to_json(xml_file, client_id) tables = display_nested_json(json_data) pd.set_option("display.max_columns", None) pd.set_option("display.width", None) pd.set_option( "display.float_format", lambda x: "{:.2f}".format(x) if isinstance(x, (float, int)) else x, ) # Return DataFrames directly instead of string representations outputs = [] # Basic Info outputs.append(gr.Markdown("## Client Basic Information")) outputs.append(tables["basic_info"]) # Contacts outputs.append(gr.Markdown("## Contacts Client")) outputs.append(tables["contacts"]) # Accounts outputs.append(gr.Markdown("## Accounts and Positions")) outputs.append( tables["accounts"] if not tables["accounts"].empty else pd.DataFrame({"Message": ["No accounts found"]}) ) # Patrimoine - Actifs outputs.append(gr.Markdown("## Patrimoine")) outputs.append(gr.Markdown("### Actifs")) outputs.append( tables["patrimoine"]["actifs"] if not tables["patrimoine"]["actifs"].empty else pd.DataFrame({"Message": ["No actifs found"]}) ) # Patrimoine - Passifs outputs.append(gr.Markdown("### Passifs")) outputs.append( tables["patrimoine"]["passifs"] if not tables["patrimoine"]["passifs"].empty else pd.DataFrame({"Message": ["No passifs found"]}) ) # Budget - Revenus outputs.append(gr.Markdown("## Budget")) outputs.append(gr.Markdown("### Revenus")) outputs.append( tables["budget"]["revenus"] if not tables["budget"]["revenus"].empty else pd.DataFrame({"Message": ["No revenus found"]}) ) # Budget - Charges outputs.append(gr.Markdown("### Charges")) outputs.append( tables["budget"]["charges"] if not tables["budget"]["charges"].empty else pd.DataFrame({"Message": ["No charges found"]}) ) return outputs # Create Gradio interface with gr.Blocks(title="Client Information Viewer") as demo: gr.Markdown("# Client Information Viewer") gr.Markdown( "Upload an XML file and select a client to view their detailed information" ) xml_file = gr.File(label="Upload XML File", file_types=[".xml"]) client_dropdown = gr.Dropdown(label="Select Client", choices=[], interactive=True) view_btn = gr.Button("View Client Info", interactive=False) # Create output containers for each section basic_info_header = gr.Markdown() basic_info_df = gr.DataFrame() contacts_header = gr.Markdown() contacts_df = gr.DataFrame() accounts_header = gr.Markdown() accounts_df = gr.DataFrame() actifs_header = gr.Markdown() actifs_subheader = gr.Markdown() actifs_df = gr.DataFrame() passifs_subheader = gr.Markdown() passifs_df = gr.DataFrame() revenus_header = gr.Markdown() revenus_subheader = gr.Markdown() revenus_df = gr.DataFrame() charges_subheader = gr.Markdown() charges_df = gr.DataFrame() # Combine all outputs in order output_dfs = [ basic_info_header, basic_info_df, contacts_header, contacts_df, accounts_header, accounts_df, actifs_header, actifs_subheader, actifs_df, passifs_subheader, passifs_df, revenus_header, revenus_subheader, revenus_df, charges_subheader, charges_df, ] # Update dropdown when file is uploaded def update_dropdown(file): if file is None: return gr.Dropdown(choices=[], value=None, interactive=False), gr.Button( interactive=False ) clients = get_clients_from_xml(file) choices = [(name, id) for id, name in clients] return gr.Dropdown(choices=choices, interactive=True), gr.Button( interactive=True ) xml_file.change( fn=update_dropdown, inputs=[xml_file], outputs=[client_dropdown, view_btn] ) # View client info when button is clicked view_btn.click( fn=format_client_info, inputs=[xml_file, client_dropdown], outputs=output_dfs, ) if __name__ == "__main__": demo.launch(server_port=7860, share=True)