Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import sqlite3 | |
| import os | |
| import datetime | |
| DB_FILE = "cases.db" | |
| # ----------------------------- | |
| # Database setup | |
| # ----------------------------- | |
| def init_db(): | |
| conn = sqlite3.connect(DB_FILE) | |
| c = conn.cursor() | |
| # Cases table | |
| c.execute('''CREATE TABLE IF NOT EXISTS summons_cases ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| name TEXT, | |
| address TEXT, | |
| ticket_number TEXT UNIQUE, | |
| vehicle_number TEXT, | |
| road_name TEXT, | |
| town_city TEXT, | |
| state TEXT, | |
| offence_en TEXT, | |
| offence_bm TEXT, | |
| offence_cn TEXT, | |
| base_fine REAL, | |
| status TEXT, | |
| created_at TEXT, | |
| updated_at TEXT | |
| )''') | |
| # Appeals table | |
| c.execute('''CREATE TABLE IF NOT EXISTS appeals ( | |
| appeal_id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| ticket_number TEXT, | |
| appeal_text TEXT, | |
| appeal_to TEXT, | |
| decision TEXT, | |
| final_fine REAL, | |
| created_at TEXT, | |
| updated_at TEXT | |
| )''') | |
| conn.commit() | |
| conn.close() | |
| def seed_mock_data(): | |
| """Seed Ali, Ah Kow, Muthu if DB empty""" | |
| conn = sqlite3.connect(DB_FILE) | |
| c = conn.cursor() | |
| c.execute("SELECT COUNT(*) FROM summons_cases") | |
| if c.fetchone()[0] == 0: | |
| now = datetime.datetime.now().isoformat() | |
| cases = [ | |
| ("Ali", "12, Jalan Kenanga 3, Taman Seri, 75450 Melaka", "K250901234", "VDK8821", | |
| "Jalan Lembongan", "Melaka", "Melaka Tengah", | |
| "Not obeying correct lane usage", | |
| "Tidak mematuhi lorong yang betul", | |
| "未按规定车道行驶", | |
| 300.00, "ISSUED", now, now), | |
| ("Ah Kow", "88, Jalan Merdeka, 75000 Melaka", "K250901235", "MCX8899", | |
| "Jalan Merdeka", "Melaka", "Melaka Tengah", | |
| "Speeding over 120km/h in city zone", | |
| "Memandu melebihi 120km/j di kawasan bandar", | |
| "在市区超速驾驶超过120公里/小时", | |
| 250.00, "ISSUED", now, now), | |
| ("Muthu", "5, Jalan Bunga Raya, 11000 Pulau Pinang", "K250901236", "PGX5521", | |
| "Jalan Bunga Raya", "George Town", "Pulau Pinang", | |
| "Parking in a no-parking zone", | |
| "Letak kenderaan di kawasan larangan", | |
| "在禁止停车区停车", | |
| 100.00, "ISSUED", now, now) | |
| ] | |
| c.executemany('''INSERT INTO summons_cases | |
| (name, address, ticket_number, vehicle_number, road_name, town_city, state, | |
| offence_en, offence_bm, offence_cn, base_fine, status, created_at, updated_at) | |
| VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', cases) | |
| conn.commit() | |
| conn.close() | |
| # ----------------------------- | |
| # DB Helper | |
| # ----------------------------- | |
| def find_case(ticket_number, name, vehicle_number): | |
| conn = sqlite3.connect(DB_FILE) | |
| c = conn.cursor() | |
| c.execute("""SELECT * FROM summons_cases | |
| WHERE ticket_number=? OR name=? OR vehicle_number=?""", | |
| (ticket_number, name, vehicle_number)) | |
| row = c.fetchone() | |
| conn.close() | |
| return row | |
| # ----------------------------- | |
| # Citizen Portal | |
| # ----------------------------- | |
| def create_case(name, address, ticket_number, vehicle_number, road_name, town_city, state, | |
| offence_en, offence_bm, offence_cn, base_fine): | |
| now = datetime.datetime.now().isoformat() | |
| conn = sqlite3.connect(DB_FILE) | |
| c = conn.cursor() | |
| try: | |
| c.execute('''INSERT INTO summons_cases | |
| (name, address, ticket_number, vehicle_number, road_name, town_city, state, | |
| offence_en, offence_bm, offence_cn, base_fine, status, created_at, updated_at) | |
| VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', | |
| (name, address, ticket_number, vehicle_number, road_name, town_city, state, | |
| offence_en, offence_bm, offence_cn, base_fine, "ISSUED", now, now)) | |
| conn.commit() | |
| return "✅ Case created successfully / Kes berjaya dicipta / 案件创建成功" | |
| except sqlite3.IntegrityError: | |
| return "❌ Case already exists / Kes sudah wujud / 案件已存在" | |
| finally: | |
| conn.close() | |
| def view_case(ticket_number, name, vehicle_number): | |
| row = find_case(ticket_number, name, vehicle_number) | |
| if not row: | |
| return "❌ Case not found / Kes tidak dijumpai / 未找到案件" | |
| return ( | |
| f"Case / Kes / 案件 — Ticket: {row[3]}\n" | |
| f"Name / Nama / 姓名: {row[1]}\n" | |
| f"Address / Alamat / 地址: {row[2]}\n\n" | |
| f"Vehicle No. / No. Kenderaan / 车牌号码: {row[4]}\n" | |
| f"Road / Jalan / 道路: {row[5]}\n" | |
| f"Town/City / Bandar / 城市: {row[6]}\n" | |
| f"State / Negeri / 州: {row[7]}\n\n" | |
| f"Offence (EN): {row[8]}\n" | |
| f"Kesalahan (BM): {row[9]}\n" | |
| f"违法 (中文): {row[10]}\n\n" | |
| f"Base Fine / Denda Asal / 原始罚款: RM {row[11]:.2f}\n" | |
| f"Status / Status / 状态: {row[12]}\n\n" | |
| f"Created / Dicipta / 创建: {row[13]}\n" | |
| f"Updated / Dikemaskini / 更新: {row[14]}" | |
| ) | |
| def appeal_to_pdrm(ticket_number, appeal_text): | |
| now = datetime.datetime.now().isoformat() | |
| conn = sqlite3.connect(DB_FILE) | |
| c = conn.cursor() | |
| c.execute('''INSERT INTO appeals (ticket_number, appeal_text, appeal_to, decision, final_fine, created_at, updated_at) | |
| VALUES (?, ?, ?, ?, ?, ?, ?)''', | |
| (ticket_number, appeal_text, "PDRM", None, None, now, now)) | |
| conn.commit() | |
| conn.close() | |
| return "📨 Appeal submitted to PDRM / Rayuan dihantar ke PDRM / 上诉已提交给皇家警察" | |
| def appeal_to_magistrate(ticket_number, appeal_text): | |
| now = datetime.datetime.now().isoformat() | |
| conn = sqlite3.connect(DB_FILE) | |
| c = conn.cursor() | |
| c.execute('''INSERT INTO appeals (ticket_number, appeal_text, appeal_to, decision, final_fine, created_at, updated_at) | |
| VALUES (?, ?, ?, ?, ?, ?, ?)''', | |
| (ticket_number, appeal_text, "MAGISTRATE", None, None, now, now)) | |
| conn.commit() | |
| conn.close() | |
| return "📨 Appeal submitted to Magistrate / Rayuan dihantar ke Majistret / 上诉已提交给地方法官" | |
| def view_appeal_status(ticket_number): | |
| conn = sqlite3.connect(DB_FILE) | |
| c = conn.cursor() | |
| c.execute("SELECT decision, final_fine FROM appeals WHERE ticket_number=? ORDER BY appeal_id DESC LIMIT 1", (ticket_number,)) | |
| row = c.fetchone() | |
| decision, final_fine = None, None | |
| # Predefined outcomes | |
| if ticket_number == "K250901234": # Ali | |
| decision, final_fine = "APPROVED_REDUCED", 150.00 | |
| elif ticket_number == "K250901235": # Ah Kow | |
| decision, final_fine = "REJECTED", 250.00 | |
| elif ticket_number == "K250901236": # Muthu | |
| decision, final_fine = "MAINTAINED", 100.00 | |
| if not row or not row[0]: | |
| c.execute("UPDATE appeals SET decision=?, final_fine=? WHERE ticket_number=?", | |
| (decision, final_fine, ticket_number)) | |
| conn.commit() | |
| else: | |
| decision, final_fine = row | |
| conn.close() | |
| decision_map = { | |
| "APPROVED_REDUCED": "APPROVED_REDUCED / DILULUSKAN & DIKURANGKAN / 批准并减免", | |
| "REJECTED": "REJECTED / DITOLAK / 驳回", | |
| "MAINTAINED": "MAINTAINED / DIKEKALKAN / 维持原判" | |
| } | |
| decision_str = decision_map.get(decision, decision) | |
| fine_str = "Pending / Menunggu / 待定" if final_fine is None else f"RM {final_fine:.2f}" | |
| return ( | |
| f"Appeal Status / Status Rayuan / 上诉状态 — Ticket: {ticket_number}\n" | |
| f"Decision / Keputusan / 决定: {decision_str}\n" | |
| f"Final Fine / Denda Akhir / 最终罚款: {fine_str}" | |
| ) | |
| def pay_fine(ticket_number): | |
| return f"💳 Payment successful / Bayaran berjaya / 支付成功 — Ticket: {ticket_number}. Receipt issued / Resit dikeluarkan / 收据已发出." | |
| # ----------------------------- | |
| # Gradio UI | |
| # ----------------------------- | |
| def citizen_portal(): | |
| with gr.Tab("Citizen Portal / Portal Warganegara / 公民门户"): | |
| with gr.Tab("Create Case / Cipta Kes / 创建案件"): | |
| name = gr.Textbox(label="Name / Nama / 姓名") | |
| address = gr.Textbox(label="Address / Alamat / 地址") | |
| ticket_number = gr.Textbox(label="Ticket Number / Nombor Saman / 传票号码") | |
| vehicle_number = gr.Textbox(label="Vehicle No. / No. Kenderaan / 车牌号码") | |
| road_name = gr.Textbox(label="Road / Jalan / 道路") | |
| town_city = gr.Textbox(label="Town/City / Bandar / 城市") | |
| state = gr.Textbox(label="State / Negeri / 州") | |
| offence_en = gr.Textbox(label="Offence (EN)") | |
| offence_bm = gr.Textbox(label="Kesalahan (BM)") | |
| offence_cn = gr.Textbox(label="违法 (中文)") | |
| base_fine = gr.Number(label="Base Fine / Denda Asal / 原始罚款", value=300.00) | |
| create_btn = gr.Button("Create / Cipta / 创建") | |
| create_output = gr.Textbox(label="Result / Keputusan / 结果") | |
| create_btn.click(create_case, [name, address, ticket_number, vehicle_number, | |
| road_name, town_city, state, | |
| offence_en, offence_bm, offence_cn, base_fine], | |
| create_output) | |
| with gr.Tab("View Case / Lihat Kes / 查看案件"): | |
| vc_ticket = gr.Textbox(label="Ticket Number / Nombor Saman / 传票号码") | |
| vc_name = gr.Textbox(label="Name / Nama / 姓名") | |
| vc_vehicle = gr.Textbox(label="Vehicle No. / No. Kenderaan / 车牌号码") | |
| view_btn = gr.Button("View / Lihat / 查看") | |
| view_output = gr.Textbox(label="Case Details / Butiran Kes / 案件详情", lines=15) | |
| view_btn.click(view_case, [vc_ticket, vc_name, vc_vehicle], view_output) | |
| with gr.Tab("Submit Appeal / Hantar Rayuan / 提交上诉"): | |
| sa_ticket = gr.Textbox(label="Ticket Number / Nombor Saman / 传票号码") | |
| sa_text = gr.Textbox(label="Appeal Text / Teks Rayuan / 上诉内容") | |
| sa_pdrm_btn = gr.Button("Appeal to PDRM / Rayuan ke PDRM / 向皇家警察上诉") | |
| sa_mag_btn = gr.Button("Appeal to Magistrate / Rayuan ke Majistret / 向地方法官上诉") | |
| sa_output = gr.Textbox(label="Result / Keputusan / 结果") | |
| sa_pdrm_btn.click(appeal_to_pdrm, [sa_ticket, sa_text], sa_output) | |
| sa_mag_btn.click(appeal_to_magistrate, [sa_ticket, sa_text], sa_output) | |
| with gr.Tab("View Appeal Status / Lihat Status Rayuan / 查看上诉状态"): | |
| vas_ticket = gr.Textbox(label="Ticket Number / Nombor Saman / 传票号码") | |
| vas_btn = gr.Button("Check / Semak / 检查") | |
| vas_output = gr.Textbox(label="Appeal Status / Status Rayuan / 上诉状态", lines=5) | |
| vas_btn.click(view_appeal_status, [vas_ticket], vas_output) | |
| with gr.Tab("Pay Fine / Bayar Denda / 缴纳罚款"): | |
| pf_ticket = gr.Textbox(label="Ticket Number / Nombor Saman / 传票号码") | |
| pf_btn = gr.Button("Pay / Bayar / 支付") | |
| pf_output = gr.Textbox(label="Result / Keputusan / 结果") | |
| pf_btn.click(pay_fine, [pf_ticket], pf_output) | |
| # ----------------------------- | |
| # Launch | |
| # ----------------------------- | |
| init_db() | |
| seed_mock_data() | |
| with gr.Blocks() as demo: | |
| gr.Markdown("## 🚦 SwiftCase.ai — Smart Traffic Justice Platform") | |
| citizen_portal() | |
| if __name__ == "__main__": | |
| demo.launch() | |