import logging import random import re from typing import Dict, List, Optional, Union, Any class ContentGenerator: """ 內容生成器 - 負責基礎內容生成和佔位符替換邏輯 此類別專門處理模板中的動態內容生成,包括物件摘要、 場景特定內容生成,以及提供默認的替換字典。 """ def __init__(self): """初始化內容生成器""" self.logger = logging.getLogger(self.__class__.__name__) # 預載入默認替換內容 self.default_replacements = self._generate_default_replacements() self.logger.debug("ContentGenerator initialized successfully") def _generate_default_replacements(self) -> Dict[str, str]: """ 生成默認的模板替換內容 Returns: Dict[str, str]: 默認替換內容字典 """ return { # 場景介紹相關 "scene_introduction": "this scene", "location_prefix": "this location", "setting_description": "this setting", "area_description": "this area", "environment_description": "this environment", "spatial_introduction": "this space", # 室內相關 "furniture": "various furniture pieces", "seating": "comfortable seating", "electronics": "entertainment devices", "bed_type": "a bed", "bed_location": "room", "bed_description": "sleeping arrangements", "extras": "personal items", "table_setup": "a dining table and chairs", "table_description": "a dining surface", "dining_items": "dining furniture and tableware", "appliances": "kitchen appliances", "kitchen_items": "cooking utensils and dishware", "cooking_equipment": "cooking equipment", "office_equipment": "work-related furniture and devices", "desk_setup": "a desk and chair", "computer_equipment": "electronic devices", # 室外/城市相關 "traffic_description": "vehicles and pedestrians", "people_and_vehicles": "people and various vehicles", "street_elements": "urban infrastructure", "park_features": "benches and greenery", "outdoor_elements": "natural features", "park_description": "outdoor amenities", "store_elements": "merchandise displays", "shopping_activity": "customers browse and shop", "store_items": "products for sale", # 高級餐廳相關 "design_elements": "elegant decor", "lighting": "stylish lighting fixtures", # 亞洲商業街相關 "storefront_features": "compact shops", "pedestrian_flow": "people walking", "asian_elements": "distinctive cultural elements", "cultural_elements": "traditional design features", "signage": "colorful signs", "street_activities": "busy urban activity", # 金融區相關 "buildings": "tall buildings", "traffic_elements": "vehicles", "skyscrapers": "high-rise buildings", "road_features": "wide streets", "architectural_elements": "modern architecture", "city_landmarks": "prominent structures", # 十字路口相關 "crossing_pattern": "clearly marked pedestrian crossings", "pedestrian_behavior": "careful pedestrian movement", "pedestrian_density": "multiple groups of pedestrians", "traffic_pattern": "well-regulated traffic flow", "pedestrian_flow": "steady pedestrian movement", "traffic_description": "active urban traffic", "people_and_vehicles": "pedestrians and vehicles", "street_elements": "urban infrastructure elements", # 交通相關 "transit_vehicles": "public transportation vehicles", "passenger_activity": "commuter movement", "transportation_modes": "various transit options", "passenger_needs": "waiting areas", "transit_infrastructure": "transit facilities", "passenger_movement": "commuter flow", # 購物區相關 "retail_elements": "shops and displays", "store_types": "various retail establishments", "walkway_features": "pedestrian pathways", "commercial_signage": "store signs", "consumer_behavior": "shopping activities", # 空中視角相關 "commercial_layout": "organized retail areas", "pedestrian_pattern": "people movement patterns", "gathering_features": "public gathering spaces", "movement_pattern": "crowd flow patterns", "urban_elements": "city infrastructure", "public_activity": "social interaction", # 文化特定元素 "stall_elements": "vendor booths", "lighting_features": "decorative lights", "food_elements": "food offerings", "vendor_stalls": "market stalls", "nighttime_activity": "evening commerce", "cultural_lighting": "traditional lighting", "night_market_sounds": "lively market sounds", "evening_crowd_behavior": "nighttime social activity", "architectural_elements": "cultural buildings", "religious_structures": "sacred buildings", "decorative_features": "ornamental designs", "cultural_practices": "traditional activities", "temple_architecture": "religious structures", "sensory_elements": "atmospheric elements", "visitor_activities": "cultural experiences", "ritual_activities": "ceremonial practices", "cultural_symbols": "meaningful symbols", "architectural_style": "historical buildings", "historic_elements": "traditional architecture", "urban_design": "city planning elements", "social_behaviors": "public interactions", "european_features": "European architectural details", "tourist_activities": "visitor activities", "local_customs": "regional practices", # 時間特定元素 "lighting_effects": "artificial lighting", "shadow_patterns": "light and shadow", "urban_features": "city elements", "illuminated_elements": "lit structures", "evening_activities": "nighttime activities", "light_sources": "lighting points", "lit_areas": "illuminated spaces", "shadowed_zones": "darker areas", "illuminated_signage": "bright signs", "colorful_lighting": "multicolored lights", "neon_elements": "neon signs", "night_crowd_behavior": "evening social patterns", "light_displays": "lighting installations", "building_features": "architectural elements", "nightlife_activities": "evening entertainment", "lighting_modifier": "bright", # 混合環境元素 "transitional_elements": "connecting features", "indoor_features": "interior elements", "outdoor_setting": "exterior spaces", "interior_amenities": "inside comforts", "exterior_features": "outside elements", "inside_elements": "interior design", "outside_spaces": "outdoor areas", "dual_environment_benefits": "combined settings", "passenger_activities": "waiting behaviors", "transportation_types": "transit vehicles", "sheltered_elements": "covered areas", "exposed_areas": "open sections", "waiting_behaviors": "passenger activities", "indoor_facilities": "inside services", "platform_features": "transit platform elements", "transit_routines": "transportation procedures", # 專門場所元素 "seating_arrangement": "spectator seating", "playing_surface": "athletic field", "sporting_activities": "sports events", "spectator_facilities": "viewer accommodations", "competition_space": "sports arena", "sports_events": "athletic competitions", "viewing_areas": "audience sections", "field_elements": "field markings and equipment", "game_activities": "competitive play", "construction_equipment": "building machinery", "building_materials": "construction supplies", "construction_activities": "building work", "work_elements": "construction tools", "structural_components": "building structures", "site_equipment": "construction gear", "raw_materials": "building supplies", "construction_process": "building phases", "medical_elements": "healthcare equipment", "clinical_activities": "medical procedures", "facility_design": "healthcare layout", "healthcare_features": "medical facilities", "patient_interactions": "care activities", "equipment_types": "medical devices", "care_procedures": "health services", "treatment_spaces": "clinical areas", "educational_furniture": "learning furniture", "learning_activities": "educational practices", "instructional_design": "teaching layout", "classroom_elements": "school equipment", "teaching_methods": "educational approaches", "student_engagement": "learning participation", "learning_spaces": "educational areas", "educational_tools": "teaching resources", "knowledge_transfer": "learning exchanges" } def generate_objects_summary(self, detected_objects: List[Dict]) -> str: """ 基於檢測物件生成自然語言摘要,按重要性排序 Args: detected_objects: 檢測到的物件列表 Returns: str: 物件摘要描述 """ try: # detected_objects 裡有幾個 traffic light) tl_count = len([obj for obj in detected_objects if obj.get("class_name","") == "traffic light"]) # print(f"[DEBUG] _generate_objects_summary 傳入的 detected_objects 中 traffic light: {tl_count} 個") for obj in detected_objects: if obj.get("class_name","") == "traffic light": print(f" - conf={obj.get('confidence',0):.4f}, bbox={obj.get('bbox')}, region={obj.get('region')}") if not detected_objects: return "various elements" # 計算物件統計 object_counts = {} total_confidence = 0 for obj in detected_objects: class_name = obj.get("class_name", "unknown") confidence = obj.get("confidence", 0.5) if class_name not in object_counts: object_counts[class_name] = {"count": 0, "total_confidence": 0} object_counts[class_name]["count"] += 1 object_counts[class_name]["total_confidence"] += confidence total_confidence += confidence # 計算平均置信度並排序 sorted_objects = [] for class_name, stats in object_counts.items(): avg_confidence = stats["total_confidence"] / stats["count"] count = stats["count"] # 重要性評分:結合數量和置信度 importance_score = (count * 0.6) + (avg_confidence * 0.4) sorted_objects.append((class_name, count, importance_score)) # 按重要性排序,取前5個最重要的物件 sorted_objects.sort(key=lambda x: x[2], reverse=True) top_objects = sorted_objects[:5] # 生成自然語言描述 descriptions = [] for class_name, count, _ in top_objects: clean_name = class_name.replace('_', ' ') if count == 1: article = "an" if clean_name[0].lower() in 'aeiou' else "a" descriptions.append(f"{article} {clean_name}") else: descriptions.append(f"{count} {clean_name}s") # 組合描述 if len(descriptions) == 1: return descriptions[0] elif len(descriptions) == 2: return f"{descriptions[0]} and {descriptions[1]}" else: return ", ".join(descriptions[:-1]) + f", and {descriptions[-1]}" except Exception as e: self.logger.warning(f"Error generating objects summary: {str(e)}") return "various elements" def get_placeholder_replacement(self, placeholder: str, fillers: Dict, all_replacements: Dict, detected_objects: List[Dict], scene_type: str) -> str: """ 獲取特定佔位符的替換內容,確保永遠不返回空值 Args: placeholder: 佔位符名稱 fillers: 模板填充器字典 all_replacements: 所有替換內容字典 detected_objects: 檢測到的物體列表 scene_type: 場景類型 Returns: str: 替換內容 """ try: # 優先處理動態內容生成的佔位符 dynamic_placeholders = [ 'primary_objects', 'detected_objects_summary', 'main_objects', 'functional_area', 'functional_zones_description', 'scene_elements' ] if placeholder in dynamic_placeholders: dynamic_content = self.generate_objects_summary(detected_objects) if dynamic_content and dynamic_content.strip(): return dynamic_content.strip() # 檢查預定義替換內容 if placeholder in all_replacements: replacement = all_replacements[placeholder] if replacement and replacement.strip(): return replacement.strip() # 檢查物體模板填充器 if placeholder in fillers: options = fillers[placeholder] if options and isinstance(options, list): valid_options = [opt.strip() for opt in options if opt and str(opt).strip()] if valid_options: num_items = min(len(valid_options), random.randint(1, 3)) selected_items = random.sample(valid_options, num_items) if len(selected_items) == 1: return selected_items[0] elif len(selected_items) == 2: return f"{selected_items[0]} and {selected_items[1]}" else: return ", ".join(selected_items[:-1]) + f", and {selected_items[-1]}" # 基於檢測對象生成動態內容 scene_specific_replacement = self.generate_scene_specific_content( placeholder, detected_objects, scene_type ) if scene_specific_replacement and scene_specific_replacement.strip(): return scene_specific_replacement.strip() # 通用備用字典 fallback_replacements = { # 交通和城市相關 "crossing_pattern": "pedestrian crosswalks", "pedestrian_behavior": "people moving carefully", "traffic_pattern": "vehicle movement", "urban_elements": "city infrastructure", "street_elements": "urban features", "intersection_features": "traffic management systems", "pedestrian_density": "groups of people", "pedestrian_flow": "pedestrian movement", "traffic_description": "vehicle traffic", "people_and_vehicles": "pedestrians and cars", # 場景設置相關 "scene_setting": "this urban environment", "location_context": "the area", "spatial_context": "the scene", "environmental_context": "this location", # 常見的家具和設備 "furniture": "various furniture pieces", "seating": "seating arrangements", "electronics": "electronic devices", "appliances": "household appliances", # 活動和行為 "activities": "various activities", "interactions": "people interacting", "movement": "movement patterns", # 照明和氛圍 "lighting_conditions": "ambient lighting", "atmosphere": "the overall atmosphere", "ambiance": "environmental ambiance", # 空間描述 "spatial_arrangement": "spatial organization", "layout": "the layout", "composition": "visual composition", # 物體和元素 "objects": "various objects", "elements": "scene elements", "features": "notable features", "details": "observable details" } if placeholder in fallback_replacements: return fallback_replacements[placeholder] # 基於場景類型的智能默認值 scene_based_defaults = self.get_scene_based_default(placeholder, scene_type) if scene_based_defaults: return scene_based_defaults # 最終備用:將下劃線轉換為有意義的短語 cleaned_placeholder = placeholder.replace('_', ' ') # 對常見模式提供更好的默認值 if placeholder.endswith('_pattern'): return f"{cleaned_placeholder.replace(' pattern', '')} arrangement" elif placeholder.endswith('_behavior'): return f"{cleaned_placeholder.replace(' behavior', '')} activity" elif placeholder.endswith('_description'): return f"{cleaned_placeholder.replace(' description', '')} elements" elif placeholder.endswith('_elements'): return cleaned_placeholder elif placeholder.endswith('_features'): return cleaned_placeholder else: return cleaned_placeholder if cleaned_placeholder != placeholder else "various elements" except Exception as e: self.logger.warning(f"Error getting replacement for placeholder '{placeholder}': {str(e)}") # 確保即使在異常情況下也返回有意義的內容 return placeholder.replace('_', ' ') if placeholder else "scene elements" def get_scene_based_default(self, placeholder: str, scene_type: str) -> Optional[str]: """ 基於場景類型提供智能默認值 Args: placeholder: 佔位符名稱 scene_type: 場景類型 Returns: Optional[str]: 場景特定的默認值或None """ try: # 針對不同場景類型的特定默認值 scene_defaults = { "urban_intersection": { "crossing_pattern": "marked crosswalks", "pedestrian_behavior": "pedestrians crossing carefully", "traffic_pattern": "controlled traffic flow" }, "city_street": { "traffic_description": "urban vehicle traffic", "street_elements": "city infrastructure", "people_and_vehicles": "pedestrians and vehicles" }, "living_room": { "furniture": "comfortable living room furniture", "seating": "sofas and chairs", "electronics": "entertainment equipment" }, "kitchen": { "appliances": "kitchen appliances", "cooking_equipment": "cooking tools and equipment" }, "office_workspace": { "office_equipment": "work furniture and devices", "desk_setup": "desk and office chair" } } if scene_type in scene_defaults and placeholder in scene_defaults[scene_type]: return scene_defaults[scene_type][placeholder] return None except Exception as e: self.logger.warning(f"Error getting scene-based default for '{placeholder}' in '{scene_type}': {str(e)}") return None def generate_scene_specific_content(self, placeholder: str, detected_objects: List[Dict], scene_type: str) -> Optional[str]: """ 基於場景特定邏輯生成佔位符內容 Args: placeholder: 佔位符名稱 detected_objects: 檢測到的物體列表 scene_type: 場景類型 Returns: Optional[str]: 生成的內容或None """ try: if placeholder == "furniture": # 提取家具物品 furniture_ids = [56, 57, 58, 59, 60, 61] # 家具類別ID furniture_objects = [obj for obj in detected_objects if obj.get("class_id") in furniture_ids] if furniture_objects: furniture_names = [obj.get("class_name", "furniture") for obj in furniture_objects[:3]] unique_names = list(set(furniture_names)) return ", ".join(unique_names) if len(unique_names) > 1 else unique_names[0] return "various furniture items" elif placeholder == "electronics": # 提取電子設備 electronics_ids = [62, 63, 64, 65, 66, 67, 68, 69, 70] # 電子設備類別ID electronics_objects = [obj for obj in detected_objects if obj.get("class_id") in electronics_ids] if electronics_objects: electronics_names = [obj.get("class_name", "electronic device") for obj in electronics_objects[:3]] unique_names = list(set(electronics_names)) return ", ".join(unique_names) if len(unique_names) > 1 else unique_names[0] return "electronic devices" elif placeholder == "people_count": # 計算人數 people_count = len([obj for obj in detected_objects if obj.get("class_id") == 0]) if people_count == 0: return "no people" elif people_count == 1: return "one person" elif people_count < 5: return f"{people_count} people" else: return "several people" elif placeholder == "seating": # 提取座位物品 seating_ids = [56, 57] # chair, sofa seating_objects = [obj for obj in detected_objects if obj.get("class_id") in seating_ids] if seating_objects: seating_names = [obj.get("class_name", "seating") for obj in seating_objects[:2]] unique_names = list(set(seating_names)) return ", ".join(unique_names) if len(unique_names) > 1 else unique_names[0] return "seating arrangements" # 如果沒有匹配的特定邏輯,返回None return None except Exception as e: self.logger.warning(f"Error generating scene-specific content for '{placeholder}': {str(e)}") return None def get_emergency_replacement(self, placeholder: str) -> str: """ 獲取緊急替換值,確保不會產生語法錯誤 Args: placeholder: 佔位符名稱 Returns: str: 安全的替換值 """ emergency_replacements = { "crossing_pattern": "pedestrian walkways", "pedestrian_behavior": "people moving through the area", "traffic_pattern": "vehicle movement", "scene_setting": "this location", "urban_elements": "city features", "street_elements": "urban components" } if placeholder in emergency_replacements: return emergency_replacements[placeholder] # 基於佔位符名稱生成合理的替換 cleaned = placeholder.replace('_', ' ') if len(cleaned.split()) > 1: return cleaned else: return f"various {cleaned}"