Repository navigation
Expand file tree
/
Copy pathprompt_engineer.py
More file actions
151 lines (117 loc) · 5.64 KB
/
Copy pathprompt_engineer.py
File metadata and controls
151 lines (117 loc) · 5.64 KB
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
"""
Prompt Engineering Module for Construction Safety AI.
Converts YOLOv11n detection results into structured prompts for sVLM conditioning.
Stage 2: Prompt Engineering Module - detected entities embedded into structured prompts for sVLM reasoning.
"""
from typing import Optional
from config import BASELINE_PROMPT, DETECTION_GUIDED_PROMPT, HAZARD_CATEGORIES
from detector import DetectionResult
class PromptEngineer:
"""
Constructs structured prompts for small VLM inference.
Implements the prompt engineering module from the paper:
- Detection-to-Text Encoding: converts YOLOv11n detections to natural language
- Structured Prompt Construction: embeds detection context into VLM prompts
- Supports baseline (no detection context) and detection-guided modes
"""
def build_prompt(
self,
detection_result: Optional[DetectionResult] = None,
mode: str = "detection_guided",
custom_context: Optional[str] = None,
) -> str:
"""
Build a structured prompt for the sVLM based on detection results.
Args:
detection_result: Detection results from YOLOv11n (None for baseline mode)
mode: Prompt mode - "baseline" or "detection_guided"
custom_context: Optional additional context to include
Returns:
Structured prompt string for VLM inference
"""
if mode == "baseline" or detection_result is None:
prompt = BASELINE_PROMPT
if custom_context:
prompt = prompt + "\n\nAdditional context:\n" + custom_context
return prompt
elif mode == "detection_guided":
detection_summary = detection_result.detection_summary_text
spatial_summary = detection_result.spatial_relations_text
# If no detections were found, fall back to baseline with a note
if not detection_result.detections:
prompt = BASELINE_PROMPT
prompt += "\n\nNote: No specific objects were detected by the object detection model. Please analyze the image directly for any safety hazards."
return prompt
prompt = DETECTION_GUIDED_PROMPT.format(
detection_summary=detection_summary,
spatial_relations_summary=spatial_summary,
)
if custom_context:
prompt = prompt + "\n\nAdditional context:\n" + custom_context
return prompt
else:
raise ValueError(f"Unknown prompt mode: {mode}. Use 'baseline' or 'detection_guided'.")
def build_hazard_focus_prompt(
self,
detection_result: DetectionResult,
focus_categories: list[str] = None,
) -> str:
"""
Build a prompt that focuses on specific hazard categories.
Useful when the user wants to focus analysis on particular hazard types
based on the detection results.
Args:
detection_result: Detection results from YOLOv11n
focus_categories: List of hazard category keys to focus on
Returns:
Focused prompt string for VLM inference
"""
detection_summary = detection_result.detection_summary_text
spatial_summary = detection_result.spatial_relations_text
# Build category focus section
if focus_categories:
focus_text = "Focus specifically on these hazard types:\n"
for cat_key in focus_categories:
if cat_key in HAZARD_CATEGORIES:
cat = HAZARD_CATEGORIES[cat_key]
focus_text += f"- {cat['label']}: {cat['description']}\n"
else:
focus_text = ""
prompt = f"""You are a construction safety expert. Analyze this construction site image for safety hazards.
Detected objects in the scene:
{detection_summary}
Spatial relationships:
{spatial_summary}
{focus_text}
Based on the detected objects and their spatial arrangement, identify any safety hazards present in this image.
For each hazard you identify, provide:
1. Hazard type (fall from height, struck-by, caught-in/between, electrical, excavation/trenching, PPE non-compliance, unsafe worker-machinery proximity)
2. Severity level (low, medium, high, critical)
3. Description of the hazardous situation
4. Recommended corrective action
If no hazards of the specified types are present, respond with "No relevant hazards detected."
Format your response as a structured list."""
return prompt
def build_comparison_prompts(
self,
detection_result: DetectionResult,
) -> dict[str, str]:
"""
Build both baseline and detection-guided prompts for comparison analysis.
Returns a dictionary with both prompts so the user can compare
VLM outputs with and without detection context.
Args:
detection_result: Detection results from YOLOv11n
Returns:
Dictionary with "baseline" and "detection_guided" prompt keys
"""
return {
"baseline": self.build_prompt(detection_result, mode="baseline"),
"detection_guided": self.build_prompt(detection_result, mode="detection_guided"),
}
def get_hazard_category_list(self) -> str:
"""Get a formatted list of all hazard categories for display."""
lines = []
for key, cat in HAZARD_CATEGORIES.items():
lines.append(f"- **{cat['label']}**: {cat['description']} (default severity: {cat['severity_default']})")
return "\n".join(lines)