import gradio as gr import uuid import time from PIL import Image import os # In-memory "DB" CASES = {} ENGINEERS = ["ENG_Ramesh", "ENG_Suresh", "ENG_Imran"] BANKS = ["State Bank of India", "HDFC Bank", "ICICI Bank"] # Required images checklist (for later completeness calc) REQUIRED_PHOTOS = [ "Street View", "Front Elevation", "Living Room", "Kitchen", "Bedroom", "Bathroom", "Document Scan" ] def create_case(bank, case_name, borrower_name, assigned_engineer, lat, lon, notes): """Create a case with bank details, assigned engineer and coordinates""" case_id = str(uuid.uuid4())[:8] created_at = time.strftime("%Y-%m-%d %H:%M:%S") CASES[case_id] = { "case_id": case_id, "bank": bank, "case_name": case_name or f"Case-{case_id}", "borrower_name": borrower_name, "assigned_engineer": assigned_engineer, "coordinates": {"lat": lat, "lon": lon}, "images": [], # list of dicts {photo_name, filepath, ts} "status": "Assigned to Engineer", "completeness": 0, "timestamp": created_at, "reviewer_status": "Pending", "notes": notes, } return f"Created case {case_id} assigned to {assigned_engineer} for {bank}" def list_cases_for_engineer(engineer): """Return simple table of cases assigned to this engineer""" rows = [] for cid, data in CASES.items(): if data["assigned_engineer"] == engineer: rows.append([cid, data["case_name"], data["borrower_name"], data["status"], f"{data['completeness']}%", data["coordinates"]["lat"], data["coordinates"]["lon"]]) return rows def engineer_upload_to_case(case_id, engineer_name, images): """Attach uploaded images to an existing case (found by case_id). Accepts multiple image file paths (from Gradio upload)""" if not case_id: return "Please provide Case ID to upload images." if case_id not in CASES: return "Case ID not found." # ensure engineer matches assignment (soft check) if CASES[case_id]["assigned_engineer"] != engineer_name: # allow upload but warn warning = f"Warning: case assigned to {CASES[case_id]['assigned_engineer']}, not {engineer_name}." else: warning = "" uploaded_count = 0 if images: for img_path in images: ts = time.strftime("%Y-%m-%d %H:%M:%S") fname = os.path.basename(img_path) CASES[case_id]["images"].append({ "photo_name": fname, "filepath": img_path, "uploaded_by": engineer_name, "timestamp": ts }) uploaded_count += 1 # update completeness (simple heuristic) unique_photos = len(CASES[case_id]["images"]) completeness = int((unique_photos / len(REQUIRED_PHOTOS)) * 100) completeness = min(100, completeness) CASES[case_id]["completeness"] = completeness # update status to indicate submission if uploaded_count > 0: CASES[case_id]["status"] = "Submitted to Data Entry" return f"{warning} Uploaded {uploaded_count} images to case {case_id}. Completeness: {completeness}%" # Data Entry & Reviewer functions (slight updates to show bank & coords) def get_data_entry_cases(): rows = [] for cid, data in CASES.items(): rows.append([cid, data["bank"], data["case_name"], data["borrower_name"], data["assigned_engineer"], data["status"], f"{data['completeness']}%", data["timestamp"]]) return rows def data_entry_action(case_id, action, notes): if case_id not in CASES: return "Case ID not found." if action == "Approve & Send to Reviewer": CASES[case_id]["status"] = "Data Entry Completed" CASES[case_id]["reviewer_status"] = "Review Pending" elif action == "Request Rework": CASES[case_id]["status"] = "Rework Requested" else: return "Invalid Action" CASES[case_id]["notes"] = notes return f"Updated Case {case_id} โ†’ {CASES[case_id]['status']}" def reviewer_dashboard(): rows = [] for cid, data in CASES.items(): rows.append([cid, data["bank"], data["case_name"], data["assigned_engineer"], data["status"], data["reviewer_status"], f"{data['completeness']}%"]) return rows def reviewer_action(case_id, decision): if case_id not in CASES: return "Invalid Case ID" if decision == "Approve": CASES[case_id]["reviewer_status"] = "Approved" CASES[case_id]["status"] = "Completed" else: CASES[case_id]["reviewer_status"] = "Rejected" CASES[case_id]["status"] = "Rejected" return f"Reviewer Updated Case {case_id}: {decision}" def mis_dashboard(): total = len(CASES) completed = len([c for c in CASES.values() if c["status"] == "Completed"]) rework = len([c for c in CASES.values() if c["status"] == "Rework Requested"]) avg_complete = 0 if total > 0: avg_complete = sum([c["completeness"] for c in CASES.values()]) / total # simple listing of recent cases recent = [] for cid, d in sorted(CASES.items(), key=lambda x: x[1]["timestamp"], reverse=True)[:10]: recent.append([cid, d["bank"], d["case_name"], d["assigned_engineer"], d["status"], f"{d['completeness']}%"]) return { "Total Cases": total, "Completed": completed, "Rework Cases": rework, "Average Completeness": f"{avg_complete:.2f}%", "Recent Cases (top 10)": recent } # ---------- UI LAYOUT ---------- with gr.Blocks(title="Property Valuation Automation POC - Case Initiation") as demo: gr.Markdown("# ๐Ÿฆ Case Initiation โ€” Bank Details + Assignment") gr.Markdown("Create case with bank selection (3 banks), assign to an engineer, provide coordinates.") # Case Creation with gr.Row(): with gr.Column(scale=1): bank_dropdown = gr.Dropdown(choices=BANKS, value=BANKS[0], label="Select Bank") case_name = gr.Textbox(label="Case Name (optional)") borrower_name = gr.Textbox(label="Borrower Name") engineer_dropdown = gr.Dropdown(choices=ENGINEERS, value=ENGINEERS[0], label="Assign to Engineer") with gr.Column(scale=1): lat_input = gr.Textbox(label="Latitude (ex: 17.4390)", value="17.4390") lon_input = gr.Textbox(label="Longitude (ex: 78.4983)", value="78.4983") notes_input = gr.Textbox(label="Notes / Instructions (optional)") create_btn = gr.Button("Create Case & Assign") create_output = gr.Textbox(label="Create Case Output") create_btn.click(create_case, [bank_dropdown, case_name, borrower_name, engineer_dropdown, lat_input, lon_input, notes_input], create_output) gr.Markdown("----") gr.Markdown("## ๐Ÿ‘ท Engineer Panel โ€” Assigned Cases & Upload Images") with gr.Row(): engineer_select = gr.Dropdown(choices=ENGINEERS, value=ENGINEERS[0], label="Select Engineer to View Assigned Cases") refresh_eng = gr.Button("Refresh Assigned Cases") eng_cases_table = gr.DataFrame(headers=["Case ID","Case Name","Borrower","Status","Completeness","Lat","Lon"], interactive=False) refresh_eng.click(list_cases_for_engineer, engineer_select, eng_cases_table) gr.Markdown("Upload images to a selected case (paste case id from table):") with gr.Row(): eng_case_id_input = gr.Textbox(label="Case ID") eng_name_input = gr.Dropdown(choices=ENGINEERS, value=ENGINEERS[0], label="Uploading Engineer") eng_images = gr.File(label="Upload Photos (multiple)", file_count="multiple", type="filepath") eng_upload_btn = gr.Button("Upload Images to Case") eng_upload_output = gr.Textbox(label="Upload Response") eng_upload_btn.click(engineer_upload_to_case, [eng_case_id_input, eng_name_input, eng_images], eng_upload_output) gr.Markdown("----") gr.Markdown("## ๐Ÿงพ Data Entry Panel") data_table = gr.DataFrame(headers=["Case ID","Bank","Case Name","Borrower","Engineer","Status","Completeness","Created At"], label="Cases", interactive=False) refresh_btn = gr.Button("Refresh List") refresh_btn.click(get_data_entry_cases, None, data_table) with gr.Row(): case_id_input = gr.Textbox(label="Case ID") action = gr.Radio(["Approve & Send to Reviewer", "Request Rework"], label="Action") notes = gr.Textbox(label="Notes") update_btn = gr.Button("Update Status") data_entry_output = gr.Textbox(label="Response") update_btn.click(data_entry_action, [case_id_input, action, notes], data_entry_output) gr.Markdown("----") gr.Markdown("## โœ… Reviewer Panel") reviewer_table = gr.DataFrame(headers=["Case ID","Bank","Case Name","Engineer","Status","Review Status","Completeness"], label="Reviewer Queue", interactive=False) refresh_review = gr.Button("Refresh Reviewer Queue") refresh_review.click(reviewer_dashboard, None, reviewer_table) with gr.Row(): reviewer_case = gr.Textbox(label="Case ID") review_decision = gr.Radio(["Approve", "Reject"], label="Decision") review_btn = gr.Button("Submit Review") review_output = gr.Textbox(label="Output") review_btn.click(reviewer_action, [reviewer_case, review_decision], review_output) gr.Markdown("----") gr.Markdown("## ๐Ÿ“Š MIS Dashboard") mis_out = gr.JSON(label="MIS Summary") mis_refresh_btn = gr.Button("Refresh MIS") mis_refresh_btn.click(mis_dashboard, None, mis_out) demo.launch()