File size: 25,263 Bytes
12d9ea9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
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}"