DawnC commited on
Commit
a5de5df
1 Parent(s): dc000b7

Upload breed_comparison.py

Browse files
Files changed (1) hide show
  1. breed_comparison.py +538 -0
breed_comparison.py ADDED
@@ -0,0 +1,538 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ import sqlite3
4
+ from dog_database import get_dog_description
5
+ from breed_health_info import breed_health_info
6
+ from breed_noise_info import breed_noise_info
7
+
8
+ def create_comparison_tab(dog_breeds, get_dog_description, breed_noise_info, breed_health_info):
9
+ with gr.TabItem("Breed Comparison"):
10
+ gr.HTML("<p style='text-align: center;'>Select two dog breeds to compare their characteristics and care requirements.</p>")
11
+
12
+ with gr.Row():
13
+ breed1_dropdown = gr.Dropdown(
14
+ choices=dog_breeds,
15
+ label="Select First Breed",
16
+ value="Golden_Retriever"
17
+ )
18
+ breed2_dropdown = gr.Dropdown(
19
+ choices=dog_breeds,
20
+ label="Select Second Breed",
21
+ value="Border_Collie"
22
+ )
23
+
24
+ compare_btn = gr.Button("Compare Breeds")
25
+ comparison_output = gr.HTML(label="Comparison Results")
26
+
27
+ def format_noise_data(notes):
28
+ characteristics = []
29
+ triggers = []
30
+ noise_level = "Moderate" # 預設值
31
+
32
+ if isinstance(notes, str):
33
+ lines = notes.strip().split('\n')
34
+ section = ""
35
+ for line in lines:
36
+ line = line.strip()
37
+ if "Typical noise characteristics:" in line:
38
+ section = "characteristics"
39
+ elif "Barking triggers:" in line:
40
+ section = "triggers"
41
+ elif "Noise level:" in line:
42
+ noise_level = line.split(':')[1].strip()
43
+ elif line.startswith('•'):
44
+ if section == "characteristics":
45
+ characteristics.append(line[1:].strip())
46
+ elif section == "triggers":
47
+ triggers.append(line[1:].strip())
48
+
49
+ return {
50
+ 'characteristics': characteristics,
51
+ 'triggers': triggers,
52
+ 'noise_level': noise_level
53
+ }
54
+
55
+ def format_health_data(notes):
56
+ considerations = []
57
+ screenings = []
58
+
59
+ if isinstance(notes, str):
60
+ lines = notes.strip().split('\n')
61
+ current_section = None
62
+
63
+ for line in lines:
64
+ line = line.strip()
65
+ # 修正字串比對
66
+ if "Common breed-specific health considerations" in line:
67
+ current_section = "considerations"
68
+ elif "Recommended health screenings:" in line:
69
+ current_section = "screenings"
70
+ elif line.startswith('•'):
71
+ item = line[1:].strip()
72
+ if current_section == "considerations":
73
+ considerations.append(item)
74
+ elif current_section == "screenings":
75
+ screenings.append(item)
76
+
77
+ # 只有當真的沒有資料時才返回 "Information not available"
78
+ if not considerations and not screenings:
79
+ return {
80
+ 'considerations': ["Information not available"],
81
+ 'screenings': ["Information not available"]
82
+ }
83
+
84
+ return {
85
+ 'considerations': considerations,
86
+ 'screenings': screenings
87
+ }
88
+
89
+ def get_comparison_styles():
90
+ return """
91
+ .comparison-container {
92
+ display: grid;
93
+ grid-template-columns: 1fr 1fr;
94
+ gap: 24px;
95
+ padding: 20px;
96
+ }
97
+
98
+ .breed-column {
99
+ background: white;
100
+ border-radius: 10px;
101
+ padding: 24px;
102
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
103
+ }
104
+
105
+ .section-title {
106
+ font-size: 24px;
107
+ color: #2D3748;
108
+ margin-bottom: 20px;
109
+ padding-bottom: 10px;
110
+ border-bottom: 2px solid #E2E8F0;
111
+ }
112
+
113
+ .info-section {
114
+ display: grid;
115
+ grid-template-columns: repeat(2, 1fr);
116
+ gap: 16px;
117
+ margin-bottom: 24px;
118
+ }
119
+
120
+ .info-item {
121
+ position: relative;
122
+ background: #F8FAFC;
123
+ padding: 16px;
124
+ border-radius: 8px;
125
+ border: 1px solid #E2E8F0;
126
+ }
127
+
128
+ .info-label {
129
+ display: flex;
130
+ align-items: center;
131
+ gap: 8px;
132
+ color: #4A5568;
133
+ font-size: 0.9em;
134
+ margin-bottom: 4px;
135
+ }
136
+
137
+ .info-icon {
138
+ cursor: help;
139
+ background: #E2E8F0;
140
+ width: 18px;
141
+ height: 18px;
142
+ border-radius: 50%;
143
+ display: inline-flex;
144
+ align-items: center;
145
+ justify-content: center;
146
+ font-size: 12px;
147
+ color: #4A5568;
148
+ margin-left: 4px;
149
+ }
150
+
151
+ .info-icon:hover + .tooltip-content {
152
+ display: block;
153
+ }
154
+
155
+ .tooltip-content {
156
+ display: none;
157
+ position: absolute;
158
+ background: #2D3748;
159
+ color: #FFFFFF;
160
+ padding: 8px 12px;
161
+ border-radius: 6px;
162
+ font-size: 14px;
163
+ line-height: 1.3;
164
+ width: max-content;
165
+ max-width: 280px;
166
+ z-index: 1000;
167
+ top: 0; /* 修改位置 */
168
+ left: 100%;
169
+ margin-left: 10px;
170
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
171
+ white-space: normal; /* 允許文字換行 */
172
+ }
173
+
174
+
175
+ .tooltip-content,
176
+ .tooltip-content *,
177
+ .tooltip-content strong,
178
+ .tooltip-content li,
179
+ .tooltip-content ul,
180
+ .tooltip-content p,
181
+ .tooltip-content span,
182
+ .tooltip-content div {
183
+ color: #FFFFFF !important;
184
+ }
185
+
186
+
187
+ .tooltip-content::before {
188
+ content: '';
189
+ position: absolute;
190
+ left: -6px;
191
+ top: 14px; /* 配合上方位置調整 */
192
+ border-width: 6px;
193
+ border-style: solid;
194
+ border-color: transparent #2D3748 transparent transparent;
195
+ }
196
+
197
+ .tooltip-content strong {
198
+ color: #FFFFFF;
199
+ display: block;
200
+ margin-bottom: 4px;
201
+ font-weight: 600;
202
+ }
203
+
204
+ .tooltip-content ul {
205
+ margin: 0;
206
+ padding-left: 16px;
207
+ color: #FFFFFF;
208
+ }
209
+
210
+ .tooltip-content * {
211
+ color: #FFFFFF;
212
+ }
213
+
214
+ .tooltip-content li {
215
+ margin-bottom: 2px;
216
+ color: #FFFFFF;
217
+ }
218
+
219
+ .tooltip-content li::before {
220
+ color: #FFFFFF !important;
221
+ }
222
+
223
+ .tooltip-content br {
224
+ display: block;
225
+ margin: 2px 0;
226
+ }
227
+
228
+ .info-value {
229
+ color: #2D3748;
230
+ font-weight: 500;
231
+ }
232
+
233
+ .characteristic-section {
234
+ background: #F8FAFC;
235
+ padding: 20px;
236
+ border-radius: 8px;
237
+ margin-bottom: 20px;
238
+ }
239
+
240
+ .subsection-title {
241
+ font-size: 18px;
242
+ color: #2D3748;
243
+ margin-bottom: 16px;
244
+ display: flex;
245
+ align-items: center;
246
+ gap: 8px;
247
+ }
248
+
249
+ .noise-level {
250
+ background: #EDF2F7;
251
+ padding: 16px;
252
+ border-radius: 6px;
253
+ margin: 16px 0;
254
+ border: 1px solid #CBD5E0;
255
+ }
256
+
257
+ .level-label {
258
+ color: #4A5568;
259
+ font-size: 1.1em;
260
+ font-weight: 500;
261
+ margin-bottom: 8px;
262
+ }
263
+
264
+ .level-value {
265
+ color: #2D3748;
266
+ font-size: 1.2em;
267
+ font-weight: 600;
268
+ }
269
+
270
+ .characteristics-grid {
271
+ display: grid;
272
+ grid-template-columns: repeat(2, 1fr);
273
+ gap: 12px;
274
+ margin-top: 12px;
275
+ }
276
+
277
+ .characteristic-item {
278
+ background: white;
279
+ padding: 12px;
280
+ border-radius: 6px;
281
+ border: 1px solid #E2E8F0;
282
+ color: #4A5568;
283
+ }
284
+
285
+ .health-insights {
286
+ margin-top: 24px;
287
+ }
288
+
289
+ .health-grid {
290
+ display: grid;
291
+ grid-template-columns: 1fr;
292
+ gap: 8px;
293
+ }
294
+
295
+ .health-item {
296
+ background: white;
297
+ padding: 12px;
298
+ border-radius: 6px;
299
+ border: 1px solid #E2E8F0;
300
+ color: #E53E3E;
301
+ }
302
+
303
+ .screening-item {
304
+ background: white;
305
+ padding: 12px;
306
+ border-radius: 6px;
307
+ border: 1px solid #E2E8F0;
308
+ color: #38A169;
309
+ }
310
+
311
+ .learn-more-btn {
312
+ display: inline-block;
313
+ margin-top: 20px;
314
+ padding: 12px 24px;
315
+ background: linear-gradient(135deg, #2B6CB0, #2C5282);
316
+ color: white;
317
+ text-decoration: none;
318
+ border-radius: 6px;
319
+ transition: all 0.3s ease;
320
+ text-align: center;
321
+ width: 100%;
322
+ font-weight: 500;
323
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
324
+ }
325
+
326
+ .learn-more-btn:hover {
327
+ background: linear-gradient(135deg, #2C5282, #2B6CB0);
328
+ transform: translateY(-2px);
329
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
330
+ }
331
+
332
+ .info-disclaimer {
333
+ margin-top: 24px;
334
+ padding: 16px;
335
+ background: #F7FAFC;
336
+ border-radius: 8px;
337
+ font-size: 0.9em;
338
+ color: #4A5568;
339
+ line-height: 1.5;
340
+ border-left: 4px solid #4299E1;
341
+ }
342
+
343
+ @media (max-width: 768px) {
344
+ .comparison-container {
345
+ grid-template-columns: 1fr;
346
+ }
347
+ .info-section {
348
+ grid-template-columns: 1fr;
349
+ }
350
+ .characteristics-grid {
351
+ grid-template-columns: 1fr;
352
+ }
353
+ }
354
+ """
355
+
356
+ def show_comparison(breed1, breed2):
357
+ if not breed1 or not breed2:
358
+ return "Please select two breeds to compare"
359
+
360
+ breed1_info = get_dog_description(breed1)
361
+ breed2_info = get_dog_description(breed2)
362
+ breed1_noise = breed_noise_info.get(breed1, {})
363
+ breed2_noise = breed_noise_info.get(breed2, {})
364
+ breed1_health = breed_health_info.get(breed1, {})
365
+ breed2_health = breed_health_info.get(breed2, {})
366
+
367
+ def create_info_item(label, value, tooltip_text=""):
368
+ tooltip = f"""
369
+ <div class="info-label">
370
+ <span>{label}</span>
371
+ <div class="tooltip">
372
+ <span class="info-icon">i</span>
373
+ <div class="tooltip-content">
374
+ {tooltip_text}
375
+ </div>
376
+ </div>
377
+ </div>
378
+ """ if tooltip_text else f'<div class="info-label">{label}</div>'
379
+
380
+ return f"""
381
+ <div class="info-item" style="position: relative;">
382
+ {tooltip}
383
+ <div class="info-value">{value}</div>
384
+ </div>
385
+ """
386
+
387
+ def create_breed_section(breed, info, noise_info, health_info):
388
+ # 建立提示文字
389
+ section_tooltips = {
390
+ 'Size': """
391
+ <strong>Size Categories:</strong><br>
392
+ • Small: Under 20 pounds<br>
393
+ • Medium: 20-60 pounds<br>
394
+ • Large: Over 60 pounds
395
+ """,
396
+ 'Exercise': """
397
+ <strong>Exercise Needs:</strong><br>
398
+ • Low: Short walks suffice<br>
399
+ • Moderate: 1-2 hours daily<br>
400
+ • High: 2+ hours daily activity<br>
401
+ • Very High: Intensive daily exercise
402
+ """,
403
+ 'Grooming': """
404
+ <strong>Grooming Requirements:</strong><br>
405
+ • Low: Occasional brushing<br>
406
+ • Moderate: Weekly grooming<br>
407
+ • High: Daily maintenance needed
408
+ """,
409
+ 'Children': """
410
+ <strong>Compatibility with Children:</strong><br>
411
+ • Yes: Excellent with kids<br>
412
+ • Moderate: Good with supervision<br>
413
+ • No: Better with older children
414
+ """,
415
+ 'Lifespan': """
416
+ <strong>Average Lifespan Range:</strong><br>
417
+ Typical lifespan for this breed with proper care and genetics
418
+ """,
419
+ 'noise': """
420
+ <strong>Noise Behavior Information:</strong><br>
421
+ • Noise Level indicates typical vocalization intensity<br>
422
+ • Characteristics describe common vocal behaviors<br>
423
+ • Triggers list common causes of barking or vocalization
424
+ """,
425
+ 'health': """
426
+ <strong>Health Information:</strong><br>
427
+ • Health considerations are breed-specific concerns<br>
428
+ • Screenings are recommended preventive tests<br>
429
+ • Always consult with veterinary professionals
430
+ """
431
+ }
432
+
433
+ noise_data = format_noise_data(noise_info.get('noise_notes', ''))
434
+ health_data = format_health_data(health_info.get('health_notes', ''))
435
+
436
+ def create_section_header(title, icon, tooltip_text):
437
+ return f"""
438
+ <div class="section-header">
439
+ <span>{icon}</span>
440
+ <span>{title}</span>
441
+ <span class="tooltip">
442
+ <span class="tooltip-icon">ⓘ</span>
443
+ <span class="tooltip-text">{tooltip_text}</span>
444
+ </span>
445
+ </div>
446
+ """
447
+
448
+ return f"""
449
+ <div class="breed-column">
450
+ <h2 class="section-title">🐕 {breed.replace('_', ' ')}</h2>
451
+
452
+ <div class="info-section">
453
+ {create_info_item('Size', info['Size'], section_tooltips['Size'])}
454
+ {create_info_item('Exercise', info['Exercise Needs'], section_tooltips['Exercise'])}
455
+ {create_info_item('Grooming', info['Grooming Needs'], section_tooltips['Grooming'])}
456
+ {create_info_item('With Children', info['Good with Children'], section_tooltips['Children'])}
457
+ {create_info_item('Lifespan', info['Lifespan'], section_tooltips['Lifespan'])}
458
+ </div>
459
+
460
+ <div class="characteristic-section">
461
+ {create_section_header('Noise Behavior', '🔊', section_tooltips['noise'])}
462
+ <div class="noise-level">
463
+ <div class="level-label">Noise Level</div>
464
+ <div class="level-value">{noise_data['noise_level'].upper()}</div>
465
+ </div>
466
+
467
+ <div class="subsection">
468
+ <h4>Typical Characteristics</h4>
469
+ <div class="characteristics-grid">
470
+ {' '.join([f'<div class="characteristic-item">{char}</div>'
471
+ for char in noise_data['characteristics']])}
472
+ </div>
473
+ </div>
474
+
475
+ <div class="subsection">
476
+ <h4>Barking Triggers</h4>
477
+ <div class="characteristics-grid">
478
+ {' '.join([f'<div class="characteristic-item">{trigger}</div>'
479
+ for trigger in noise_data['triggers']])}
480
+ </div>
481
+ </div>
482
+ </div>
483
+
484
+ <div class="characteristic-section health-insights">
485
+ {create_section_header('Health Insights', '🏥', section_tooltips['health'])}
486
+ <div class="subsection">
487
+ <h4>Health Considerations</h4>
488
+ <div class="health-grid">
489
+ {' '.join([f'<div class="health-item">{item}</div>'
490
+ for item in health_data['considerations']])}
491
+ </div>
492
+ </div>
493
+
494
+ <div class="subsection">
495
+ <h4>Recommended Screenings</h4>
496
+ <div class="health-grid">
497
+ {' '.join([f'<div class="screening-item">{item}</div>'
498
+ for item in health_data['screenings']])}
499
+ </div>
500
+ </div>
501
+ </div>
502
+
503
+ <a href="https://www.akc.org/dog-breeds/{breed.lower().replace('_', '-')}/"
504
+ class="learn-more-btn"
505
+ target="_blank">
506
+ 🌐 Learn more about {breed.replace('_', ' ')} on AKC
507
+ </a>
508
+ </div>
509
+ """
510
+
511
+ html_output = f"""
512
+ <div class="comparison-container">
513
+ {create_breed_section(breed1, breed1_info, breed1_noise, breed1_health)}
514
+ {create_breed_section(breed2, breed2_info, breed2_noise, breed2_health)}
515
+ </div>
516
+ <div class="info-disclaimer">
517
+ <strong>Note:</strong> The health and behavioral information provided is for general reference only.
518
+ Individual dogs may vary, and characteristics can be influenced by training, socialization, and genetics.
519
+ Always consult with veterinary professionals for specific health advice and professional trainers for
520
+ behavioral guidance.
521
+ </div>
522
+ <style>{get_comparison_styles()}</style>
523
+ """
524
+
525
+ return html_output
526
+
527
+ compare_btn.click(
528
+ show_comparison,
529
+ inputs=[breed1_dropdown, breed2_dropdown],
530
+ outputs=comparison_output
531
+ )
532
+
533
+ return {
534
+ 'breed1_dropdown': breed1_dropdown,
535
+ 'breed2_dropdown': breed2_dropdown,
536
+ 'compare_btn': compare_btn,
537
+ 'comparison_output': comparison_output
538
+ }