POC_Valuation / app.py
dschandra's picture
Update app.py
3a90b51 verified
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()