File size: 9,709 Bytes
d980008
 
 
 
3a90b51
d980008
3a90b51
d980008
3a90b51
 
d980008
3a90b51
d980008
 
 
 
 
 
 
 
 
 
3a90b51
 
d980008
3a90b51
d980008
 
3a90b51
 
 
 
 
 
 
 
 
d980008
3a90b51
d980008
3a90b51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d980008
3a90b51
 
d980008
3a90b51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d980008
 
 
3a90b51
 
d980008
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3a90b51
 
d980008
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3a90b51
 
 
 
 
 
d980008
 
 
 
 
3a90b51
d980008
 
 
 
 
3a90b51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d980008
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
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()