""" Manual Dashboard UI - FIXED VERSION Complete tool-by-tool interface with working form filler """ import os import gradio as gr import json import asyncio from pathlib import Path from utils.pdf_utils import extract_text_from_pdf, get_pdf_metadata from utils.llm_utils import get_llm_response from tools import ( extract_text_ocr, summarize_pdf, extract_pdf_metadata, fill_form, create_calendar_event, draft_email, organize_files, ) UPLOAD_DIR = "data/uploads" OUTPUT_DIR = "data/outputs" def ensure_dirs(): os.makedirs(UPLOAD_DIR, exist_ok=True) os.makedirs(OUTPUT_DIR, exist_ok=True) ensure_dirs() # ---------------- FILE UPLOAD ---------------- def handle_file_upload(files): """Handle file uploads from Gradio""" if not files: return "⚠️ No files uploaded.", [], None saved_files = [] file_list = [] for temp_path in files: if temp_path is None: continue filename = os.path.basename(temp_path) dest_path = os.path.join(UPLOAD_DIR, filename) try: with open(temp_path, "rb") as src: with open(dest_path, "wb") as dst: dst.write(src.read()) saved_files.append(filename) file_list.append(filename) except Exception as e: return f"⚠️ File save error:\n{e}", [], None text = "\n".join([f"✓ {name}" for name in saved_files]) choices = file_list default = file_list[0] if file_list else None return ( text, file_list, gr.update(choices=choices, value=default), ) # ---------------- OCR TEXT EXTRACTION ---------------- def extract_ocr_text_ui(filename): """Extract text from image using OCR""" try: file_path = os.path.join(UPLOAD_DIR, filename) result = asyncio.run(extract_text_ocr(file_path, 'en')) if 'error' in result: return f"⚠️ Error: {result['error']}" return result.get('text', 'No text found') except Exception as e: return f"⚠️ Error:\n{e}" # ---------------- PDF TEXT ---------------- def extract_pdf_text_ui(filename): """Extract text from PDF""" try: return extract_text_from_pdf(os.path.join(UPLOAD_DIR, filename)) except Exception as e: return f"⚠️ Error:\n{e}" # ---------------- PDF SUMMARY ---------------- def summarize_pdf_ui(filename, length): """Summarize PDF document""" try: file_path = os.path.join(UPLOAD_DIR, filename) result = asyncio.run(summarize_pdf(file_path, max_length=length*100)) if isinstance(result, dict): if 'error' in result: return f"⚠️ Error: {result['error']}" return result.get('summary', 'No summary generated') return str(result) except Exception as e: return f"⚠️ Error:\n{e}" # ---------------- PDF METADATA ---------------- def extract_metadata_ui(filename): """Extract metadata from PDF""" try: file_path = os.path.join(UPLOAD_DIR, filename) result = asyncio.run(extract_pdf_metadata(file_path)) return json.dumps(result, indent=2) except Exception as e: return f"⚠️ Error:\n{e}" # ---------------- EMAIL ---------------- def email_ui(recipient, subject, body): """Draft email""" try: result = asyncio.run(draft_email( recipient=recipient, subject=subject, context=body, tone='professional' )) if isinstance(result, dict): if 'success' in result and result['success']: email_body = result.get('email_body', '') output_file = result.get('output_path_txt', '') return email_body, output_file else: return f"⚠️ Error: {result.get('error', 'Unknown error')}", None return str(result), None except Exception as e: return f"⚠️ Error:\n{e}", None # ---------------- CALENDAR ---------------- def calendar_ui(title, date, time_str, desc): """Create calendar event""" try: start_datetime = f"{date} {time_str}" from datetime import datetime, timedelta start_dt = datetime.strptime(start_datetime, "%Y-%m-%d %H:%M") end_dt = start_dt + timedelta(hours=1) end_datetime = end_dt.strftime("%Y-%m-%d %H:%M") result = asyncio.run(create_calendar_event( title=title, start=start_datetime, end=end_datetime, description=desc )) if isinstance(result, dict): if 'success' in result and result['success']: output_path = result.get('output_path', '') return "✅ Event created successfully!", output_path else: return f"⚠️ Error: {result.get('error', 'Unknown error')}", None return "✅ Event created!", None except Exception as e: return f"⚠️ Error:\n{e}", None # ---------------- ORGANIZER ---------------- def organize_files_ui(): """Organize files in upload directory""" try: result = asyncio.run(organize_files(UPLOAD_DIR, strategy='by_type')) return json.dumps(result, indent=2) except Exception as e: return f"⚠️ Error:\n{e}" # ---------------- FORM FILLING (COMPLETE FIXED) ---------------- def fill_form_ui(template_file, user_text): """Fill form template with data - COMPLETELY FIXED VERSION""" if not template_file: return "⚠️ Please upload a .docx or .xlsx template", None try: # Handle file path if isinstance(template_file, str): template_path = template_file else: template_path = template_file.name if hasattr(template_file, 'name') else str(template_file) # Copy to uploads directory filename = os.path.basename(template_path) dest_template = os.path.join(UPLOAD_DIR, filename) with open(template_path, "rb") as src: with open(dest_template, "wb") as dst: dst.write(src.read()) # Parse user input into dictionary fields = {} for line in user_text.split("\n"): line = line.strip() if not line: continue if ":" in line: parts = line.split(":", 1) if len(parts) == 2: key = parts[0].strip() value = parts[1].strip() fields[key] = value if not fields: return "⚠️ No fields parsed. Use format:\nField Name: Value", None # Run async function result = asyncio.run(fill_form(dest_template, fields)) if isinstance(result, dict): if result.get('success'): output_path = result.get('output_path', '') fields_filled = result.get('fields_filled', []) total = result.get('total_fields', 0) debug_info = result.get('debug_info', []) status_msg = f"✅ Form filled successfully!\n\n" status_msg += f"📝 Fields filled: {total}\n" if fields_filled: status_msg += f"✓ {', '.join(set(fields_filled))}\n\n" if debug_info: status_msg += f"Debug info:\n" + "\n".join([f" • {info}" for info in debug_info[:10]]) status_msg += f"\n\n📥 Download the filled form below" return status_msg, output_path else: error = result.get('error', 'Unknown error') return f"⚠️ Error: {error}", None return "⚠️ Unexpected result format", None except Exception as e: import traceback error_detail = traceback.format_exc() return f"⚠️ Error:\n{str(e)}\n\nDetails:\n{error_detail}", None # ---------------- BUILD UI ---------------- def create_manual_dashboard(agent): """Create manual dashboard interface""" with gr.Blocks() as ui: gr.Markdown("# 📊 Manual Dashboard — LifeAdmin AI") with gr.Group(): upload = gr.Files(label="📤 Upload Files", file_count="multiple") file_list_txt = gr.Textbox(label="Uploaded Files", interactive=False) file_dd = gr.Dropdown(label="Select File", choices=[]) upload.change( handle_file_upload, inputs=[upload], outputs=[file_list_txt, gr.State(), file_dd], ) with gr.Tabs(): # PDF TAB with gr.Tab("📄 PDF Tools"): with gr.Group(): t1 = gr.Button("Extract Text from PDF", variant="primary") out1 = gr.Textbox(lines=12, label="Extracted Text") t1.click(extract_pdf_text_ui, inputs=[file_dd], outputs=[out1]) with gr.Group(): summary_len = gr.Slider(1, 10, value=3, step=1, label="Summary Paragraphs") t2 = gr.Button("Summarize PDF", variant="primary") out2 = gr.Textbox(lines=10, label="Summary") t2.click(summarize_pdf_ui, inputs=[file_dd, summary_len], outputs=[out2]) with gr.Group(): t3 = gr.Button("Extract Metadata", variant="primary") out3 = gr.Textbox(lines=8, label="Metadata (JSON)") t3.click(extract_metadata_ui, inputs=[file_dd], outputs=[out3]) # OCR TAB with gr.Tab("🖼️ OCR (Image to Text)"): with gr.Group(): gr.Markdown("Extract text from images using OCR") ocr_btn = gr.Button("Extract Text from Image", variant="primary") ocr_out = gr.Textbox(lines=15, label="Extracted Text") ocr_btn.click(extract_ocr_text_ui, inputs=[file_dd], outputs=[ocr_out]) # EMAIL TAB with gr.Tab("✉️ Email Drafter"): with gr.Group(): recipient = gr.Textbox(label="Recipient Email", placeholder="example@email.com") subj = gr.Textbox(label="Subject", placeholder="Enter email subject") msg = gr.Textbox(lines=8, label="Context / Message Body", placeholder="Describe what you want to say...") btn = gr.Button("Generate Email Draft", variant="primary") out = gr.Textbox(lines=12, label="Draft Email") email_file = gr.File(label="Download Email") btn.click(email_ui, inputs=[recipient, subj, msg], outputs=[out, email_file]) # CALENDAR TAB with gr.Tab("📅 Calendar Event Creator"): with gr.Group(): title = gr.Textbox(label="Event Title", placeholder="Meeting with team") date = gr.Textbox(label="Date (YYYY-MM-DD)", placeholder="2025-12-01") time = gr.Textbox(label="Time (HH:MM)", placeholder="14:00") desc = gr.Textbox(label="Description", placeholder="Event details...") btn2 = gr.Button("Create Calendar Event", variant="primary") status = gr.Textbox(label="Status") file_out = gr.File(label="Download ICS File") btn2.click(calendar_ui, inputs=[title, date, time, desc], outputs=[status, file_out]) # FORM FILLER TAB (COMPLETE FIXED) with gr.Tab("📋 Form Filler"): with gr.Group(): gr.Markdown(""" ### ✨ Auto Form Filler **Instructions:** 1. Upload your form template (.docx or .xlsx) 2. Enter field values using the format below 3. Click "Fill Form" and download the result **Format (one field per line):** ``` Field Label: Value ``` **Example for membership form:** ``` First Name: John Last Name: Doe Cell Phone: +1-555-1234 Work Phone: +1-555-5678 Email: john@example.com Membership fee: 1000 ``` """) template = gr.File(label="📄 Upload Template (.docx or .xlsx)") form_text = gr.Textbox( lines=10, label="📝 Enter Field Data", placeholder="First Name: John\nLast Name: Doe\nCell Phone: +1-555-1234\nWork Phone: +1-555-5678\nEmail: john@example.com\nMembership fee: 1000", value="" ) btn3 = gr.Button("Fill Form", variant="primary", size="lg") status2 = gr.Textbox(label="Status", lines=6) file2 = gr.File(label="📥 Download Filled Form") btn3.click(fill_form_ui, inputs=[template, form_text], outputs=[status2, file2]) # ORGANIZER with gr.Tab("🗂️ File Organizer"): with gr.Group(): gr.Markdown("Organize uploaded files by type, date, or size") org_btn = gr.Button("Organize Files by Type", variant="primary") org_out = gr.Textbox(lines=10, label="Organization Result") org_btn.click(organize_files_ui, outputs=[org_out]) return ui