import gradio as gr import tempfile import os import shutil from pathlib import Path from parse_invoices import read_msg, parse_lpo_html, init_or_load_workbook, append_row, get_excel_path def process_msg_files(files): if not files: return None, "No files uploaded." with tempfile.TemporaryDirectory() as tmpdir: tmpdir = Path(tmpdir) # Save uploaded files to temp folder for f in files: shutil.copy(f.name, tmpdir / Path(f.name).name) # Run parser excel_path = get_excel_path(tmpdir) wb, ws = init_or_load_workbook(excel_path) next_row = ws.max_row + 1 log_lines = [] for msg_path in sorted(tmpdir.glob('*.msg')): try: subject, html_bytes = read_msg(msg_path) if not html_bytes: log_lines.append(f"⚠️ {msg_path.name} — no HTML body") continue fields = parse_lpo_html(html_bytes) row_data = {'subject': subject, 'filename': msg_path.name, **fields} missing = [k for k, v in fields.items() if v is None] status = 'PARTIAL' if missing else 'OK' append_row(ws, row_data, next_row, status=status) next_row += 1 log_lines.append(f"✅ {msg_path.name} — LPO:{fields['lpo_number']} | Inv:{fields['inv_number']} | Amount:{fields['inv_amount']}") except Exception as e: log_lines.append(f"❌ {msg_path.name} — ERROR: {e}") wb.save(excel_path) wb.close() # Copy excel to a stable output path Gradio can serve out_path = Path(tempfile.mktemp(suffix='.xlsx')) shutil.copy(excel_path, out_path) return str(out_path), "\n".join(log_lines) demo = gr.Interface( fn=process_msg_files, inputs=gr.File( file_count="multiple", file_types=[".msg"], label="Upload .msg files" ), outputs=[ gr.File(label="Download Excel"), gr.Textbox(label="Processing Log", lines=15) ], title="LPO Invoice Parser", description="Upload one or more Outlook .msg LPO emails. Get back a formatted Excel with LPO #, Ref No, Inv #, and Amount." ) demo.launch()