VisionScout / cultural_context_analyzer.py
DawnC's picture
Upload 59 files
e6a18b7 verified
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 {}