Spaces:
Running
on
Zero
Running
on
Zero
import logging | |
import traceback | |
import random | |
from typing import Dict, List, Optional, Any | |
from cultural_templates import CULTURAL_TEMPLATES | |
class CulturalContextError(Exception): | |
"""文化語境分析過程中的自定義異常""" | |
pass | |
class CulturalContextAnalyzer: | |
""" | |
文化語境分析器 - 檢測場景中的文化特徵並生成相關的描述 | |
該類別負責識別場景中的文化語境線索,包括建築風格、標誌特徵 | |
和物件配置,然後生成適當的文化描述元素。 | |
""" | |
def __init__(self, cultural_templates: Optional[Dict] = None): | |
""" | |
初始化文化語境分析器 | |
Args: | |
cultural_templates: 可選的自定義文化模板,如果提供則會與默認模板合併 | |
""" | |
self.logger = logging.getLogger(self.__class__.__name__) | |
try: | |
# 載入文化模板 | |
self.cultural_templates = self._load_cultural_templates() | |
# 如果提供了自定義模板,進行合併 | |
if cultural_templates: | |
self._merge_custom_templates(cultural_templates) | |
# 初始化場景類型到文化語境的映射 | |
self.scene_cultural_mapping = self._initialize_scene_cultural_mapping() | |
self.logger.info("CulturalContextAnalyzer initialized with %d cultural templates", | |
len(self.cultural_templates)) | |
except Exception as e: | |
error_msg = f"Failed to initialize CulturalContextAnalyzer: {str(e)}" | |
self.logger.error(f"{error_msg}\n{traceback.format_exc()}") | |
raise CulturalContextError(error_msg) from e | |
def _load_cultural_templates(self) -> Dict: | |
""" | |
載入文化模板 | |
Returns: | |
Dict: 文化模板字典 | |
Raises: | |
CulturalContextError: 當模板載入失敗時 | |
""" | |
try: | |
self.logger.debug("Loading cultural templates") | |
# 從配置模組載入文化模板 | |
templates = CULTURAL_TEMPLATES.copy() | |
# 確保模板結構正確 | |
self._validate_cultural_templates(templates) | |
# 如果沒有載入到模板,使用默認模板 | |
if not templates: | |
self.logger.warning("No cultural templates loaded, using defaults") | |
templates = self._get_default_cultural_templates() | |
self.logger.debug("Successfully loaded %d cultural template categories", len(templates)) | |
return templates | |
except ImportError as e: | |
self.logger.warning(f"Failed to import cultural templates: {str(e)}, using defaults") | |
return self._get_default_cultural_templates() | |
except Exception as e: | |
error_msg = f"Error loading cultural templates: {str(e)}" | |
self.logger.error(f"{error_msg}\n{traceback.format_exc()}") | |
raise CulturalContextError(error_msg) from e | |
def _get_default_cultural_templates(self) -> Dict: | |
""" | |
獲取默認文化模板 | |
Returns: | |
Dict: 默認文化模板字典 | |
""" | |
return { | |
"asian": { | |
"elements": [ | |
"traditional architectural elements", | |
"cultural signage", | |
"Asian design features", | |
"oriental decorative patterns", | |
"traditional building materials", | |
"characteristic roofline styles", | |
"cultural landscaping elements" | |
], | |
"description": "The scene displays distinctive Asian cultural characteristics with {elements}." | |
}, | |
"european": { | |
"elements": [ | |
"classical architecture", | |
"European design elements", | |
"historic features", | |
"traditional stonework", | |
"characteristic window styles", | |
"ornamental facades", | |
"heritage building elements" | |
], | |
"description": "The scene exhibits European architectural and cultural elements including {elements}." | |
}, | |
"american": { | |
"elements": [ | |
"modern architectural styles", | |
"contemporary design features", | |
"commercial signage", | |
"urban planning elements", | |
"standardized building designs" | |
], | |
"description": "The scene shows American urban characteristics featuring {elements}." | |
}, | |
"mediterranean": { | |
"elements": [ | |
"coastal architectural styles", | |
"warm climate adaptations", | |
"traditional building colors", | |
"characteristic outdoor spaces" | |
], | |
"description": "The scene reflects Mediterranean cultural influences with {elements}." | |
} | |
} | |
def _validate_cultural_templates(self, templates: Dict): | |
""" | |
驗證文化模板結構 | |
Args: | |
templates: 要驗證的模板字典 | |
Raises: | |
CulturalContextError: 當模板結構無效時 | |
""" | |
try: | |
for culture, template_data in templates.items(): | |
if not isinstance(template_data, dict): | |
self.logger.warning(f"Invalid cultural template structure for '{culture}': not a dictionary") | |
continue | |
required_keys = ["elements", "description"] | |
for key in required_keys: | |
if key not in template_data: | |
self.logger.warning(f"Missing required key '{key}' in cultural template '{culture}'") | |
# 驗證元素列表 | |
if "elements" in template_data: | |
if not isinstance(template_data["elements"], list): | |
self.logger.warning(f"Cultural template '{culture}' elements should be a list") | |
elif not template_data["elements"]: | |
self.logger.warning(f"Cultural template '{culture}' has empty elements list") | |
# 驗證描述模板 | |
if "description" in template_data: | |
if not isinstance(template_data["description"], str): | |
self.logger.warning(f"Cultural template '{culture}' description should be a string") | |
elif "{elements}" not in template_data["description"]: | |
self.logger.warning(f"Cultural template '{culture}' description missing {{elements}} placeholder") | |
self.logger.debug("Cultural templates validation completed") | |
except Exception as e: | |
self.logger.warning(f"Error validating cultural templates: {str(e)}") | |
def _merge_custom_templates(self, custom_templates: Dict): | |
""" | |
合併自定義文化模板 | |
Args: | |
custom_templates: 自定義模板字典 | |
""" | |
try: | |
for culture, template_data in custom_templates.items(): | |
if culture in self.cultural_templates: | |
# 合併現有文化的模板 | |
if isinstance(self.cultural_templates[culture], dict) and isinstance(template_data, dict): | |
# 合併元素列表 | |
if "elements" in template_data and "elements" in self.cultural_templates[culture]: | |
existing_elements = self.cultural_templates[culture]["elements"] | |
new_elements = template_data["elements"] | |
if isinstance(existing_elements, list) and isinstance(new_elements, list): | |
self.cultural_templates[culture]["elements"] = existing_elements + new_elements | |
# 更新其他鍵值 | |
for key, value in template_data.items(): | |
if key != "elements": | |
self.cultural_templates[culture][key] = value | |
else: | |
self.cultural_templates[culture] = template_data | |
else: | |
# 添加新的文化模板 | |
self.cultural_templates[culture] = template_data | |
self.logger.debug(f"Merged custom template for culture: {culture}") | |
self.logger.info("Successfully merged custom cultural templates") | |
except Exception as e: | |
self.logger.warning(f"Error merging custom cultural templates: {str(e)}") | |
def _initialize_scene_cultural_mapping(self) -> Dict[str, str]: | |
""" | |
初始化場景類型到文化語境的display | |
Returns: | |
Dict[str, str]: 場景類型到文化語境的映射字典 | |
""" | |
return { | |
"asian_commercial_street": "asian", | |
"asian_night_market": "asian", | |
"asian_temple_area": "asian", | |
"chinese_restaurant": "asian", | |
"japanese_restaurant": "asian", | |
"korean_restaurant": "asian", | |
"european_plaza": "european", | |
"european_cafe": "european", | |
"mediterranean_restaurant": "mediterranean", | |
"american_diner": "american", | |
"american_fast_food": "american" | |
} | |
def detect_cultural_context(self, scene_type: str, detected_objects: List[Dict]) -> Optional[str]: | |
""" | |
檢測場景的文化語境 | |
Args: | |
scene_type: 識別的場景類型 | |
detected_objects: 檢測到的物件列表 | |
Returns: | |
Optional[str]: 檢測到的文化語境(asian, european等)或None | |
""" | |
try: | |
self.logger.debug(f"Detecting cultural context for scene_type: {scene_type}") | |
# 檢查場景類型是否直接指示文化語境 | |
if scene_type in self.scene_cultural_mapping: | |
cultural_context = self.scene_cultural_mapping[scene_type] | |
self.logger.debug(f"Direct cultural mapping found: {scene_type} -> {cultural_context}") | |
return cultural_context | |
# 基於場景類型名稱的模式匹配 | |
cultural_context = self._detect_from_scene_name_patterns(scene_type) | |
if cultural_context: | |
self.logger.debug(f"Cultural context detected from name patterns: {cultural_context}") | |
return cultural_context | |
# 基於檢測物件的文化特徵分析 | |
cultural_context = self._detect_from_object_analysis(detected_objects) | |
if cultural_context: | |
self.logger.debug(f"Cultural context detected from object analysis: {cultural_context}") | |
return cultural_context | |
# 沒有檢測到特定文化語境 | |
self.logger.debug("No specific cultural context detected") | |
return None | |
except Exception as e: | |
self.logger.warning(f"Error detecting cultural context: {str(e)}") | |
return None | |
def _detect_from_scene_name_patterns(self, scene_type: str) -> Optional[str]: | |
""" | |
基於場景類型名稱模式檢測文化語境 | |
Args: | |
scene_type: 場景類型名稱 | |
Returns: | |
Optional[str]: 檢測到的文化語境或None | |
""" | |
try: | |
scene_lower = scene_type.lower() | |
# Asia | |
asian_keywords = [ | |
"asian", "chinese", "japanese", "korean", "thai", "vietnamese", | |
"temple", "pagoda", "zen", "oriental", "bamboo", "tatami" | |
] | |
# Europe | |
european_keywords = [ | |
"european", "french", "italian", "spanish", "german", "british", | |
"plaza", "piazza", "cathedral", "gothic", "baroque", "renaissance", | |
"cafe", "bistro", "pub" | |
] | |
# 地中海文化 | |
mediterranean_keywords = [ | |
"mediterranean", "greek", "turkish", "coastal", "terrace", | |
"villa", "courtyard" | |
] | |
# 美國 | |
american_keywords = [ | |
"american", "diner", "fast_food", "mall", "suburban", | |
"downtown", "strip_mall" | |
] | |
# 檢查各文化的key word | |
if any(keyword in scene_lower for keyword in asian_keywords): | |
return "asian" | |
elif any(keyword in scene_lower for keyword in european_keywords): | |
return "european" | |
elif any(keyword in scene_lower for keyword in mediterranean_keywords): | |
return "mediterranean" | |
elif any(keyword in scene_lower for keyword in american_keywords): | |
return "american" | |
return None | |
except Exception as e: | |
self.logger.warning(f"Error detecting cultural context from scene name patterns: {str(e)}") | |
return None | |
def _detect_from_object_analysis(self, detected_objects: List[Dict]) -> Optional[str]: | |
""" | |
基於檢測物件分析文化特徵 | |
Args: | |
detected_objects: 檢測到的物件列表 | |
Returns: | |
Optional[str]: 檢測到的文化語境或None | |
""" | |
try: | |
if not detected_objects: | |
return None | |
# 統計文化相關物件 | |
cultural_indicators = { | |
"asian": 0, | |
"european": 0, | |
"american": 0, | |
"mediterranean": 0 | |
} | |
for obj in detected_objects: | |
class_name = obj.get("class_name", "").lower() | |
# Asia 特色 | |
if any(indicator in class_name for indicator in [ | |
"lantern", "chopsticks", "rice", "noodles", "tea", | |
"bamboo", "pagoda", "shrine", "torii" | |
]): | |
cultural_indicators["asian"] += 1 | |
# 歐洲的特色 | |
elif any(indicator in class_name for indicator in [ | |
"wine", "cheese", "bread", "fountain", "column", | |
"statue", "cathedral", "clock_tower" | |
]): | |
cultural_indicators["european"] += 1 | |
# 地中海的特色 | |
elif any(indicator in class_name for indicator in [ | |
"olive", "terracotta", "pergola", "villa", | |
"coastal", "maritime" | |
]): | |
cultural_indicators["mediterranean"] += 1 | |
# 美國的特色 | |
elif any(indicator in class_name for indicator in [ | |
"burger", "pizza", "hotdog", "soda", | |
"drive_through", "parking_lot" | |
]): | |
cultural_indicators["american"] += 1 | |
# 找出得分最高的文化語境 | |
if max(cultural_indicators.values()) > 0: | |
dominant_culture = max(cultural_indicators.items(), key=lambda x: x[1])[0] | |
max_score = cultural_indicators[dominant_culture] | |
# 需要至少2個指標物件才算有效檢測 | |
if max_score >= 2: | |
return dominant_culture | |
return None | |
except Exception as e: | |
self.logger.warning(f"Error detecting cultural context from object analysis: {str(e)}") | |
return None | |
def generate_cultural_elements(self, cultural_context: str) -> str: | |
""" | |
為檢測到的文化語境生成描述元素 | |
Args: | |
cultural_context: 檢測到的文化語境 | |
Returns: | |
str: 文化元素描述 | |
Raises: | |
CulturalContextError: 當文化元素生成失敗時 | |
""" | |
try: | |
if not cultural_context: | |
return "" | |
self.logger.debug(f"Generating cultural elements for context: {cultural_context}") | |
# 獲取該文化語境的模板 | |
if cultural_context not in self.cultural_templates: | |
self.logger.warning(f"No template found for cultural context: {cultural_context}") | |
return "" | |
template = self.cultural_templates[cultural_context] | |
elements = template.get("elements", []) | |
if not elements: | |
self.logger.warning(f"No elements found for cultural context: {cultural_context}") | |
return "" | |
# 選擇1-2個隨機元素 | |
num_elements = min(len(elements), random.randint(1, 2)) | |
selected_elements = random.sample(elements, num_elements) | |
# 格式化元素列表 | |
if len(selected_elements) == 1: | |
elements_text = selected_elements[0] | |
else: | |
elements_text = " and ".join(selected_elements) | |
# 填充模板 | |
description_template = template.get("description", "") | |
if not description_template: | |
return f"The scene displays {cultural_context} cultural characteristics." | |
# 替換佔位符 | |
cultural_description = description_template.format(elements=elements_text) | |
self.logger.debug(f"Generated cultural description: {cultural_description}") | |
return cultural_description | |
except Exception as e: | |
error_msg = f"Error generating cultural elements for context '{cultural_context}': {str(e)}" | |
self.logger.error(f"{error_msg}\n{traceback.format_exc()}") | |
raise CulturalContextError(error_msg) from e | |
def get_cultural_template(self, cultural_context: str) -> Dict[str, Any]: | |
""" | |
獲取指定文化語境的模板 | |
Args: | |
cultural_context: 文化語境名稱 | |
Returns: | |
Dict[str, Any]: 文化模板字典 | |
""" | |
try: | |
if cultural_context in self.cultural_templates: | |
return self.cultural_templates[cultural_context].copy() | |
# 返回備用模板 | |
self.logger.warning(f"Cultural template not found for '{cultural_context}', using fallback") | |
return { | |
"elements": ["various cultural elements"], | |
"description": f"The scene displays {cultural_context} cultural characteristics." | |
} | |
except Exception as e: | |
self.logger.warning(f"Error getting cultural template for '{cultural_context}': {str(e)}") | |
return { | |
"elements": ["various elements"], | |
"description": "The scene displays cultural characteristics." | |
} | |
def add_cultural_template(self, cultural_context: str, template: Dict[str, Any]): | |
""" | |
添加或更新文化模板 | |
Args: | |
cultural_context: 文化語境名稱 | |
template: 文化模板字典 | |
Raises: | |
CulturalContextError: 當模板格式無效時 | |
""" | |
try: | |
# 驗證模板格式 | |
if not isinstance(template, dict): | |
raise CulturalContextError("Template must be a dictionary") | |
required_keys = ["elements", "description"] | |
for key in required_keys: | |
if key not in template: | |
raise CulturalContextError(f"Template missing required key: {key}") | |
if not isinstance(template["elements"], list): | |
raise CulturalContextError("Template 'elements' must be a list") | |
if not isinstance(template["description"], str): | |
raise CulturalContextError("Template 'description' must be a string") | |
# 添加模板 | |
self.cultural_templates[cultural_context] = template.copy() | |
self.logger.info(f"Added cultural template for context: {cultural_context}") | |
except CulturalContextError: | |
raise | |
except Exception as e: | |
error_msg = f"Error adding cultural template for '{cultural_context}': {str(e)}" | |
self.logger.error(f"{error_msg}\n{traceback.format_exc()}") | |
raise CulturalContextError(error_msg) from e | |
def get_supported_cultures(self) -> List[str]: | |
""" | |
獲取所有支援的文化語境列表 | |
Returns: | |
List[str]: 支援的文化語境名稱列表 | |
""" | |
return list(self.cultural_templates.keys()) | |
def has_cultural_context(self, cultural_context: str) -> bool: | |
""" | |
檢查是否支援指定的文化語境 | |
Args: | |
cultural_context: 文化語境名稱 | |
Returns: | |
bool: 是否支援該文化語境 | |
""" | |
return cultural_context in self.cultural_templates | |
def analyze_cultural_diversity(self, detected_objects: List[Dict]) -> Dict[str, int]: | |
""" | |
分析場景中的文化多樣性 | |
Args: | |
detected_objects: 檢測到的物件列表 | |
Returns: | |
Dict[str, int]: 各文化語境的指標物件計數 | |
""" | |
try: | |
cultural_scores = {culture: 0 for culture in self.cultural_templates.keys()} | |
if not detected_objects: | |
return cultural_scores | |
for obj in detected_objects: | |
class_name = obj.get("class_name", "").lower() | |
# 為每個文化語境計算指標分數 | |
for culture in cultural_scores: | |
if self._is_cultural_indicator(class_name, culture): | |
cultural_scores[culture] += 1 | |
self.logger.debug(f"Cultural diversity analysis: {cultural_scores}") | |
return cultural_scores | |
except Exception as e: | |
self.logger.warning(f"Error analyzing cultural diversity: {str(e)}") | |
return {culture: 0 for culture in self.cultural_templates.keys()} | |
def _is_cultural_indicator(self, object_name: str, culture: str) -> bool: | |
""" | |
檢查物件名稱是否為特定文化的指標 | |
Args: | |
object_name: 物件名稱 | |
culture: 文化語境 | |
Returns: | |
bool: 是否為該文化的指標物件 | |
""" | |
try: | |
cultural_keywords = { | |
"asian": [ | |
"lantern", "chopsticks", "rice", "noodles", "tea", | |
"bamboo", "pagoda", "shrine", "torii", "kimono", | |
"sushi", "ramen", "dim_sum" | |
], | |
"european": [ | |
"wine", "cheese", "bread", "fountain", "column", | |
"statue", "cathedral", "clock_tower", "baguette", | |
"croissant", "espresso", "gelato" | |
], | |
"mediterranean": [ | |
"olive", "terracotta", "pergola", "villa", | |
"coastal", "maritime", "cypress", "vineyard" | |
], | |
"american": [ | |
"burger", "pizza", "hotdog", "soda", | |
"drive_through", "parking_lot", "diner", | |
"strip_mall", "suburb" | |
] | |
} | |
if culture not in cultural_keywords: | |
return False | |
keywords = cultural_keywords[culture] | |
return any(keyword in object_name for keyword in keywords) | |
except Exception as e: | |
self.logger.warning(f"Error checking cultural indicator for {object_name}, {culture}: {str(e)}") | |
return False | |
def get_template_summary(self) -> Dict[str, Dict[str, Any]]: | |
""" | |
獲取所有文化模板的摘要信息 | |
Returns: | |
Dict[str, Dict[str, Any]]: 文化模板摘要 | |
""" | |
try: | |
summary = {} | |
for culture, template in self.cultural_templates.items(): | |
summary[culture] = { | |
"element_count": len(template.get("elements", [])), | |
"has_description": bool(template.get("description", "")), | |
"sample_elements": template.get("elements", [])[:3] # 前3個元素作為樣本 | |
} | |
return summary | |
except Exception as e: | |
self.logger.warning(f"Error generating template summary: {str(e)}") | |
return {} | |