Spaces:
Running on Zero
Running on Zero
File size: 3,868 Bytes
cb6be11 | 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 | """
IRIS - Priority / Context Engine
Takes YOLO detections + optional VLM reasoning output and selects
EXACTLY ONE instruction to speak. Never a list β always the single
most relevant thing for the visually impaired user right now.
Priority order:
1. VLM reasoning output (context-aware, if available)
2. Urgent object blocking center path (person, car, etc.)
3. Caution object in center (chair, bench, stairs, etc.)
4. Closest high-conf object on left or right
5. General scene clear message
"""
class PriorityEngine:
"""
Selects exactly one navigation instruction from structured detections
and optional VLM context reasoning.
"""
# Objects that trigger immediate caution warnings
URGENT = {
"person", "car", "truck", "bus", "motorcycle", "bicycle",
"dog", "cat", "horse", "traffic light", "stop sign",
}
# Objects that need caution but are less mobile
CAUTION = {
"chair", "bench", "dining table", "potted plant", "suitcase",
"backpack", "umbrella", "fire hydrant", "parking meter",
"stairs", "step", "pole", "bollard",
}
# Position β spoken phrase
POS_PHRASE = {
"left": "on your left",
"center": "directly ahead",
"right": "on your right",
}
def pick(self, detections: list, vlm_text: str = "") -> str:
"""
Return exactly ONE instruction string.
Args:
detections: sorted YOLO detections (highest confidence first)
vlm_text: reasoning from VLM engine (empty string if unavailable)
Returns:
A single short instruction for TTS.
"""
# ββ 1. VLM reasoning takes highest priority (context-aware) ββββββββββ
if vlm_text and len(vlm_text.strip()) > 5:
return self._clean(vlm_text)
if not detections:
return "Path ahead looks clear."
# ββ 2. Urgent object directly ahead ββββββββββββββββββββββββββββββββββ
center_urgent = [
d for d in detections
if d["position"] == "center" and d["object"] in self.URGENT
]
if center_urgent:
obj = center_urgent[0]["object"]
return f"Caution! {obj.capitalize()} directly ahead."
# ββ 3. Any object blocking center ββββββββββββββββββββββββββββββββββββ
center_any = [d for d in detections if d["position"] == "center"]
if center_any:
obj = center_any[0]["object"]
if obj in self.CAUTION:
return f"Watch out β {obj} ahead. Step around it."
return f"{obj.capitalize()} ahead. Proceed carefully."
# ββ 4. Urgent object on sides ββββββββββββββββββββββββββββββββββββββββ
side_urgent = [
d for d in detections
if d["position"] in ("left", "right") and d["object"] in self.URGENT
]
if side_urgent:
d = side_urgent[0]
pos = self.POS_PHRASE.get(d["position"], d["position"])
return f"{d['object'].capitalize()} {pos}. Stay aware."
# ββ 5. Highest confidence detection anywhere ββββββββββββββββββββββββββ
top = detections[0]
pos = self.POS_PHRASE.get(top["position"], top["position"])
return f"{top['object'].capitalize()} {pos}."
@staticmethod
def _clean(text: str) -> str:
"""Ensure sentence ends with a period and is clean."""
text = text.strip()
if text and not text.endswith((".", "!", "?")):
text += "."
return text
|