Benny-Tang commited on
Commit
2807f04
·
verified ·
1 Parent(s): ecc439f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +102 -147
app.py CHANGED
@@ -3,7 +3,6 @@ import sqlite3
3
  import os
4
  import datetime
5
  import random
6
- import json
7
 
8
  DB_FILE = "cases.db"
9
 
@@ -14,37 +13,46 @@ def init_db():
14
  conn = sqlite3.connect(DB_FILE)
15
  c = conn.cursor()
16
 
17
- # Tables
18
  c.execute("""CREATE TABLE IF NOT EXISTS summons_cases (
19
  case_id INTEGER PRIMARY KEY AUTOINCREMENT,
20
  citizen_name TEXT,
 
 
 
 
 
 
21
  offence_en TEXT,
22
  offence_bm TEXT,
23
  offence_cn TEXT,
24
  fine_amount REAL,
25
- status TEXT,
26
- evidence_files TEXT
27
  )""")
28
 
 
29
  c.execute("""CREATE TABLE IF NOT EXISTS appeals (
30
  appeal_id INTEGER PRIMARY KEY AUTOINCREMENT,
31
  case_id INTEGER,
32
  appeal_text TEXT,
33
- evidence_file TEXT,
34
  target TEXT,
35
  created_at TEXT
36
  )""")
37
 
 
38
  c.execute("""CREATE TABLE IF NOT EXISTS reviews (
39
  review_id INTEGER PRIMARY KEY AUTOINCREMENT,
40
  case_id INTEGER,
41
  reviewer TEXT,
42
  decision TEXT,
43
- rationale TEXT,
 
 
44
  reduced_fine REAL,
45
  created_at TEXT
46
  )""")
47
 
 
48
  c.execute("""CREATE TABLE IF NOT EXISTS payments (
49
  payment_id INTEGER PRIMARY KEY AUTOINCREMENT,
50
  case_id INTEGER,
@@ -52,6 +60,7 @@ def init_db():
52
  paid_at TEXT
53
  )""")
54
 
 
55
  c.execute("""CREATE TABLE IF NOT EXISTS receipts (
56
  receipt_id INTEGER PRIMARY KEY AUTOINCREMENT,
57
  payment_id INTEGER,
@@ -59,27 +68,6 @@ def init_db():
59
  issued_at TEXT
60
  )""")
61
 
62
- c.execute("""CREATE TABLE IF NOT EXISTS audit_logs (
63
- log_id INTEGER PRIMARY KEY AUTOINCREMENT,
64
- case_id INTEGER,
65
- actor TEXT,
66
- action TEXT,
67
- log_text TEXT,
68
- created_at TEXT
69
- )""")
70
-
71
- # Seed mock data if empty
72
- c.execute("SELECT COUNT(*) FROM summons_cases")
73
- if c.fetchone()[0] == 0:
74
- cases = [
75
- ("Ali", "Not obeying correct lane", "Tidak mematuhi lorong yang betul", "未按规定车道行驶", 300.0, "ISSUED"),
76
- ("Ah Kow", "Running a red light", "Melanggar lampu merah", "闯红灯", 250.0, "APPEAL_PENDING"),
77
- ("Muthu", "Illegal parking", "Letak kereta haram", "非法停车", 100.0, "APPEAL_APPROVED_REDUCED"),
78
- ]
79
- c.executemany(
80
- "INSERT INTO summons_cases (citizen_name, offence_en, offence_bm, offence_cn, fine_amount, status) VALUES (?,?,?,?,?,?)",
81
- cases
82
- )
83
  conn.commit()
84
  conn.close()
85
 
@@ -88,113 +76,47 @@ init_db()
88
  # ----------------------
89
  # Helpers
90
  # ----------------------
91
- def log_action(case_id, actor, action, log_text):
92
- conn = sqlite3.connect(DB_FILE)
93
- c = conn.cursor()
94
- c.execute(
95
- "INSERT INTO audit_logs (case_id, actor, action, log_text, created_at) VALUES (?,?,?,?,?)",
96
- (case_id, actor, action, log_text, datetime.datetime.now().isoformat())
97
- )
98
- conn.commit()
99
- conn.close()
100
-
101
- def autonomous_pdrm_decision(case_id):
102
- """Auto-decide compound fine appeals using rules"""
103
- conn = sqlite3.connect(DB_FILE)
104
- c = conn.cursor()
105
- c.execute("SELECT fine_amount FROM summons_cases WHERE case_id=?", (case_id,))
106
- row = c.fetchone()
107
- if not row:
108
- conn.close()
109
- return None
110
- fine = row[0]
111
-
112
- # Rules: simple example
113
- if fine > 200:
114
- decision = "ApproveReduced"
115
- reduced_fine = fine * 0.5
116
- rationale = "Pengurangan denda automatik: kesalahan ringan."
117
- else:
118
- decision = "Reject"
119
- reduced_fine = None
120
- rationale = "Permohonan ditolak automatik: denda rendah."
121
-
122
- # Save review
123
- c.execute(
124
- "INSERT INTO reviews (case_id, reviewer, decision, rationale, reduced_fine, created_at) VALUES (?,?,?,?,?,?)",
125
- (case_id, "PDRM-AI", decision, rationale, reduced_fine, datetime.datetime.now().isoformat())
126
- )
127
- new_status = "APPEAL_APPROVED_REDUCED" if decision == "ApproveReduced" else "APPEAL_REJECTED"
128
- c.execute("UPDATE summons_cases SET status=?, fine_amount=? WHERE case_id=?", (new_status, reduced_fine if reduced_fine else fine, case_id))
129
- conn.commit()
130
- conn.close()
131
-
132
- log_text = f"PDRM-AI membuat keputusan: {decision}, sebab: {rationale}"
133
- log_action(case_id, "PDRM-AI", "auto_review", log_text)
134
- return decision, rationale, reduced_fine
135
-
136
- def autonomous_magistrate_decision(case_id):
137
- """AI-assisted magistrate review"""
138
  conn = sqlite3.connect(DB_FILE)
139
  c = conn.cursor()
140
- c.execute("SELECT fine_amount FROM summons_cases WHERE case_id=?", (case_id,))
141
- row = c.fetchone()
142
- if not row:
143
- conn.close()
144
- return None
145
- fine = row[0]
146
-
147
- # Rules: small fines often waived, medium fines reduced, high fines rejected
148
- if fine <= 100:
149
- decision = "ApproveNoFine"
150
- reduced_fine = 0
151
- rationale = "Kesalahan kecil, denda dihapuskan automatik."
152
- elif fine <= 250:
153
- decision = "ApproveReduced"
154
- reduced_fine = fine * 0.5
155
- rationale = "Kesalahan sederhana, denda dikurangkan automatik."
156
- else:
157
- decision = "Reject"
158
- reduced_fine = None
159
- rationale = "Kesalahan serius, rayuan ditolak automatik."
160
-
161
- # Save review
162
  c.execute(
163
- "INSERT INTO reviews (case_id, reviewer, decision, rationale, reduced_fine, created_at) VALUES (?,?,?,?,?,?)",
164
- (case_id, "Magistrate-AI", decision, rationale, reduced_fine, datetime.datetime.now().isoformat())
 
 
165
  )
166
- new_status = "APPEAL_APPROVED_REDUCED" if decision == "ApproveReduced" else \
167
- "APPEAL_APPROVED_NOFINE" if decision == "ApproveNoFine" else \
168
- "APPEAL_REJECTED"
169
- c.execute("UPDATE summons_cases SET status=?, fine_amount=? WHERE case_id=?", (new_status, reduced_fine if reduced_fine else fine, case_id))
170
  conn.commit()
171
  conn.close()
 
172
 
173
- log_text = f"Magistrate-AI decision: {decision}, reason: {rationale}"
174
- log_action(case_id, "Magistrate-AI", "auto_review", log_text)
175
- return decision, rationale, reduced_fine
176
-
177
- # ----------------------
178
- # Citizen Portal
179
- # ----------------------
180
  def view_case(case_id):
181
  conn = sqlite3.connect(DB_FILE)
182
  c = conn.cursor()
183
- c.execute("SELECT case_id, citizen_name, offence_en, offence_bm, offence_cn, fine_amount, status FROM summons_cases WHERE case_id=?", (case_id,))
184
  row = c.fetchone()
185
  conn.close()
186
  if not row:
187
  return "❌ Case not found."
188
- case_id, citizen_name, offence_en, offence_bm, offence_cn, fine, status = row
189
- return f"""
190
- 🆔 Case ID: {case_id}
191
- 👤 Name: {citizen_name}
192
-
193
- Offence (EN): {offence_en}
194
- Kesalahan (BM): {offence_bm}
195
- 违法 (中文): {offence_cn}
196
 
197
- 💰 Fine: RM {fine:.2f}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  📌 Status: {status}
199
  """
200
 
@@ -208,15 +130,20 @@ def submit_appeal(case_id, appeal_text, target):
208
  c.execute("UPDATE summons_cases SET status=? WHERE case_id=?", ("APPEAL_PENDING", case_id))
209
  conn.commit()
210
  conn.close()
211
- log_action(case_id, "Citizen", "submit_appeal", f"Appeal submitted to {target}.")
212
-
213
- # Autonomous processing
214
- if target == "PDRM":
215
- decision = autonomous_pdrm_decision(case_id)
216
- return f"✅ Appeal submitted to PDRM.\n🤖 Auto-decision: {decision}"
217
- else:
218
- decision = autonomous_magistrate_decision(case_id)
219
- return f"✅ Appeal submitted to Magistrate.\n🤖 Auto-decision: {decision}"
 
 
 
 
 
220
 
221
  def pay_fine(case_id):
222
  conn = sqlite3.connect(DB_FILE)
@@ -235,30 +162,57 @@ def pay_fine(case_id):
235
  c.execute("UPDATE summons_cases SET status=? WHERE case_id=?", ("PAID", case_id))
236
  conn.commit()
237
  conn.close()
238
- log_action(case_id, "Citizen", "pay_fine", f"Fine RM{fine} paid. Receipt {receipt_no}.")
239
- return f"✅ Fine paid RM {fine:.2f}. Receipt: {receipt_no}"
 
 
 
 
240
 
241
  # ----------------------
242
- # Gradio Interface
243
  # ----------------------
244
  with gr.Blocks() as demo:
245
- gr.Markdown("# 🚦 SwiftCase.ai – Citizen Portal (Autonomous)")
246
- with gr.Tab("View Case"):
247
- case_id_in = gr.Number(label="Enter Case ID", value=1)
248
- case_out = gr.Textbox(label="Case Details", lines=10)
249
- view_btn = gr.Button("View Case")
250
- view_btn.click(fn=view_case, inputs=case_id_in, outputs=case_out)
251
- with gr.Tab("Submit Appeal"):
252
- appeal_case_id = gr.Number(label="Case ID")
253
- appeal_text = gr.Textbox(label="Appeal Text", lines=3)
254
- appeal_target = gr.Radio(choices=["PDRM", "Magistrate"], label="Submit Appeal To")
255
- appeal_btn = gr.Button("Submit Appeal")
256
- appeal_out = gr.Textbox(label="Appeal Status")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  appeal_btn.click(fn=submit_appeal, inputs=[appeal_case_id, appeal_text, appeal_target], outputs=appeal_out)
258
- with gr.Tab("Pay Fine"):
259
- pay_case_id = gr.Number(label="Case ID")
260
- pay_btn = gr.Button("Pay Fine")
261
- pay_out = gr.Textbox(label="Payment Result")
 
262
  pay_btn.click(fn=pay_fine, inputs=pay_case_id, outputs=pay_out)
263
 
264
  if __name__ == "__main__":
@@ -274,3 +228,4 @@ if __name__ == "__main__":
274
 
275
 
276
 
 
 
3
  import os
4
  import datetime
5
  import random
 
6
 
7
  DB_FILE = "cases.db"
8
 
 
13
  conn = sqlite3.connect(DB_FILE)
14
  c = conn.cursor()
15
 
16
+ # Summons table with full details
17
  c.execute("""CREATE TABLE IF NOT EXISTS summons_cases (
18
  case_id INTEGER PRIMARY KEY AUTOINCREMENT,
19
  citizen_name TEXT,
20
+ address TEXT,
21
+ ticket_number TEXT,
22
+ vehicle_number TEXT,
23
+ road_name TEXT,
24
+ town_city TEXT,
25
+ state TEXT,
26
  offence_en TEXT,
27
  offence_bm TEXT,
28
  offence_cn TEXT,
29
  fine_amount REAL,
30
+ status TEXT
 
31
  )""")
32
 
33
+ # Appeals
34
  c.execute("""CREATE TABLE IF NOT EXISTS appeals (
35
  appeal_id INTEGER PRIMARY KEY AUTOINCREMENT,
36
  case_id INTEGER,
37
  appeal_text TEXT,
 
38
  target TEXT,
39
  created_at TEXT
40
  )""")
41
 
42
+ # Reviews (AI or human)
43
  c.execute("""CREATE TABLE IF NOT EXISTS reviews (
44
  review_id INTEGER PRIMARY KEY AUTOINCREMENT,
45
  case_id INTEGER,
46
  reviewer TEXT,
47
  decision TEXT,
48
+ rationale_en TEXT,
49
+ rationale_bm TEXT,
50
+ rationale_cn TEXT,
51
  reduced_fine REAL,
52
  created_at TEXT
53
  )""")
54
 
55
+ # Payments
56
  c.execute("""CREATE TABLE IF NOT EXISTS payments (
57
  payment_id INTEGER PRIMARY KEY AUTOINCREMENT,
58
  case_id INTEGER,
 
60
  paid_at TEXT
61
  )""")
62
 
63
+ # Receipts
64
  c.execute("""CREATE TABLE IF NOT EXISTS receipts (
65
  receipt_id INTEGER PRIMARY KEY AUTOINCREMENT,
66
  payment_id INTEGER,
 
68
  issued_at TEXT
69
  )""")
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  conn.commit()
72
  conn.close()
73
 
 
76
  # ----------------------
77
  # Helpers
78
  # ----------------------
79
+ def insert_case(name, address, ticket_number, vehicle, road, town, state, offence_en, offence_bm, offence_cn, fine):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  conn = sqlite3.connect(DB_FILE)
81
  c = conn.cursor()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  c.execute(
83
+ """INSERT INTO summons_cases
84
+ (citizen_name, address, ticket_number, vehicle_number, road_name, town_city, state, offence_en, offence_bm, offence_cn, fine_amount, status)
85
+ VALUES (?,?,?,?,?,?,?,?,?,?,?,?)""",
86
+ (name, address, ticket_number, vehicle, road, town, state, offence_en, offence_bm, offence_cn, fine, "ISSUED")
87
  )
 
 
 
 
88
  conn.commit()
89
  conn.close()
90
+ return "✅ Summons case created successfully."
91
 
 
 
 
 
 
 
 
92
  def view_case(case_id):
93
  conn = sqlite3.connect(DB_FILE)
94
  c = conn.cursor()
95
+ c.execute("SELECT * FROM summons_cases WHERE case_id=?", (case_id,))
96
  row = c.fetchone()
97
  conn.close()
98
  if not row:
99
  return "❌ Case not found."
100
+ (
101
+ case_id, citizen_name, address, ticket_number, vehicle, road, town, state,
102
+ offence_en, offence_bm, offence_cn, fine, status
103
+ ) = row
 
 
 
 
104
 
105
+ return f"""
106
+ 🆔 Case ID / Nombor Kes / 案件编号: {case_id}
107
+ 👤 Name / Nama / 姓名: {citizen_name}
108
+ 🏠 Address / Alamat / 地址: {address}
109
+ 📄 Ticket No. / Nombor Saman / 罚单号码: {ticket_number}
110
+ 🚗 Vehicle No. / Nombor Kenderaan / 车牌号码: {vehicle}
111
+ 🛣 Road / Jalan / 道路: {road}
112
+ 🏙 Town/City / Bandar / 城市: {town}
113
+ 🗺 State / Negeri / 州: {state}
114
+
115
+ ⚖️ Offence (EN): {offence_en}
116
+ ⚖️ Kesalahan (BM): {offence_bm}
117
+ ⚖️ 违法 (中文): {offence_cn}
118
+
119
+ 💰 Fine / Denda / 罚款: RM {fine:.2f}
120
  📌 Status: {status}
121
  """
122
 
 
130
  c.execute("UPDATE summons_cases SET status=? WHERE case_id=?", ("APPEAL_PENDING", case_id))
131
  conn.commit()
132
  conn.close()
133
+
134
+ # Generate AI recommendation text
135
+ rationale_en = "AI suggests reducing fine due to mitigating factors."
136
+ rationale_bm = "AI mencadangkan pengurangan denda kerana faktor meringankan."
137
+ rationale_cn = "人工智能建议减轻罚款,因为有减轻因素。"
138
+
139
+ return f"""
140
+ Appeal Submitted / Rayuan Dihantar / 上诉已提交
141
+ 📌 Target: {target}
142
+
143
+ 🤖 Recommendation (EN): {rationale_en}
144
+ 🤖 Cadangan (BM): {rationale_bm}
145
+ 🤖 建议 (中文): {rationale_cn}
146
+ """
147
 
148
  def pay_fine(case_id):
149
  conn = sqlite3.connect(DB_FILE)
 
162
  c.execute("UPDATE summons_cases SET status=? WHERE case_id=?", ("PAID", case_id))
163
  conn.commit()
164
  conn.close()
165
+
166
+ return f"""
167
+ ✅ Fine Paid / Denda Dibayar / 已付款
168
+ 💰 Amount / Jumlah / 金额: RM {fine:.2f}
169
+ 🧾 Receipt No. / No. Resit / 收据号码: {receipt_no}
170
+ """
171
 
172
  # ----------------------
173
+ # Gradio UI
174
  # ----------------------
175
  with gr.Blocks() as demo:
176
+ gr.Markdown("# 🚦 SwiftCase.ai – Citizen Portal (3 Languages / 3 Bahasa)")
177
+
178
+ with gr.Tab(" Create Case"):
179
+ name = gr.Textbox(label="Name / Nama / 姓名")
180
+ address = gr.Textbox(label="Address / Alamat / 地址")
181
+ ticket_number = gr.Textbox(label="Summon Ticket No. / Nombor Saman / 罚单号码")
182
+ vehicle_number = gr.Textbox(label="Vehicle No. / Nombor Kenderaan / 车牌号码")
183
+ road_name = gr.Textbox(label="Road / Jalan / 道路")
184
+ town_city = gr.Textbox(label="Town/City / Bandar / 城市")
185
+ state = gr.Textbox(label="State / Negeri / ")
186
+ offence_en = gr.Textbox(label="Offence (EN)")
187
+ offence_bm = gr.Textbox(label="Kesalahan (BM)")
188
+ offence_cn = gr.Textbox(label="违法 (中文)")
189
+ fine_amount = gr.Number(label="Fine Amount (RM)", value=300)
190
+ create_btn = gr.Button("Create Case / Buat Kes / 建立案件")
191
+ create_out = gr.Textbox(label="Result / Keputusan / 结果")
192
+ create_btn.click(
193
+ fn=insert_case,
194
+ inputs=[name, address, ticket_number, vehicle_number, road_name, town_city, state, offence_en, offence_bm, offence_cn, fine_amount],
195
+ outputs=create_out
196
+ )
197
+
198
+ with gr.Tab("🔍 View Case"):
199
+ view_case_id = gr.Number(label="Enter Case ID / Masukkan Nombor Kes / 输入案件编号", value=1)
200
+ view_btn = gr.Button("View Case / Lihat Kes / 查看案件")
201
+ view_out = gr.Textbox(label="Case Details / Butiran Kes / 案件详情", lines=15)
202
+ view_btn.click(fn=view_case, inputs=view_case_id, outputs=view_out)
203
+
204
+ with gr.Tab("📨 Submit Appeal"):
205
+ appeal_case_id = gr.Number(label="Case ID / Nombor Kes / 案件编号")
206
+ appeal_text = gr.Textbox(label="Appeal Text / Teks Rayuan / 上诉内容", lines=3)
207
+ appeal_target = gr.Radio(choices=["PDRM", "Magistrate"], label="Submit To / Hantar Kepada / 提交至")
208
+ appeal_btn = gr.Button("Submit Appeal / Hantar Rayuan / 提交上诉")
209
+ appeal_out = gr.Textbox(label="Appeal Status / Status Rayuan / 上诉状态", lines=8)
210
  appeal_btn.click(fn=submit_appeal, inputs=[appeal_case_id, appeal_text, appeal_target], outputs=appeal_out)
211
+
212
+ with gr.Tab("💳 Pay Fine"):
213
+ pay_case_id = gr.Number(label="Case ID / Nombor Kes / 案件编号")
214
+ pay_btn = gr.Button("Pay Fine / Bayar Denda / 支付罚款")
215
+ pay_out = gr.Textbox(label="Payment Result / Keputusan Bayaran / 付款结果", lines=6)
216
  pay_btn.click(fn=pay_fine, inputs=pay_case_id, outputs=pay_out)
217
 
218
  if __name__ == "__main__":
 
228
 
229
 
230
 
231
+