Lashtw commited on
Commit
f27649c
·
verified ·
1 Parent(s): 90d06cf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +156 -69
app.py CHANGED
@@ -1,8 +1,38 @@
1
  import gradio as gr
2
- import time # 新增 time 模組處理快取
 
 
 
 
3
 
4
- # 使用正確的圖片路徑格式
5
- data = [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  {"蛛絲馬跡": 1, "嫌疑犯": "5冰淇淋師傅", "直接證據": "SAS", "間接證據": "RHS SSS", "嫌疑犯圖片": "https://huggingface.co/spaces/Lashtw/Judge_system/resolve/main/5%E5%86%B0%E6%B7%87%E6%B7%8B%E5%B8%AB%E5%82%85.png"},
7
  {"蛛絲馬跡": 2, "嫌疑犯": "7候選人", "直接證據": "SSS", "間接證據": "SAS ASA AAS", "嫌疑犯圖片": "https://huggingface.co/spaces/Lashtw/Judge_system/resolve/main/7%E5%80%99%E9%81%B8%E4%BA%BA.png"},
8
  {"蛛絲馬跡": 3, "嫌疑犯": "8列車長", "直接證據": "SAS", "間接證據": "無", "嫌疑犯圖片": "https://huggingface.co/spaces/Lashtw/Judge_system/resolve/main/8%E5%88%97%E8%BB%8A%E9%95%B7.png"},
@@ -33,98 +63,155 @@ data = [
33
  {"蛛絲馬跡": 28, "嫌疑犯": "26保全", "直接證據": "ASA", "間接證據": "AAS", "嫌疑犯圖片": "https://huggingface.co/spaces/Lashtw/Judge_system/resolve/main/26%E4%BF%9D%E5%85%A8.png"}
34
  ]
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  indirect_evidence_store = ""
37
 
38
  def query_data(clue_number):
39
  global indirect_evidence_store
40
  try:
41
  clue_number = int(clue_number)
42
- row = next((item for item in data if item['蛛絲馬跡'] == clue_number), None)
43
- if row:
44
- suspect = row['嫌疑犯']
45
- direct_evidence = row['直接證據']
46
- indirect_evidence_store = row['間接證據'] if row['間接證據'] != "無" else "無間接證據"
47
-
48
- # 加入時間戳記處理快取問題
49
- image_url = f"{row['嫌疑犯圖片']}?{int(time.time())}" if row['嫌疑犯圖片'] else None
50
 
51
- return (
52
- f"嫌疑犯: {suspect}\n直接證據: {direct_evidence}",
 
 
 
 
53
  gr.update(visible=True),
54
- gr.update(value="", visible=False),
55
- image_url
56
- )
57
- else:
58
- return (
59
- "未找到相關資料,請檢查蛛絲馬跡號碼是否正確。",
60
  gr.update(visible=False),
61
- gr.update(value="", visible=False),
62
- None
63
- )
64
- except ValueError:
65
- return (
66
- "請輸入有效的數字。",
67
  gr.update(visible=False),
68
- gr.update(value="", visible=False),
69
  None
70
- )
 
 
 
 
 
 
 
71
 
72
- def show_indirect_evidence():
73
  global indirect_evidence_store
74
- return gr.update(value=indirect_evidence_store, visible=True)
75
 
76
- def reset_fields():
77
  global indirect_evidence_store
78
  indirect_evidence_store = ""
79
- return (
80
- "",
 
81
  gr.update(visible=False),
82
- gr.update(value="", visible=False),
83
- gr.update(value="", visible=True),
84
  None
85
- )
86
 
87
- with gr.Blocks() as demo:
88
- gr.Markdown("<h1>嫌疑犯ABC的現身</h1>")
89
- gr.Markdown("<h3>法官系統</h3>")
 
 
 
 
 
 
 
 
 
 
 
90
 
91
- with gr.Row():
92
- input_box = gr.Textbox(label="請輸入蛛絲馬跡號碼", placeholder="例如: 11", lines=1)
93
- query_button = gr.Button("查詢", variant="primary")
 
 
 
94
 
 
 
 
 
 
 
 
 
 
 
95
  with gr.Row():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  with gr.Column(scale=1):
97
- output_box = gr.Textbox(label="查詢結果", interactive=False)
98
- with gr.Column(scale=1):
99
- image_output = gr.Image(label="嫌疑犯圖片", elem_id="suspect-image", show_label=True)
100
-
101
- indirect_button = gr.Button("顯示間接證據", visible=False)
102
- indirect_output = gr.Textbox(label="間接證據內容", interactive=False, visible=False)
103
- reset_button = gr.Button("重新查詢", variant="secondary")
 
 
 
104
 
105
- query_button.click(
 
106
  query_data,
107
- inputs=input_box,
108
- outputs=[output_box, indirect_button, indirect_output, image_output]
109
  )
110
- indirect_button.click(
111
- show_indirect_evidence,
112
- inputs=None,
113
- outputs=indirect_output
114
  )
115
- reset_button.click(
116
- reset_fields,
117
- inputs=None,
118
- outputs=[input_box, indirect_button, indirect_output, output_box, image_output]
119
  )
120
 
121
- demo.css = """
122
- #suspect-image {
123
- max-width: 250px !important;
124
- max-height: 250px !important;
125
- border: 2px solid #e0e0e0;
126
- border-radius: 8px;
127
- }
128
- """
129
-
130
- demo.launch()
 
1
  import gradio as gr
2
+ import base64
3
+ import requests
4
+ import time
5
+ from io import BytesIO
6
+ from PIL import Image
7
 
8
+ # 圖片處理函數 (包含壓縮和Base64編碼)
9
+ def process_image(url):
10
+ try:
11
+ response = requests.get(url, timeout=10)
12
+ response.raise_for_status()
13
+
14
+ img = Image.open(BytesIO(response.content))
15
+
16
+ # 保持透明度處理
17
+ if img.mode in ('RGBA', 'LA'):
18
+ img = img.convert('RGBA')
19
+ else:
20
+ img = img.convert('RGB')
21
+
22
+ # 調整大小(保持比例縮放到最大300px)
23
+ img.thumbnail((300, 300))
24
+
25
+ # 轉換為Base64
26
+ buffered = BytesIO()
27
+ img.save(buffered, format="PNG", optimize=True, quality=85)
28
+ return f"data:image/png;base64,{base64.b64encode(buffered.getvalue()).decode()}"
29
+
30
+ except Exception as e:
31
+ print(f"圖片處理失敗: {str(e)}")
32
+ return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="
33
+
34
+ # 完整28個嫌疑犯數據(原始URL格式)
35
+ raw_data = [
36
  {"蛛絲馬跡": 1, "嫌疑犯": "5冰淇淋師傅", "直接證據": "SAS", "間接證據": "RHS SSS", "嫌疑犯圖片": "https://huggingface.co/spaces/Lashtw/Judge_system/resolve/main/5%E5%86%B0%E6%B7%87%E6%B7%8B%E5%B8%AB%E5%82%85.png"},
37
  {"蛛絲馬跡": 2, "嫌疑犯": "7候選人", "直接證據": "SSS", "間接證據": "SAS ASA AAS", "嫌疑犯圖片": "https://huggingface.co/spaces/Lashtw/Judge_system/resolve/main/7%E5%80%99%E9%81%B8%E4%BA%BA.png"},
38
  {"蛛絲馬跡": 3, "嫌疑犯": "8列車長", "直接證據": "SAS", "間接證據": "無", "嫌疑犯圖片": "https://huggingface.co/spaces/Lashtw/Judge_system/resolve/main/8%E5%88%97%E8%BB%8A%E9%95%B7.png"},
 
63
  {"蛛絲馬跡": 28, "嫌疑犯": "26保全", "直接證據": "ASA", "間接證據": "AAS", "嫌疑犯圖片": "https://huggingface.co/spaces/Lashtw/Judge_system/resolve/main/26%E4%BF%9D%E5%85%A8.png"}
64
  ]
65
 
66
+ # 預處理所有圖片(部署時自動執行)
67
+ print("⏳ 正在預處理28張嫌疑人圖片...")
68
+ start_loading = time.time()
69
+
70
+ for item in raw_data:
71
+ try:
72
+ process_start = time.time()
73
+ item["嫌疑犯圖片"] = process_image(item["嫌疑犯圖片"])
74
+ print(f"✅ 蛛絲馬跡 {item['蛛絲馬跡']:02d} 圖片處理完成 | 耗時 {time.time()-process_start:.2f}s")
75
+ except Exception as e:
76
+ print(f"❌ 蛛絲馬跡 {item['蛛絲馬跡']:02d} 圖片處理失敗: {str(e)}")
77
+ item["嫌疑犯圖片"] = None
78
+
79
+ print(f"🎉 所有圖片預處理完成 | 總耗時 {time.time()-start_loading:.2f}秒")
80
+
81
+ # 共用狀態儲存
82
  indirect_evidence_store = ""
83
 
84
  def query_data(clue_number):
85
  global indirect_evidence_store
86
  try:
87
  clue_number = int(clue_number)
88
+ if not 1 <= clue_number <= 28:
89
+ return [
90
+ gr.update(value="⚠️ 請輸入1-28之間的整數"),
91
+ gr.update(visible=False),
92
+ gr.update(visible=False),
93
+ None
94
+ ]
 
95
 
96
+ target = next((i for i in raw_data if i['蛛絲馬跡'] == clue_number), None)
97
+
98
+ if target:
99
+ indirect_evidence_store = target['間接證據'] if target['間接證據'] != "無" else "無間接證據"
100
+ return [
101
+ f"🔍 嫌疑犯:{target['嫌疑犯']}\n🔖 直接證據:{target['直接證據']}",
102
  gr.update(visible=True),
 
 
 
 
 
 
103
  gr.update(visible=False),
104
+ target['嫌疑犯圖片'] or None
105
+ ]
106
+ return [
107
+ "🕵️♂️ 查無此編號的嫌疑人記錄",
108
+ gr.update(visible=False),
 
109
  gr.update(visible=False),
 
110
  None
111
+ ]
112
+ except:
113
+ return [
114
+ "❌ 輸入格式錯誤,請輸入數字",
115
+ gr.update(visible=False),
116
+ gr.update(visible=False),
117
+ None
118
+ ]
119
 
120
+ def show_indirect():
121
  global indirect_evidence_store
122
+ return gr.update(value=f"📚 間接證據分析:{indirect_evidence_store}", visible=True)
123
 
124
+ def reset_all():
125
  global indirect_evidence_store
126
  indirect_evidence_store = ""
127
+ return [
128
+ gr.update(value=""),
129
+ gr.update(visible=False),
130
  gr.update(visible=False),
 
 
131
  None
132
+ ]
133
 
134
+ # 界面設計
135
+ with gr.Blocks(
136
+ theme=gr.themes.Soft(
137
+ primary_hue="blue",
138
+ secondary_hue="gray",
139
+ font=[gr.themes.GoogleFont("Noto Sans TC")]
140
+ ),
141
+ css="""
142
+ .suspect-img {border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.1);}
143
+ .dark .suspect-img {border: 2px solid #333 !important;}
144
+ .result-box {background: #f8f9fa!important; border-radius: 8px!important;}
145
+ .dark .result-box {background: #2d2d2d!important;}
146
+ """
147
+ ) as demo:
148
 
149
+ gr.Markdown("""
150
+ <div style="text-align: center; margin-bottom: 30px;">
151
+ <h1 style="font-weight: 700; color: #2563eb;">🕵️♂️ 刑事偵查系統</h1>
152
+ <h3 style="color: #4b5563;">重大刑案專案追緝平台</h3>
153
+ </div>
154
+ """)
155
 
156
+ with gr.Row(variant="panel"):
157
+ input_clue = gr.Number(
158
+ label="🕹️ 輸入蛛絲馬跡編號",
159
+ minimum=1,
160
+ maximum=28,
161
+ precision=0,
162
+ interactive=True,
163
+ container=False
164
+ )
165
+
166
  with gr.Row():
167
+ with gr.Column(scale=2):
168
+ with gr.Group(elem_classes="result-box"):
169
+ result_display = gr.Textbox(
170
+ label="🔎 偵查結果",
171
+ interactive=False,
172
+ lines=3,
173
+ max_lines=3
174
+ )
175
+ indirect_btn = gr.Button(
176
+ "📖 顯示間接證據",
177
+ visible=False,
178
+ size="sm"
179
+ )
180
+ indirect_display = gr.Textbox(
181
+ label="📝 間接證據報告",
182
+ visible=False,
183
+ interactive=False
184
+ )
185
+
186
  with gr.Column(scale=1):
187
+ img_display = gr.Image(
188
+ label="📸 嫌疑人檔案照",
189
+ height=320,
190
+ interactive=False,
191
+ elem_classes="suspect-img"
192
+ )
193
+
194
+ with gr.Row():
195
+ submit_btn = gr.Button("🚀 開始偵查", variant="primary")
196
+ reset_btn = gr.Button("🔄 重置查詢", variant="secondary")
197
 
198
+ # 事件綁定
199
+ submit_btn.click(
200
  query_data,
201
+ inputs=input_clue,
202
+ outputs=[result_display, indirect_btn, indirect_display, img_display]
203
  )
204
+
205
+ indirect_btn.click(
206
+ show_indirect,
207
+ outputs=indirect_display
208
  )
209
+
210
+ reset_btn.click(
211
+ reset_all,
212
+ outputs=[input_clue, indirect_btn, indirect_display, img_display]
213
  )
214
 
215
+ # 啟動應用
216
+ if __name__ == "__main__":
217
+ demo.launch(server_name="0.0.0.0", server_port=7860)