cjian2025 commited on
Commit
c6d0584
·
verified ·
1 Parent(s): d41faf6

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +643 -0
app.py ADDED
@@ -0,0 +1,643 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import csv
3
+ import base64
4
+ from datetime import datetime
5
+ from pathlib import Path
6
+ import gradio as gr
7
+ import google.generativeai as genai
8
+ from PIL import Image
9
+ import resend
10
+ import tempfile
11
+
12
+ class GeminiImageAnalyzer:
13
+ def __init__(self, api_key):
14
+ """初始化Gemini客戶端"""
15
+ self.api_key = api_key
16
+ # 正確的配置方式
17
+ genai.configure(api_key=api_key)
18
+ # 創建模型實例
19
+ self.model = genai.GenerativeModel('gemini-2.0-flash-exp')
20
+
21
+ def validate_image(self, image_path):
22
+ """驗證圖片格式和存在性"""
23
+ if not os.path.exists(image_path):
24
+ raise FileNotFoundError(f"圖片檔案不存在: {image_path}")
25
+
26
+ file_extension = Path(image_path).suffix.lower()
27
+ if file_extension not in ['.jpg', '.jpeg', '.png', '.gif', '.webp']:
28
+ raise ValueError("支援 .jpg, .jpeg, .png, .gif, .webp 格式的圖片")
29
+
30
+ return True
31
+
32
+ def analyze_single_image(self, image_path, prompt="請詳細描述這張圖片的內容,並提取圖片中的文字,使用繁體中文"):
33
+ """分析單張圖片"""
34
+ try:
35
+ # 驗證圖片
36
+ self.validate_image(image_path)
37
+
38
+ # 直接使用PIL打開圖片
39
+ image = Image.open(image_path)
40
+
41
+ # 調用Gemini API的正確方式
42
+ response = self.model.generate_content([prompt, image])
43
+
44
+ return response.text
45
+
46
+ except Exception as e:
47
+ return f"分析失敗: {str(e)}"
48
+
49
+ def analyze_multiple_images(self, image_paths, comparison_prompt=None):
50
+ """分析多張圖片並進行比較"""
51
+ try:
52
+ if not image_paths or len(image_paths) == 0:
53
+ return "❌ 請至少上傳一張圖片"
54
+
55
+ # 如果只有一張圖片,使用單圖片分析
56
+ if len(image_paths) == 1:
57
+ return self.analyze_single_image(
58
+ image_paths[0],
59
+ comparison_prompt or "請詳細描述這張圖片的內容,並提取圖片中的文字,使用繁體中文"
60
+ )
61
+
62
+ # 多圖片分析
63
+ images = []
64
+ image_info = []
65
+
66
+ for i, image_path in enumerate(image_paths):
67
+ # 驗證圖片
68
+ self.validate_image(image_path)
69
+ # 打開圖片
70
+ image = Image.open(image_path)
71
+ images.append(image)
72
+ image_info.append(f"圖片 {i+1}: {os.path.basename(image_path)}")
73
+
74
+ # 構建比較提示詞
75
+ if not comparison_prompt:
76
+ comparison_prompt = f"""
77
+ 請詳細分析和比較這 {len(images)} 張圖片。請從以下方面進行分析:
78
+
79
+ 1. **個別圖片描述**:
80
+ - 分別描述每張圖片的主要內容
81
+ - 識別每張圖片中的文字、物品、人物等
82
+
83
+ 2. **相似之處**:
84
+ - 找出圖片之間的共同點
85
+ - 相同的元素、主題、風格等
86
+
87
+ 3. **差異比較**:
88
+ - 指出圖片之間的明顯差異
89
+ - 不同的顏色、構圖、內容、角度等
90
+
91
+ 4. **整體總結**:
92
+ - 這些圖片可能的關聯性
93
+ - 整體給人的印象或傳達的訊息
94
+
95
+ 請使用繁體中文回答,條理清晰地組織你的分析。
96
+ """
97
+
98
+ # 準備內容列表
99
+ content_parts = [comparison_prompt]
100
+ content_parts.extend(images)
101
+
102
+ # 調用API進行比較分析
103
+ response = self.model.generate_content(content_parts)
104
+
105
+ return response.text
106
+
107
+ except Exception as e:
108
+ return f"多圖片分析失敗: {str(e)}"
109
+
110
+ def batch_analyze_images(self, image_paths, individual_prompt=None):
111
+ """批量分析圖片(每張圖片單獨分析)"""
112
+ try:
113
+ if not image_paths or len(image_paths) == 0:
114
+ return "❌ 請至少上傳一張圖片"
115
+
116
+ results = {}
117
+ individual_prompt = individual_prompt or "請詳細描述這張圖片的內容,並提取圖片中的文字,使用繁體中文"
118
+
119
+ for i, image_path in enumerate(image_paths):
120
+ image_name = os.path.basename(image_path)
121
+ print(f"正在分析圖片 {i+1}/{len(image_paths)}: {image_name}")
122
+
123
+ result = self.analyze_single_image(image_path, individual_prompt)
124
+ results[f"圖片 {i+1} ({image_name})"] = result
125
+
126
+ # 格式化輸出
127
+ formatted_result = "📊 **批量圖片分析結果**\n\n"
128
+ for image_key, analysis in results.items():
129
+ formatted_result += f"## {image_key}\n\n{analysis}\n\n---\n\n"
130
+
131
+ return formatted_result
132
+
133
+ except Exception as e:
134
+ return f"批量分析失敗: {str(e)}"
135
+
136
+ class EmailSender:
137
+ def __init__(self, api_key):
138
+ """初始化Resend郵件客戶端"""
139
+ resend.api_key = api_key
140
+
141
+ def send_analysis_email(self, to_email, analysis_result, image_count=1, analysis_type="單圖片分析"):
142
+ """發送分析結果郵件"""
143
+ try:
144
+ # 構建HTML郵件內容
145
+ html_content = f"""
146
+ <html>
147
+ <head>
148
+ <style>
149
+ body {{
150
+ font-family: 'Microsoft JhengHei', Arial, sans-serif;
151
+ line-height: 1.6;
152
+ color: #333;
153
+ max-width: 900px;
154
+ margin: 0 auto;
155
+ padding: 20px;
156
+ }}
157
+ .header {{
158
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
159
+ color: white;
160
+ padding: 20px;
161
+ text-align: center;
162
+ border-radius: 10px;
163
+ margin-bottom: 20px;
164
+ }}
165
+ .content {{
166
+ background-color: #f9f9f9;
167
+ padding: 25px;
168
+ border-radius: 10px;
169
+ border-left: 5px solid #667eea;
170
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
171
+ }}
172
+ .analysis-type {{
173
+ background-color: #e3f2fd;
174
+ padding: 10px;
175
+ border-radius: 5px;
176
+ margin-bottom: 15px;
177
+ font-weight: bold;
178
+ color: #1976d2;
179
+ }}
180
+ .timestamp {{
181
+ color: #666;
182
+ font-size: 0.9em;
183
+ margin-top: 20px;
184
+ text-align: right;
185
+ border-top: 1px solid #ddd;
186
+ padding-top: 10px;
187
+ }}
188
+ pre {{
189
+ white-space: pre-wrap;
190
+ background: white;
191
+ padding: 20px;
192
+ border-radius: 8px;
193
+ border: 1px solid #e0e0e0;
194
+ font-family: 'Microsoft JhengHei', Arial, sans-serif;
195
+ font-size: 14px;
196
+ line-height: 1.5;
197
+ }}
198
+ </style>
199
+ </head>
200
+ <body>
201
+ <div class="header">
202
+ <h1>🤖 Gemini AI 圖片分析結果</h1>
203
+ <p>智能圖片分析與比較系統</p>
204
+ </div>
205
+
206
+ <div class="content">
207
+ <div class="analysis-type">
208
+ 📋 分析類型:{analysis_type} | 📸 圖片數量:{image_count} 張
209
+ </div>
210
+
211
+ <h2>🔍 分析結果</h2>
212
+ <pre>{analysis_result}</pre>
213
+ </div>
214
+
215
+ <div class="timestamp">
216
+ 🕐 產生時間:{datetime.now().strftime("%Y年%m月%d日 %H:%M:%S")}
217
+ <br>
218
+ 🚀 Powered by Google Gemini 2.0 & Resend
219
+ </div>
220
+ </body>
221
+ </html>
222
+ """
223
+
224
+ params = {
225
+ "from": "Gemini AI <onboarding@resend.dev>",
226
+ "to": [to_email],
227
+ "subject": f"🤖 AI圖片分析結果 - {analysis_type} ({image_count}張圖片)",
228
+ "html": html_content
229
+ }
230
+
231
+ email = resend.Emails.send(params)
232
+ return f"郵件發送成功!郵件ID: {email.get('id', 'N/A')}"
233
+
234
+ except Exception as e:
235
+ return f"郵件發送失敗: {str(e)}"
236
+
237
+ def analyze_images_and_send_email(images, analysis_mode, custom_prompt, recipient_email, gemini_key, resend_key):
238
+ """分析圖片並發送郵件"""
239
+ if not images or len(images) == 0:
240
+ return "❌ 請至少上傳一張圖片", "", ""
241
+
242
+ if not recipient_email:
243
+ return "❌ 請輸入收件人信箱", "", ""
244
+
245
+ if not gemini_key:
246
+ return "❌ 請輸入Gemini API Key", "", ""
247
+
248
+ if not resend_key:
249
+ return "❌ 請輸入Resend API Key", "", ""
250
+
251
+ try:
252
+ # 初始化服務
253
+ analyzer = GeminiImageAnalyzer(gemini_key)
254
+ email_sender = EmailSender(resend_key)
255
+
256
+ # 獲取圖片路徑列表
257
+ image_paths = images if isinstance(images, list) else [images]
258
+ image_count = len(image_paths)
259
+
260
+ # 根據分析模式選擇分析方法
261
+ if analysis_mode == "比較分析":
262
+ analysis_result = analyzer.analyze_multiple_images(image_paths, custom_prompt)
263
+ analysis_type = "多圖片比較分析"
264
+ elif analysis_mode == "批量分析":
265
+ analysis_result = analyzer.batch_analyze_images(image_paths, custom_prompt)
266
+ analysis_type = "批量個別分析"
267
+ else: # 單張分析
268
+ if len(image_paths) > 1:
269
+ # 如果上傳多張但選擇單張分析,只分析第一張
270
+ analysis_result = analyzer.analyze_single_image(image_paths[0], custom_prompt)
271
+ analysis_type = "單圖片分析(僅分析第一張)"
272
+ image_count = 1
273
+ else:
274
+ analysis_result = analyzer.analyze_single_image(image_paths[0], custom_prompt)
275
+ analysis_type = "單圖片分析"
276
+
277
+ if analysis_result.startswith(("分析失敗", "多圖片分析失敗", "批量分析失敗", "❌")):
278
+ return f"❌ {analysis_result}", analysis_result, ""
279
+
280
+ # 發送郵件
281
+ email_result = email_sender.send_analysis_email(
282
+ recipient_email,
283
+ analysis_result,
284
+ image_count,
285
+ analysis_type
286
+ )
287
+
288
+ status = f"✅ 處理完成!\n📊 分析模式:{analysis_type}\n📸 處理圖片:{image_count} 張\n📧 {email_result}"
289
+
290
+ return status, analysis_result, email_result
291
+
292
+ except Exception as e:
293
+ error_msg = f"❌ 處理失敗: {str(e)}"
294
+ return error_msg, "", ""
295
+
296
+ def save_results_to_csv(images, analysis_mode, custom_prompt, analysis_result):
297
+ """儲存結果到CSV"""
298
+ try:
299
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
300
+ temp_dir = tempfile.gettempdir()
301
+ csv_filename = os.path.join(temp_dir, f"multi_image_analysis_{timestamp}.csv")
302
+
303
+ with open(csv_filename, 'w', newline='', encoding='utf-8-sig') as csvfile:
304
+ fieldnames = ['時間戳記', '分析模式', '圖片數量', '圖片列表', '自訂提示', '分析結果']
305
+ writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
306
+
307
+ writer.writeheader()
308
+
309
+ # 處理圖片列表
310
+ if images:
311
+ image_list = [os.path.basename(img) if isinstance(img, str) else f"圖片_{i+1}"
312
+ for i, img in enumerate(images)]
313
+ image_names = "; ".join(image_list)
314
+ image_count = len(images)
315
+ else:
316
+ image_names = "無"
317
+ image_count = 0
318
+
319
+ writer.writerow({
320
+ '時間戳記': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
321
+ '分析模式': analysis_mode,
322
+ '圖片數量': image_count,
323
+ '圖片列表': image_names,
324
+ '自訂提示': custom_prompt or "預設提示",
325
+ '分析結果': analysis_result
326
+ })
327
+
328
+ return csv_filename
329
+ except Exception as e:
330
+ return f"儲存失敗: {str(e)}"
331
+
332
+ # 建立Gradio介面
333
+ def create_interface():
334
+ with gr.Blocks(
335
+ title="🤖 Gemini 多圖片分析比較助手",
336
+ theme=gr.themes.Soft(),
337
+ css="""
338
+ .gradio-container {
339
+ max-width: 1400px !important;
340
+ margin: auto !important;
341
+ }
342
+ .main-header {
343
+ text-align: center;
344
+ margin-bottom: 2rem;
345
+ padding: 1.5rem;
346
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
347
+ color: white;
348
+ border-radius: 15px;
349
+ box-shadow: 0 4px 15px rgba(0,0,0,0.2);
350
+ }
351
+ .api-warning {
352
+ background: linear-gradient(135deg, #fff3cd 0%, #ffeaa7 100%);
353
+ border: 1px solid #ffeaa7;
354
+ border-radius: 10px;
355
+ padding: 15px;
356
+ margin: 15px 0;
357
+ color: #856404;
358
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
359
+ }
360
+ .feature-highlight {
361
+ background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
362
+ border: 2px solid #2196f3;
363
+ border-radius: 10px;
364
+ padding: 15px;
365
+ margin: 15px 0;
366
+ color: #1976d2;
367
+ }
368
+ """
369
+ ) as demo:
370
+
371
+ gr.HTML("""
372
+ <div class="main-header">
373
+ <h1>🤖 Gemini 多圖片分析比較助手</h1>
374
+ <p>支援單張分析、多圖比較、批量處理 - 一站式AI圖片分析解決方案</p>
375
+ <p><small>🚀 部署於 Hugging Face Spaces | 🔥 支援最新 Gemini 2.0</small></p>
376
+ </div>
377
+ """)
378
+
379
+ # 新功能亮點
380
+ gr.HTML("""
381
+ <div class="feature-highlight">
382
+ <h3>🎯 新增功能亮點:</h3>
383
+ <ul>
384
+ <li>📸 <strong>多圖片上傳</strong>:一次上傳多張圖片進行分析</li>
385
+ <li>🔍 <strong>智能比較</strong>:AI自動比較多張圖片的差異和相似點</li>
386
+ <li>📊 <strong>批量處理</strong>:同時分析多張圖片並生成個別報告</li>
387
+ <li>🎨 <strong>靈活模式</strong>:支援單張分析、比較分析、批量分析三種模式</li>
388
+ </ul>
389
+ </div>
390
+ """)
391
+
392
+ # API 安全提醒
393
+ gr.HTML("""
394
+ <div class="api-warning">
395
+ <strong>⚠️ 重要提醒:</strong><br>
396
+ • 請勿在公共��境中分享您的 API 密鑰<br>
397
+ • 建議在本地環境或私人部署中使用敏感功能<br>
398
+ • 此應用程式不會儲存您的 API 密鑰<br>
399
+ • 多圖片分析會消耗更多 API 配額,請注意使用量
400
+ </div>
401
+ """)
402
+
403
+ with gr.Row():
404
+ with gr.Column(scale=1):
405
+ gr.Markdown("### 📁 圖片上傳")
406
+ images_input = gr.File(
407
+ label="選擇圖片 (支援多張上傳)",
408
+ file_count="multiple",
409
+ file_types=["image"],
410
+ height=200
411
+ )
412
+
413
+ # 顯示上傳的圖片預覽
414
+ images_gallery = gr.Gallery(
415
+ label="圖片預覽",
416
+ show_label=True,
417
+ elem_id="gallery",
418
+ columns=3,
419
+ rows=2,
420
+ height=300,
421
+ object_fit="contain"
422
+ )
423
+
424
+ gr.Markdown("### 🎯 分析模式")
425
+ analysis_mode = gr.Radio(
426
+ choices=["單張分析", "比較分析", "批量分析"],
427
+ value="比較分析",
428
+ label="選擇分析模式",
429
+ info="""
430
+ • 單張分析:分析單張圖片(如上傳多張僅分析第一張)
431
+ • 比較分析:比較多張圖片的差異和相似點(推薦)
432
+ • 批量分析:對每張圖片進行單獨分析
433
+ """
434
+ )
435
+
436
+ gr.Markdown("### ✏️ 分析設定")
437
+ prompt_input = gr.Textbox(
438
+ label="自訂提示詞 (可選)",
439
+ placeholder="留空將使用智能預設提示詞...",
440
+ lines=3,
441
+ info="不同分析模式會自動使用相應的最佳化提示詞"
442
+ )
443
+
444
+ recipient_email = gr.Textbox(
445
+ label="📧 收件人信箱",
446
+ placeholder="your-email@example.com"
447
+ )
448
+
449
+ with gr.Column(scale=1):
450
+ gr.Markdown("### 🔑 API 設定")
451
+
452
+ with gr.Accordion("如何獲取 API Keys", open=False):
453
+ gr.Markdown("""
454
+ **Gemini API Key:**
455
+ 1. 前往 [Google AI Studio](https://aistudio.google.com/app/apikey)
456
+ 2. 創建新的 API Key
457
+ 3. 複製 API Key(格式:AIza...)
458
+
459
+ **Resend API Key:**
460
+ 1. 前往 [Resend](https://resend.com/api-keys)
461
+ 2. 註冊帳號並創建 API Key
462
+ 3. 複製 API Key(格式:re_...)
463
+
464
+ **注意事項:**
465
+ - 多圖片分析會消耗更多 API 配額
466
+ - 建議先用少量圖片測試
467
+ - 大型圖片會增加處理時間
468
+ """)
469
+
470
+ gemini_key = gr.Textbox(
471
+ label="Gemini API Key",
472
+ placeholder="AIza...",
473
+ type="password"
474
+ )
475
+
476
+ resend_key = gr.Textbox(
477
+ label="Resend API Key",
478
+ placeholder="re_...",
479
+ type="password"
480
+ )
481
+
482
+ gr.Markdown("### 🚀 執行操作")
483
+ analyze_btn = gr.Button(
484
+ "🔍 開始AI分析並發送郵件",
485
+ variant="primary",
486
+ size="lg"
487
+ )
488
+
489
+ gr.Markdown("### 📊 處理結果")
490
+
491
+ with gr.Row():
492
+ status_output = gr.Textbox(
493
+ label="📈 處理狀態",
494
+ lines=4,
495
+ interactive=False
496
+ )
497
+
498
+ with gr.Row():
499
+ with gr.Column():
500
+ analysis_output = gr.Textbox(
501
+ label="🤖 AI分析結果",
502
+ lines=15,
503
+ interactive=False
504
+ )
505
+
506
+ with gr.Column():
507
+ email_output = gr.Textbox(
508
+ label="📧 郵件發送結果",
509
+ lines=15,
510
+ interactive=False
511
+ )
512
+
513
+ with gr.Row():
514
+ download_btn = gr.Button("💾 下載詳細CSV結果", variant="secondary")
515
+ csv_file = gr.File(label="CSV檔案", visible=False)
516
+
517
+ # 事件綁定
518
+ def update_gallery(files):
519
+ if files:
520
+ return [file.name for file in files]
521
+ return []
522
+
523
+ images_input.change(
524
+ fn=update_gallery,
525
+ inputs=[images_input],
526
+ outputs=[images_gallery]
527
+ )
528
+
529
+ analyze_btn.click(
530
+ fn=analyze_images_and_send_email,
531
+ inputs=[images_input, analysis_mode, prompt_input, recipient_email, gemini_key, resend_key],
532
+ outputs=[status_output, analysis_output, email_output]
533
+ )
534
+
535
+ def download_csv(images, analysis_mode, custom_prompt, analysis_result):
536
+ if analysis_result and not analysis_result.startswith("❌"):
537
+ filename = save_results_to_csv(images, analysis_mode, custom_prompt, analysis_result)
538
+ if not filename.startswith("儲存失敗"):
539
+ return gr.update(value=filename, visible=True)
540
+ return gr.update(visible=False)
541
+
542
+ download_btn.click(
543
+ fn=download_csv,
544
+ inputs=[images_input, analysis_mode, prompt_input, analysis_output],
545
+ outputs=csv_file
546
+ )
547
+
548
+ # 使用說明
549
+ with gr.Accordion("📝 詳細使用說明", open=False):
550
+ gr.Markdown("""
551
+ ### 🎯 分析模式說明
552
+
553
+ **1. 單張分析**
554
+ - 適用:單張圖片的詳細分析
555
+ - 特點:深入分析圖片內容、文字識別
556
+ - 建議:需要詳細了解單張圖片內容時使用
557
+
558
+ **2. 比較分析(推薦)**
559
+ - 適用:2-10張圖片的對比分析
560
+ - 特點:找出圖片間的差異、相似點、關聯性
561
+ - 建議:需要對比多張圖片時使用,最適合2-5張圖片
562
+
563
+ **3. 批量分析**
564
+ - 適用:多張圖片需要分別分析
565
+ - 特點:每張圖片獨立分析,生成個別報告
566
+ - 建議:需要處理大量圖片且每張都需單獨報告
567
+
568
+ ### 📝 使用步驟
569
+ 1. **上傳圖片**:支援 JPG、PNG、GIF、WebP 格式
570
+ 2. **選擇模式**:根據需求選擇分析模式
571
+ 3. **設定提示**:可自訂提示詞或使用預設
572
+ 4. **輸入信箱**:設定接收結果的郵箱
573
+ 5. **配置API**:輸入必要的API密鑰
574
+ 6. **開始分析**:點擊按鈕開始處理
575
+ 7. **查看結果**:在介面查看結果或等待郵件
576
+
577
+ ### ⚡ 效能建議
578
+ - **圖片數量**:建議一次處理2-10張圖片
579
+ - **圖片大小**:單張圖片建議不超過10MB
580
+ - **處理時間**:多圖片分析需要更長時間,請耐心等待
581
+ - **API配額**:注意API使用量,避免超出限制
582
+
583
+ ### 🛠️ 故障排除
584
+ - 如果分析失敗,檢查API密鑰是否正確
585
+ - 確保圖片格式支援且未損壞
586
+ - 網路不穩定時可能需要重試
587
+ - 大量圖片處理時間較長,請耐心等待
588
+ """)
589
+
590
+ # 提示詞範例
591
+ with gr.Accordion("🎯 提示詞範例", open=False):
592
+ gr.Markdown("### 📸 單張分析提示詞")
593
+ gr.Examples(
594
+ examples=[
595
+ ["請詳細描述這張圖片,包括主要物件、顏色、構圖和可能的背景故事"],
596
+ ["提取並分析圖片中的所有文字內容,並解釋其含義"],
597
+ ["分析圖片的藝術風格、攝影技法和視覺效果"],
598
+ ["識別圖片中的品牌、標誌和商業元素"],
599
+ ["描述圖片中人物的情緒、動作和互動關係"]
600
+ ],
601
+ inputs=prompt_input,
602
+ label="點擊使用單張分析範例"
603
+ )
604
+
605
+ gr.Markdown("### 🔄 比較分析提示詞")
606
+ gr.Examples(
607
+ examples=[
608
+ ["比較這些圖片的相似點和差異,分析它們的關聯性"],
609
+ ["分析這些圖片在構圖、色彩和風格上的異同"],
610
+ ["比較圖片中產品或物件的特徵差異"],
611
+ ["分析這些圖片的時間順序和變化過程"],
612
+ ["比較不同角度或場景下同一主題的表現差異"]
613
+ ],
614
+ inputs=prompt_input,
615
+ label="點擊使用比較分析範例"
616
+ )
617
+
618
+ # 版本資訊
619
+ gr.HTML("""
620
+ <div style="text-align: center; margin-top: 2rem; padding: 1.5rem; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
621
+ <p><small>
622
+ 🚀 Powered by <strong>Google Gemini 2.0</strong> & <strong>Resend</strong><br>
623
+ 📍 Deployed on <strong>Hugging Face Spaces</strong><br>
624
+ 🔥 <strong>多圖片比較分析版本 2.0</strong> | Made with ❤️ using Gradio<br>
625
+ ⭐ 支援最多10張圖片同時分析比較
626
+ </small></p>
627
+ </div>
628
+ """)
629
+
630
+ return demo
631
+
632
+ # 主程式入口
633
+ if __name__ == "__main__":
634
+ # 建立並啟動介面
635
+ demo = create_interface()
636
+
637
+ # Hugging Face Spaces 部署設定
638
+ demo.launch(
639
+ share=False,
640
+ show_error=True,
641
+ show_api=False,
642
+ quiet=False
643
+ )