VisionScout / content_generator.py
DawnC's picture
Upload 14 files
12d9ea9 verified
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}"