DawnC commited on
Commit
348967e
1 Parent(s): fa4c635

Delete recommendation_html_format.py

Browse files
Files changed (1) hide show
  1. recommendation_html_format.py +0 -496
recommendation_html_format.py DELETED
@@ -1,496 +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
- <span class="tooltip">
248
- <span class="tooltip-icon">ⓘ</span>
249
- <span class="tooltip-text">
250
- <strong>Noise Behavior:</strong><br>
251
- • Typical vocalization patterns<br>
252
- • Common triggers and frequency<br>
253
- • Based on breed characteristics
254
- </span>
255
- </span>
256
- </h3>
257
- <div class="noise-info">
258
- <div class="noise-details">
259
- <h4 class="section-header">Typical noise characteristics:</h4>
260
- <div class="characteristics-list">
261
- <div class="list-item">Moderate to high barker</div>
262
- <div class="list-item">Alert watch dog</div>
263
- <div class="list-item">Attention-seeking barks</div>
264
- <div class="list-item">Social vocalizations</div>
265
- </div>
266
-
267
- <div class="noise-level-display">
268
- <h4 class="section-header">Noise level:</h4>
269
- <div class="level-indicator">
270
- <span class="level-text">Moderate-High</span>
271
- <div class="level-bars">
272
- <span class="bar"></span>
273
- <span class="bar"></span>
274
- <span class="bar"></span>
275
- </div>
276
- </div>
277
- </div>
278
-
279
- <h4 class="section-header">Barking triggers:</h4>
280
- <div class="triggers-list">
281
- <div class="list-item">Separation anxiety</div>
282
- <div class="list-item">Attention needs</div>
283
- <div class="list-item">Strange noises</div>
284
- <div class="list-item">Excitement</div>
285
- </div>
286
- </div>
287
- <div class="noise-disclaimer">
288
- <p class="disclaimer-text source-text">Source: Compiled from various breed behavior resources, 2024</p>
289
- <p class="disclaimer-text">Individual dogs may vary in their vocalization patterns.</p>
290
- <p class="disclaimer-text">Training can significantly influence barking behavior.</p>
291
- <p class="disclaimer-text">Environmental factors may affect noise levels.</p>
292
- </div>
293
- </div>
294
- </div>
295
-
296
- <div class="health-section">
297
- <h3 class="section-header">
298
- <span class="icon">🏥</span> Health Insights
299
- <span class="tooltip">
300
- <span class="tooltip-icon">ⓘ</span>
301
- <span class="tooltip-text">
302
- Health information is compiled from multiple sources including veterinary resources, breed guides, and international canine health databases.
303
- Each dog is unique and may vary from these general guidelines.
304
- </span>
305
- </span>
306
- </h3>
307
- <div class="health-info">
308
- <div class="health-details">
309
- <div class="health-block">
310
- <h4 class="section-header">Common breed-specific health considerations:</h4>
311
- <div class="health-grid">
312
- <div class="health-item">Patellar luxation</div>
313
- <div class="health-item">Progressive retinal atrophy</div>
314
- <div class="health-item">Von Willebrand's disease</div>
315
- <div class="health-item">Open fontanel</div>
316
- </div>
317
- </div>
318
-
319
- <div class="health-block">
320
- <h4 class="section-header">Recommended health screenings:</h4>
321
- <div class="health-grid">
322
- <div class="health-item screening">Patella evaluation</div>
323
- <div class="health-item screening">Eye examination</div>
324
- <div class="health-item screening">Blood clotting tests</div>
325
- <div class="health-item screening">Skull development monitoring</div>
326
- </div>
327
- </div>
328
- </div>
329
- <div class="health-disclaimer">
330
- <p class="disclaimer-text source-text">Source: Compiled from various veterinary and breed information resources, 2024</p>
331
- <p class="disclaimer-text">This information is for reference only and based on breed tendencies.</p>
332
- <p class="disclaimer-text">Each dog is unique and may not develop any or all of these conditions.</p>
333
- <p class="disclaimer-text">Always consult with qualified veterinarians for professional advice.</p>
334
- </div>
335
- </div>
336
- </div>
337
-
338
- <div class="action-section">
339
- <a href="https://www.akc.org/dog-breeds/{breed.lower().replace('_', '-')}/"
340
- target="_blank"
341
- class="akc-button">
342
- <span class="icon">🌐</span>
343
- Learn more about {breed.replace('_', ' ')} on AKC website
344
- </a>
345
- </div>
346
- </div>
347
- </div>
348
- """
349
-
350
- html_content += "</div>"
351
- return html_content
352
-
353
- def get_breed_recommendations(user_prefs: UserPreferences, top_n: int = 10) -> List[Dict]:
354
- """基於使用者偏好推薦狗品種,確保正確的分數排序"""
355
- print("Starting get_breed_recommendations")
356
- recommendations = []
357
- seen_breeds = set()
358
-
359
- try:
360
- # 獲取所有品種
361
- conn = sqlite3.connect('animal_detector.db')
362
- cursor = conn.cursor()
363
- cursor.execute("SELECT Breed FROM AnimalCatalog")
364
- all_breeds = cursor.fetchall()
365
- conn.close()
366
-
367
- # 收集所有品種的分數
368
- for breed_tuple in all_breeds:
369
- breed = breed_tuple[0]
370
- base_breed = breed.split('(')[0].strip()
371
-
372
- if base_breed in seen_breeds:
373
- continue
374
- seen_breeds.add(base_breed)
375
-
376
- # 獲取品種資訊
377
- breed_info = get_dog_description(breed)
378
- if not isinstance(breed_info, dict):
379
- continue
380
-
381
- # 獲取噪音資訊
382
- noise_info = breed_noise_info.get(breed, {
383
- "noise_notes": "Noise information not available",
384
- "noise_level": "Unknown",
385
- "source": "N/A"
386
- })
387
-
388
- # 將噪音資訊整合到品種資訊中
389
- breed_info['noise_info'] = noise_info
390
-
391
- # 計算基礎相容性分數
392
- compatibility_scores = calculate_compatibility_score(breed_info, user_prefs)
393
-
394
- # 計算品種特定加分
395
- breed_bonus = 0.0
396
-
397
- # 壽命加分
398
- try:
399
- lifespan = breed_info.get('Lifespan', '10-12 years')
400
- years = [int(x) for x in lifespan.split('-')[0].split()[0:1]]
401
- longevity_bonus = min(0.02, (max(years) - 10) * 0.005)
402
- breed_bonus += longevity_bonus
403
- except:
404
- pass
405
-
406
- # 性格特徵加分
407
- temperament = breed_info.get('Temperament', '').lower()
408
- positive_traits = ['friendly', 'gentle', 'affectionate', 'intelligent']
409
- negative_traits = ['aggressive', 'stubborn', 'dominant']
410
-
411
- breed_bonus += sum(0.01 for trait in positive_traits if trait in temperament)
412
- breed_bonus -= sum(0.01 for trait in negative_traits if trait in temperament)
413
-
414
- # 與孩童相容性加分
415
- if user_prefs.has_children:
416
- if breed_info.get('Good with Children') == 'Yes':
417
- breed_bonus += 0.02
418
- elif breed_info.get('Good with Children') == 'No':
419
- breed_bonus -= 0.03
420
-
421
- # 噪音相關加分
422
- if user_prefs.noise_tolerance == 'low':
423
- if noise_info['noise_level'].lower() == 'high':
424
- breed_bonus -= 0.03
425
- elif noise_info['noise_level'].lower() == 'low':
426
- breed_bonus += 0.02
427
- elif user_prefs.noise_tolerance == 'high':
428
- if noise_info['noise_level'].lower() == 'high':
429
- breed_bonus += 0.01
430
-
431
- # 計算最終分數
432
- breed_bonus = round(breed_bonus, 4)
433
- final_score = round(compatibility_scores['overall'] + breed_bonus, 4)
434
-
435
- recommendations.append({
436
- 'breed': breed,
437
- 'base_score': round(compatibility_scores['overall'], 4),
438
- 'bonus_score': round(breed_bonus, 4),
439
- 'final_score': final_score,
440
- 'scores': compatibility_scores,
441
- 'info': breed_info,
442
- 'noise_info': noise_info # 添加噪音資訊到推薦結果
443
- })
444
- # 嚴格按照 final_score 排序
445
- recommendations.sort(key=lambda x: (round(-x['final_score'], 4), x['breed'] )) # 負號使其降序排列,並確保4位小數
446
-
447
- # 選擇前N名並確保正確排序
448
- final_recommendations = []
449
- last_score = None
450
- rank = 1
451
-
452
- for rec in recommendations:
453
- if len(final_recommendations) >= top_n:
454
- break
455
-
456
- current_score = rec['final_score']
457
-
458
- # 確保分數遞減
459
- if last_score is not None and current_score > last_score:
460
- continue
461
-
462
- # 添加排名資訊
463
- rec['rank'] = rank
464
- final_recommendations.append(rec)
465
-
466
- last_score = current_score
467
- rank += 1
468
-
469
- # 驗證最終排序
470
- for i in range(len(final_recommendations)-1):
471
- current = final_recommendations[i]
472
- next_rec = final_recommendations[i+1]
473
-
474
- if current['final_score'] < next_rec['final_score']:
475
- print(f"Warning: Sorting error detected!")
476
- print(f"#{i+1} {current['breed']}: {current['final_score']}")
477
- print(f"#{i+2} {next_rec['breed']}: {next_rec['final_score']}")
478
-
479
- # 交換位置
480
- final_recommendations[i], final_recommendations[i+1] = \
481
- final_recommendations[i+1], final_recommendations[i]
482
-
483
- # 打印最終結果以供驗證
484
- print("\nFinal Rankings:")
485
- for rec in final_recommendations:
486
- print(f"#{rec['rank']} {rec['breed']}")
487
- print(f"Base Score: {rec['base_score']:.4f}")
488
- print(f"Bonus: {rec['bonus_score']:.4f}")
489
- print(f"Final Score: {rec['final_score']:.4f}\n")
490
-
491
- return final_recommendations
492
-
493
- except Exception as e:
494
- print(f"Error in get_breed_recommendations: {str(e)}")
495
- print(f"Traceback: {traceback.format_exc()}")
496
- return []