DawnC commited on
Commit
6dcaa2e
1 Parent(s): 02bec90

Delete recommendation_html_format.py

Browse files
Files changed (1) hide show
  1. recommendation_html_format.py +0 -487
recommendation_html_format.py DELETED
@@ -1,487 +0,0 @@
1
- import sqlite3
2
- import traceback
3
- from typing import List, Dict
4
- from breed_health_info import breed_health_info, default_health_note
5
- from breed_noise_info import breed_noise_info
6
- from dog_database import get_dog_description
7
- from scoring_calculation_system import (
8
- UserPreferences,
9
- calculate_compatibility_score
10
- )
11
-
12
- def format_recommendation_html(recommendations: List[Dict]) -> str:
13
- """將推薦結果格式化為HTML"""
14
- html_content = "<div class='recommendations-container'>"
15
-
16
- for rec in recommendations:
17
- breed = rec['breed']
18
- scores = rec['scores']
19
- info = rec['info']
20
- rank = rec.get('rank', 0)
21
- final_score = rec.get('final_score', scores['overall'])
22
- bonus_score = rec.get('bonus_score', 0)
23
-
24
- health_info = breed_health_info.get(breed, {"health_notes": default_health_note})
25
- noise_info = breed_noise_info.get(breed, {
26
- "noise_notes": "Noise information not available",
27
- "noise_level": "Unknown",
28
- "source": "N/A"
29
- })
30
-
31
- # 解析噪音資訊
32
- noise_notes = noise_info.get('noise_notes', '').split('\n')
33
- noise_characteristics = []
34
- barking_triggers = []
35
- noise_level = ''
36
-
37
- current_section = None
38
- for line in noise_notes:
39
- line = line.strip()
40
- if 'Typical noise characteristics:' in line:
41
- current_section = 'characteristics'
42
- elif 'Noise level:' in line:
43
- noise_level = line.replace('Noise level:', '').strip()
44
- elif 'Barking triggers:' in line:
45
- current_section = 'triggers'
46
- elif line.startswith('•'):
47
- if current_section == 'characteristics':
48
- noise_characteristics.append(line[1:].strip())
49
- elif current_section == 'triggers':
50
- barking_triggers.append(line[1:].strip())
51
-
52
- # 生成特徵和觸發因素的HTML
53
- noise_characteristics_html = '\n'.join([f'<li>{item}</li>' for item in noise_characteristics])
54
- barking_triggers_html = '\n'.join([f'<li>{item}</li>' for item in barking_triggers])
55
-
56
- # 處理健康資訊
57
- health_notes = health_info.get('health_notes', '').split('\n')
58
- health_considerations = []
59
- health_screenings = []
60
-
61
- current_section = None
62
- for line in health_notes:
63
- line = line.strip()
64
- if 'Common breed-specific health considerations' in line:
65
- current_section = 'considerations'
66
- elif 'Recommended health screenings:' in line:
67
- current_section = 'screenings'
68
- elif line.startswith('•'):
69
- if current_section == 'considerations':
70
- health_considerations.append(line[1:].strip())
71
- elif current_section == 'screenings':
72
- health_screenings.append(line[1:].strip())
73
-
74
- health_considerations_html = '\n'.join([f'<li>{item}</li>' for item in health_considerations])
75
- health_screenings_html = '\n'.join([f'<li>{item}</li>' for item in health_screenings])
76
-
77
- # 獎勵原因計算
78
- bonus_reasons = []
79
- temperament = info.get('Temperament', '').lower()
80
- if any(trait in temperament for trait in ['friendly', 'gentle', 'affectionate']):
81
- bonus_reasons.append("Positive temperament traits")
82
- if info.get('Good with Children') == 'Yes':
83
- bonus_reasons.append("Excellent with children")
84
- try:
85
- lifespan = info.get('Lifespan', '10-12 years')
86
- years = int(lifespan.split('-')[0])
87
- if years > 12:
88
- bonus_reasons.append("Above-average lifespan")
89
- except:
90
- pass
91
-
92
- html_content += f"""
93
- <div class="dog-info-card recommendation-card">
94
- <div class="breed-info">
95
- <h2 class="section-title">
96
- <span class="icon">🏆</span> #{rank} {breed.replace('_', ' ')}
97
- <span class="score-badge">
98
- Overall Match: {final_score*100:.1f}%
99
- </span>
100
- </h2>
101
- <div class="compatibility-scores">
102
- <div class="score-item">
103
- <span class="label">Space Compatibility:</span>
104
- <div class="progress-bar">
105
- <div class="progress" style="width: {scores['space']*100}%"></div>
106
- </div>
107
- <span class="percentage">{scores['space']*100:.1f}%</span>
108
- </div>
109
- <div class="score-item">
110
- <span class="label">Exercise Match:</span>
111
- <div class="progress-bar">
112
- <div class="progress" style="width: {scores['exercise']*100}%"></div>
113
- </div>
114
- <span class="percentage">{scores['exercise']*100:.1f}%</span>
115
- </div>
116
- <div class="score-item">
117
- <span class="label">Grooming Match:</span>
118
- <div class="progress-bar">
119
- <div class="progress" style="width: {scores['grooming']*100}%"></div>
120
- </div>
121
- <span class="percentage">{scores['grooming']*100:.1f}%</span>
122
- </div>
123
- <div class="score-item">
124
- <span class="label">Experience Match:</span>
125
- <div class="progress-bar">
126
- <div class="progress" style="width: {scores['experience']*100}%"></div>
127
- </div>
128
- <span class="percentage">{scores['experience']*100:.1f}%</span>
129
- </div>
130
- <div class="score-item">
131
- <span class="label">
132
- Noise Compatibility:
133
- <span class="tooltip">
134
- <span class="tooltip-icon">ⓘ</span>
135
- <span class="tooltip-text">
136
- <strong>Noise Compatibility Score:</strong><br>
137
- • Based on your noise tolerance preference<br>
138
- • Considers breed's typical noise level<br>
139
- • Accounts for living environment
140
- </span>
141
- </span>
142
- </span>
143
- <div class="progress-bar">
144
- <div class="progress" style="width: {scores['noise']*100}%"></div>
145
- </div>
146
- <span class="percentage">{scores['noise']*100:.1f}%</span>
147
- </div>
148
- {f'''
149
- <div class="score-item bonus-score">
150
- <span class="label">
151
- Breed Bonus:
152
- <span class="tooltip">
153
- <span class="tooltip-icon">ⓘ</span>
154
- <span class="tooltip-text">
155
- <strong>Breed Bonus Points:</strong><br>
156
- • {('<br>• '.join(bonus_reasons)) if bonus_reasons else 'No additional bonus points'}<br>
157
- <br>
158
- <strong>Bonus Factors Include:</strong><br>
159
- • Friendly temperament<br>
160
- • Child compatibility<br>
161
- • Longer lifespan<br>
162
- • Living space adaptability
163
- </span>
164
- </span>
165
- </span>
166
- <div class="progress-bar">
167
- <div class="progress" style="width: {bonus_score*100}%"></div>
168
- </div>
169
- <span class="percentage">{bonus_score*100:.1f}%</span>
170
- </div>
171
- ''' if bonus_score > 0 else ''}
172
- </div>
173
- <div class="breed-details-section">
174
- <h3 class="subsection-title">
175
- <span class="icon">📋</span> Breed Details
176
- </h3>
177
- <div class="details-grid">
178
- <div class="detail-item">
179
- <span class="tooltip">
180
- <span class="icon">📏</span>
181
- <span class="label">Size:</span>
182
- <span class="tooltip-icon">ⓘ</span>
183
- <span class="tooltip-text">
184
- <strong>Size Categories:</strong><br>
185
- • Small: Under 20 pounds<br>
186
- • Medium: 20-60 pounds<br>
187
- • Large: Over 60 pounds
188
- </span>
189
- <span class="value">{info['Size']}</span>
190
- </span>
191
- </div>
192
- <div class="detail-item">
193
- <span class="tooltip">
194
- <span class="icon">🏃</span>
195
- <span class="label">Exercise Needs:</span>
196
- <span class="tooltip-icon">ⓘ</span>
197
- <span class="tooltip-text">
198
- <strong>Exercise Needs:</strong><br>
199
- • Low: Short walks<br>
200
- • Moderate: 1-2 hours daily<br>
201
- • High: 2+ hours daily<br>
202
- • Very High: Constant activity
203
- </span>
204
- <span class="value">{info['Exercise Needs']}</span>
205
- </span>
206
- </div>
207
- <div class="detail-item">
208
- <span class="tooltip">
209
- <span class="icon">👨‍👩‍👧‍👦</span>
210
- <span class="label">Good with Children:</span>
211
- <span class="tooltip-icon">ⓘ</span>
212
- <span class="tooltip-text">
213
- <strong>Child Compatibility:</strong><br>
214
- • Yes: Excellent with kids<br>
215
- • Moderate: Good with older children<br>
216
- • No: Better for adult households
217
- </span>
218
- <span class="value">{info['Good with Children']}</span>
219
- </span>
220
- </div>
221
- <div class="detail-item">
222
- <span class="tooltip">
223
- <span class="icon">⏳</span>
224
- <span class="label">Lifespan:</span>
225
- <span class="tooltip-icon">ⓘ</span>
226
- <span class="tooltip-text">
227
- <strong>Average Lifespan:</strong><br>
228
- • Short: 6-8 years<br>
229
- • Average: 10-15 years<br>
230
- • Long: 12-20 years<br>
231
- • Varies by size: Larger breeds typically have shorter lifespans
232
- </span>
233
- </span>
234
- <span class="value">{info['Lifespan']}</span>
235
- </div>
236
- </div>
237
- </div>
238
- <div class="description-section">
239
- <h3 class="subsection-title">
240
- <span class="icon">📝</span> Description
241
- </h3>
242
- <p class="description-text">{info.get('Description', '')}</p>
243
- </div>
244
- <div class="noise-section">
245
- <h3 class="section-header">
246
- <span class="icon">🔊</span> Noise Behavior
247
- </h3>
248
- <div class="noise-info">
249
- <div class="noise-details">
250
- <h4 class="section-header">Typical noise characteristics:</h4>
251
- <div class="characteristics-list">
252
- <div class="list-item">Moderate to high barker</div>
253
- <div class="list-item">Alert watch dog</div>
254
- <div class="list-item">Attention-seeking barks</div>
255
- <div class="list-item">Social vocalizations</div>
256
- </div>
257
-
258
- <div class="noise-level-display">
259
- <h4 class="section-header">Noise level:</h4>
260
- <div class="level-indicator">
261
- <span class="level-text">Moderate-High</span>
262
- <div class="level-bars">
263
- <span class="bar"></span>
264
- <span class="bar"></span>
265
- <span class="bar"></span>
266
- </div>
267
- </div>
268
- </div>
269
-
270
- <h4 class="section-header">Barking triggers:</h4>
271
- <div class="triggers-list">
272
- <div class="list-item">Separation anxiety</div>
273
- <div class="list-item">Attention needs</div>
274
- <div class="list-item">Strange noises</div>
275
- <div class="list-item">Excitement</div>
276
- </div>
277
- </div>
278
- <div class="noise-disclaimer">
279
- <p class="disclaimer-text source-text">Source: Compiled from various breed behavior resources, 2024</p>
280
- <p class="disclaimer-text">Individual dogs may vary in their vocalization patterns.</p>
281
- <p class="disclaimer-text">Training can significantly influence barking behavior.</p>
282
- <p class="disclaimer-text">Environmental factors may affect noise levels.</p>
283
- </div>
284
- </div>
285
- </div>
286
-
287
- <div class="health-section">
288
- <h3 class="section-header">
289
- <span class="icon">🏥</span> Health Insights
290
- <span class="tooltip">
291
- <span class="tooltip-icon">ⓘ</span>
292
- <span class="tooltip-text">
293
- Health information is compiled from multiple sources including veterinary resources, breed guides, and international canine health databases.
294
- Each dog is unique and may vary from these general guidelines.
295
- </span>
296
- </span>
297
- </h3>
298
- <div class="health-info">
299
- <div class="health-details">
300
- <div class="health-block">
301
- <h4 class="section-header">Common breed-specific health considerations:</h4>
302
- <div class="health-grid">
303
- <div class="health-item">Patellar luxation</div>
304
- <div class="health-item">Progressive retinal atrophy</div>
305
- <div class="health-item">Von Willebrand's disease</div>
306
- <div class="health-item">Open fontanel</div>
307
- </div>
308
- </div>
309
-
310
- <div class="health-block">
311
- <h4 class="section-header">Recommended health screenings:</h4>
312
- <div class="health-grid">
313
- <div class="health-item screening">Patella evaluation</div>
314
- <div class="health-item screening">Eye examination</div>
315
- <div class="health-item screening">Blood clotting tests</div>
316
- <div class="health-item screening">Skull development monitoring</div>
317
- </div>
318
- </div>
319
- </div>
320
- <div class="health-disclaimer">
321
- <p class="disclaimer-text source-text">Source: Compiled from various veterinary and breed information resources, 2024</p>
322
- <p class="disclaimer-text">This information is for reference only and based on breed tendencies.</p>
323
- <p class="disclaimer-text">Each dog is unique and may not develop any or all of these conditions.</p>
324
- <p class="disclaimer-text">Always consult with qualified veterinarians for professional advice.</p>
325
- </div>
326
- </div>
327
- </div>
328
-
329
- <div class="action-section">
330
- <a href="https://www.akc.org/dog-breeds/{breed.lower().replace('_', '-')}/"
331
- target="_blank"
332
- class="akc-button">
333
- <span class="icon">🌐</span>
334
- Learn more about {breed.replace('_', ' ')} on AKC website
335
- </a>
336
- </div>
337
- </div>
338
- </div>
339
- """
340
-
341
- html_content += "</div>"
342
- return html_content
343
-
344
- def get_breed_recommendations(user_prefs: UserPreferences, top_n: int = 10) -> List[Dict]:
345
- """基於使用者偏好推薦狗品種,確保正確的分數排序"""
346
- print("Starting get_breed_recommendations")
347
- recommendations = []
348
- seen_breeds = set()
349
-
350
- try:
351
- # 獲取所有品種
352
- conn = sqlite3.connect('animal_detector.db')
353
- cursor = conn.cursor()
354
- cursor.execute("SELECT Breed FROM AnimalCatalog")
355
- all_breeds = cursor.fetchall()
356
- conn.close()
357
-
358
- # 收集所有品種的分數
359
- for breed_tuple in all_breeds:
360
- breed = breed_tuple[0]
361
- base_breed = breed.split('(')[0].strip()
362
-
363
- if base_breed in seen_breeds:
364
- continue
365
- seen_breeds.add(base_breed)
366
-
367
- # 獲取品種資訊
368
- breed_info = get_dog_description(breed)
369
- if not isinstance(breed_info, dict):
370
- continue
371
-
372
- # 獲取噪音資訊
373
- noise_info = breed_noise_info.get(breed, {
374
- "noise_notes": "Noise information not available",
375
- "noise_level": "Unknown",
376
- "source": "N/A"
377
- })
378
-
379
- # 將噪音資訊整合到品種資訊中
380
- breed_info['noise_info'] = noise_info
381
-
382
- # 計算基礎相容性分數
383
- compatibility_scores = calculate_compatibility_score(breed_info, user_prefs)
384
-
385
- # 計算品種特定加分
386
- breed_bonus = 0.0
387
-
388
- # 壽命加分
389
- try:
390
- lifespan = breed_info.get('Lifespan', '10-12 years')
391
- years = [int(x) for x in lifespan.split('-')[0].split()[0:1]]
392
- longevity_bonus = min(0.02, (max(years) - 10) * 0.005)
393
- breed_bonus += longevity_bonus
394
- except:
395
- pass
396
-
397
- # 性格特徵加分
398
- temperament = breed_info.get('Temperament', '').lower()
399
- positive_traits = ['friendly', 'gentle', 'affectionate', 'intelligent']
400
- negative_traits = ['aggressive', 'stubborn', 'dominant']
401
-
402
- breed_bonus += sum(0.01 for trait in positive_traits if trait in temperament)
403
- breed_bonus -= sum(0.01 for trait in negative_traits if trait in temperament)
404
-
405
- # 與孩童相容性加分
406
- if user_prefs.has_children:
407
- if breed_info.get('Good with Children') == 'Yes':
408
- breed_bonus += 0.02
409
- elif breed_info.get('Good with Children') == 'No':
410
- breed_bonus -= 0.03
411
-
412
- # 噪音相關加分
413
- if user_prefs.noise_tolerance == 'low':
414
- if noise_info['noise_level'].lower() == 'high':
415
- breed_bonus -= 0.03
416
- elif noise_info['noise_level'].lower() == 'low':
417
- breed_bonus += 0.02
418
- elif user_prefs.noise_tolerance == 'high':
419
- if noise_info['noise_level'].lower() == 'high':
420
- breed_bonus += 0.01
421
-
422
- # 計算最終分數
423
- breed_bonus = round(breed_bonus, 4)
424
- final_score = round(compatibility_scores['overall'] + breed_bonus, 4)
425
-
426
- recommendations.append({
427
- 'breed': breed,
428
- 'base_score': round(compatibility_scores['overall'], 4),
429
- 'bonus_score': round(breed_bonus, 4),
430
- 'final_score': final_score,
431
- 'scores': compatibility_scores,
432
- 'info': breed_info,
433
- 'noise_info': noise_info # 添加噪音資訊到推薦結果
434
- })
435
- # 嚴格按照 final_score 排序
436
- recommendations.sort(key=lambda x: (round(-x['final_score'], 4), x['breed'] )) # 負號使其降序排列,並確保4位小數
437
-
438
- # 選擇前N名並確保正確排序
439
- final_recommendations = []
440
- last_score = None
441
- rank = 1
442
-
443
- for rec in recommendations:
444
- if len(final_recommendations) >= top_n:
445
- break
446
-
447
- current_score = rec['final_score']
448
-
449
- # 確保分數遞減
450
- if last_score is not None and current_score > last_score:
451
- continue
452
-
453
- # 添加排名資訊
454
- rec['rank'] = rank
455
- final_recommendations.append(rec)
456
-
457
- last_score = current_score
458
- rank += 1
459
-
460
- # 驗證最終排序
461
- for i in range(len(final_recommendations)-1):
462
- current = final_recommendations[i]
463
- next_rec = final_recommendations[i+1]
464
-
465
- if current['final_score'] < next_rec['final_score']:
466
- print(f"Warning: Sorting error detected!")
467
- print(f"#{i+1} {current['breed']}: {current['final_score']}")
468
- print(f"#{i+2} {next_rec['breed']}: {next_rec['final_score']}")
469
-
470
- # 交換位置
471
- final_recommendations[i], final_recommendations[i+1] = \
472
- final_recommendations[i+1], final_recommendations[i]
473
-
474
- # 打印最終結果以供驗證
475
- print("\nFinal Rankings:")
476
- for rec in final_recommendations:
477
- print(f"#{rec['rank']} {rec['breed']}")
478
- print(f"Base Score: {rec['base_score']:.4f}")
479
- print(f"Bonus: {rec['bonus_score']:.4f}")
480
- print(f"Final Score: {rec['final_score']:.4f}\n")
481
-
482
- return final_recommendations
483
-
484
- except Exception as e:
485
- print(f"Error in get_breed_recommendations: {str(e)}")
486
- print(f"Traceback: {traceback.format_exc()}")
487
- return []