Spaces:
Running
on
Zero
Running
on
Zero
File size: 16,875 Bytes
1b3ab7b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
# %%writefile inference_engine.py
import re
import numpy as np
from typing import Dict, List, Tuple, Set, Optional, Any, Callable
from dataclasses import dataclass, field
import traceback
@dataclass
class InferenceRule:
"""推理規則結構"""
name: str
condition: Callable[[str, Dict[str, Any]], bool]
imply: Callable[[str, Dict[str, Any]], Dict[str, float]]
reasoning: str
priority: int = 1 # 規則優先級
@dataclass
class InferenceResult:
"""推理結果結構"""
implicit_priorities: Dict[str, float] = field(default_factory=dict)
triggered_rules: List[str] = field(default_factory=list)
reasoning_chains: List[str] = field(default_factory=list)
confidence: float = 1.0
class BreedRecommendationInferenceEngine:
"""
品種推薦推理引擎
從使用者明確輸入中推斷隱含需求,補充優先級設定
核心邏輯:
1. 居住環境推理 (公寓 → 安靜、中小型)
2. 家庭情況推理 (有小孩 → 溫和、耐心)
3. 經驗程度推理 (新手 → 易照顧)
4. 生活方式推理 (忙碌 → 低維護)
"""
def __init__(self):
"""初始化推理引擎"""
self.inference_rules = self._build_inference_rules()
self.spatial_keywords = self._initialize_spatial_keywords()
self.lifestyle_keywords = self._initialize_lifestyle_keywords()
def _initialize_spatial_keywords(self) -> Dict[str, List[str]]:
"""初始化空間相關關鍵字"""
return {
'apartment': [
'apartment', 'flat', 'condo', 'studio',
'small space', 'limited space', 'city living', 'urban'
],
'small_house': [
'small house', 'townhouse', 'small home'
],
'large_house': [
'large house', 'big house', 'spacious home',
'yard', 'garden', 'backyard', 'outdoor space'
]
}
def _initialize_lifestyle_keywords(self) -> Dict[str, List[str]]:
"""初始化生活方式關鍵字"""
return {
'has_children': [
'kids', 'children', 'toddler', 'baby', 'school age',
'child', 'son', 'daughter', 'family with kids'
],
'beginner': [
'first dog', 'first time', 'beginner', 'never had',
'new to dogs', 'inexperienced', 'no experience'
],
'busy': [
'busy', 'limited time', 'work full time', 'not much time',
'long hours', 'busy schedule', 'hectic lifestyle'
],
'active': [
'active', 'athletic', 'outdoor', 'hiking', 'running',
'jogging', 'sports', 'exercise enthusiast'
]
}
def _build_inference_rules(self) -> List[InferenceRule]:
"""構建推理規則庫"""
return [
# 規則1: 公寓居住推理
InferenceRule(
name="apartment_living",
condition=lambda input_text, ctx: self._check_apartment(input_text, ctx),
imply=lambda input_text, ctx: {
'noise': 1.3, # 公寓暗示需要安靜 (reduced from 1.4)
'size': 1.2, # 公寓暗示偏好中小型 (reduced from 1.3)
'exercise': 1.15 # 公寓暗示可能運動空間有限 (reduced from 1.2)
},
reasoning="Apartment living typically requires quieter, smaller dogs with moderate exercise needs",
priority=1
),
# 規則2: 有小孩推理
InferenceRule(
name="has_children",
condition=lambda input_text, ctx: self._check_children(input_text, ctx),
imply=lambda input_text, ctx: {
'family': 1.4, # 明確需要家庭友善 (reduced from 1.5)
'experience': 1.15, # 暗示希望容易訓練 (reduced from 1.2)
'noise': 1.15 # 有小孩通常希望狗較安靜 (reduced from 1.2)
},
reasoning="Families with children need gentle, patient, child-safe breeds",
priority=1
),
# 規則3: 新手飼主推理
InferenceRule(
name="beginner_owner",
condition=lambda input_text, ctx: self._check_beginner(input_text, ctx),
imply=lambda input_text, ctx: {
'experience': 1.3, # 需要容易照顧 (reduced from 1.4)
'grooming': 1.25, # 偏好低維護 (reduced from 1.3)
'health': 1.15 # 希望健康問題少 (reduced from 1.2)
},
reasoning="Beginners benefit from easier-to-care-for, low-maintenance breeds",
priority=1
),
# 規則4: 忙碌生活方式推理
InferenceRule(
name="busy_lifestyle",
condition=lambda input_text, ctx: self._check_busy(input_text, ctx),
imply=lambda input_text, ctx: {
'grooming': 1.3, # 需要低維護 (reduced from 1.4)
'exercise': 1.25, # 不能需要太多運動 (reduced from 1.3)
'experience': 1.15 # 希望獨立性強 (reduced from 1.2)
},
reasoning="Busy owners need lower-maintenance breeds with moderate exercise needs",
priority=1
),
# 規則5: 大型住宅推理
InferenceRule(
name="large_house",
condition=lambda input_text, ctx: self._check_large_house(input_text, ctx),
imply=lambda input_text, ctx: {
'size': 1.15, # 可以接受大型犬 (reduced from 1.2)
'exercise': 1.2 # 可能有更多運動空間 (reduced from 1.3)
},
reasoning="Large homes can accommodate more active, larger breeds",
priority=2
),
# 規則6: 有院子推理
InferenceRule(
name="has_yard",
condition=lambda input_text, ctx: self._check_yard(input_text, ctx),
imply=lambda input_text, ctx: {
'exercise': 1.2, # 有院子可以支持更活躍的品種 (reduced from 1.3)
'size': 1.15 # 可以考慮較大的品種 (reduced from 1.2)
},
reasoning="Yards provide exercise space for more active breeds",
priority=2
),
# 規則7: 噪音敏感環境推理
InferenceRule(
name="noise_sensitive",
condition=lambda input_text, ctx: self._check_noise_sensitive(input_text, ctx),
imply=lambda input_text, ctx: {
'noise': 1.5 # 強調需要安靜 (reduced from 1.6)
},
reasoning="Noise-sensitive environments require quieter breeds",
priority=1
),
# 規則8: 過敏體質推理
InferenceRule(
name="allergy_concerns",
condition=lambda input_text, ctx: self._check_allergies(input_text, ctx),
imply=lambda input_text, ctx: {
'grooming': 1.4, # 需要低掉毛品種 (reduced from 1.5)
'health': 1.25 # 關注健康問題 (reduced from 1.3)
},
reasoning="Allergy concerns require hypoallergenic, low-shedding breeds",
priority=1
),
# 規則9: 活躍生活方式推理
InferenceRule(
name="active_lifestyle",
condition=lambda input_text, ctx: self._check_active(input_text, ctx),
imply=lambda input_text, ctx: {
'exercise': 1.3, # 需要高運動量品種 (reduced from 1.4)
'size': 1.15 # 可能偏好中大型犬 (reduced from 1.2)
},
reasoning="Active lifestyle matches well with energetic, athletic breeds",
priority=1
),
# 規則10: 小型空間推理
InferenceRule(
name="small_space",
condition=lambda input_text, ctx: self._check_small_space(input_text, ctx),
imply=lambda input_text, ctx: {
'size': 1.3, # 強調需要小型犬 (reduced from 1.4)
'noise': 1.25, # 小空間需要安靜 (reduced from 1.3)
'exercise': 1.15 # 運動需求不宜過高 (reduced from 1.2)
},
reasoning="Small spaces require compact, quiet dogs with moderate energy",
priority=1
)
]
def _check_apartment(self, input_text: str, ctx: Dict[str, Any]) -> bool:
"""檢查是否提到公寓"""
text_lower = input_text.lower()
return (any(keyword in text_lower for keyword in self.spatial_keywords['apartment']) or
ctx.get('living_space') == 'apartment')
def _check_children(self, input_text: str, ctx: Dict[str, Any]) -> bool:
"""檢查是否有小孩"""
text_lower = input_text.lower()
return (any(keyword in text_lower for keyword in self.lifestyle_keywords['has_children']) or
ctx.get('has_children') == True)
def _check_beginner(self, input_text: str, ctx: Dict[str, Any]) -> bool:
"""檢查是否為新手"""
text_lower = input_text.lower()
return (any(keyword in text_lower for keyword in self.lifestyle_keywords['beginner']) or
ctx.get('experience_level') == 'beginner')
def _check_busy(self, input_text: str, ctx: Dict[str, Any]) -> bool:
"""檢查是否為忙碌生活方式"""
text_lower = input_text.lower()
return (any(keyword in text_lower for keyword in self.lifestyle_keywords['busy']) or
ctx.get('time_availability') == 'limited')
def _check_large_house(self, input_text: str, ctx: Dict[str, Any]) -> bool:
"""檢查是否有大房子"""
text_lower = input_text.lower()
return (any(keyword in text_lower for keyword in self.spatial_keywords['large_house']) or
ctx.get('living_space') in ['house_large', 'house'])
def _check_yard(self, input_text: str, ctx: Dict[str, Any]) -> bool:
"""檢查是否有院子"""
text_lower = input_text.lower()
return (any(keyword in text_lower for keyword in ['yard', 'garden', 'backyard', 'outdoor space']) or
ctx.get('yard_access') in ['shared_yard', 'private_yard'])
def _check_noise_sensitive(self, input_text: str, ctx: Dict[str, Any]) -> bool:
"""檢查是否為噪音敏感環境"""
text_lower = input_text.lower()
noise_keywords = ['noise sensitive', 'thin walls', 'neighbors close', 'townhouse', 'condo']
return any(keyword in text_lower for keyword in noise_keywords)
def _check_allergies(self, input_text: str, ctx: Dict[str, Any]) -> bool:
"""檢查是否有過敏體質"""
text_lower = input_text.lower()
allergy_keywords = ['allergies', 'hypoallergenic', 'sensitive to fur', 'asthma', 'allergy']
return (any(keyword in text_lower for keyword in allergy_keywords) or
ctx.get('has_allergies') == True)
def _check_active(self, input_text: str, ctx: Dict[str, Any]) -> bool:
"""檢查是否為活躍生活方式"""
text_lower = input_text.lower()
return (any(keyword in text_lower for keyword in self.lifestyle_keywords['active']) or
ctx.get('activity_level') == 'high')
def _check_small_space(self, input_text: str, ctx: Dict[str, Any]) -> bool:
"""檢查是否為小型空間"""
text_lower = input_text.lower()
small_space_keywords = ['small space', 'limited space', 'tiny', 'compact', 'studio']
return any(keyword in text_lower for keyword in small_space_keywords)
def infer_implicit_priorities(self,
explicit_input: str,
user_context: Optional[Dict[str, Any]] = None) -> InferenceResult:
"""
從明確輸入和使用者上下文推斷隱含優先級
Args:
explicit_input: 使用者明確輸入
user_context: 使用者上下文資訊
Returns:
InferenceResult: 推理結果
"""
try:
if user_context is None:
user_context = {}
implicit_priorities = {}
triggered_rules = []
reasoning_chains = []
# 按優先級排序規則
sorted_rules = sorted(self.inference_rules, key=lambda r: r.priority)
# 應用推理規則
for rule in sorted_rules:
try:
if rule.condition(explicit_input, user_context):
# 規則觸發
implied = rule.imply(explicit_input, user_context)
triggered_rules.append(rule.name)
reasoning_chains.append(rule.reasoning)
# 合併隱含優先級(取最大值)
for dim, score in implied.items():
implicit_priorities[dim] = max(
implicit_priorities.get(dim, 1.0),
score
)
except Exception as e:
print(f"Error applying rule {rule.name}: {str(e)}")
continue
# 計算信心度
confidence = self._calculate_inference_confidence(
triggered_rules, explicit_input
)
return InferenceResult(
implicit_priorities=implicit_priorities,
triggered_rules=triggered_rules,
reasoning_chains=reasoning_chains,
confidence=confidence
)
except Exception as e:
print(f"Error inferring implicit priorities: {str(e)}")
print(traceback.format_exc())
return InferenceResult()
def _calculate_inference_confidence(self,
triggered_rules: List[str],
input_text: str) -> float:
"""
計算推理信心度
Args:
triggered_rules: 觸發的規則列表
input_text: 輸入文字
Returns:
float: 信心度 (0-1)
"""
base_confidence = 0.6
# 觸發的規則越多,信心度越高
rule_bonus = min(0.3, len(triggered_rules) * 0.1)
# 輸入文字越詳細,信心度越高
word_count = len(input_text.split())
detail_bonus = min(0.1, word_count / 100)
return min(1.0, base_confidence + rule_bonus + detail_bonus)
def get_inference_summary(self, result: InferenceResult) -> Dict[str, Any]:
"""
獲取推理摘要
Args:
result: 推理結果
Returns:
Dict[str, Any]: 推理摘要
"""
return {
'total_implicit_priorities': len(result.implicit_priorities),
'implicit_priorities': result.implicit_priorities,
'triggered_rules': result.triggered_rules,
'reasoning_chains': result.reasoning_chains,
'inference_confidence': result.confidence,
'high_confidence_inferences': [
dim for dim, score in result.implicit_priorities.items() if score >= 1.4
]
}
def infer_user_priorities(user_input: str,
user_context: Optional[Dict[str, Any]] = None) -> InferenceResult:
"""
便利函數: 推斷使用者隱含優先級
Args:
user_input: 使用者輸入
user_context: 使用者上下文
Returns:
InferenceResult: 推理結果
"""
engine = BreedRecommendationInferenceEngine()
return engine.infer_implicit_priorities(user_input, user_context)
def get_inference_summary(user_input: str,
user_context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
"""
便利函數: 獲取推理摘要
Args:
user_input: 使用者輸入
user_context: 使用者上下文
Returns:
Dict[str, Any]: 推理摘要
"""
engine = BreedRecommendationInferenceEngine()
result = engine.infer_implicit_priorities(user_input, user_context)
return engine.get_inference_summary(result)
|