-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathc_main.py
More file actions
147 lines (112 loc) · 4.42 KB
/
Copy pathc_main.py
File metadata and controls
147 lines (112 loc) · 4.42 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
import threading
import time
from audio import listen, speak
from conversation import handle_user_message
from eyes import capture_image
import wakeUp
CONVERSATION_IMAGE_FILE = "conversation_vision.jpg"
CONVERSATION_IMAGE_TIMEOUT = 5.0
SLEEP_COMMANDS = {
"sleep",
"go to sleep",
"sleep mode",
"shutdown",
"shut down",
"power down",
"standby",
"stand by",
"go back to sleep",
}
def is_sleep_command(message: str) -> bool:
"""Return True when the user wants the robot to go back to sleep mode."""
normalized = message.strip().lower()
return any(command in normalized for command in SLEEP_COMMANDS)
def run_wake_mode() -> str:
"""Start the wake-up pipelines and wait until one of them wakes the robot."""
print("[INFO] Entering wake mode.")
wakeUp.awakened_event.clear()
wakeUp.last_wake_reason = ""
visual_rules = wakeUp.load_rules(wakeUp.VISUAL_RULES_FILE)
time_rules = wakeUp.load_rules(wakeUp.REMAINDER_FILE)
audio_thread = threading.Thread(
target=wakeUp.audio_pipeline,
args=(False,),
daemon=True,
)
visual_thread = threading.Thread(
target=wakeUp.visual_pipeline,
args=(visual_rules, time_rules, False),
daemon=True,
)
audio_thread.start()
visual_thread.start()
try:
while not wakeUp.awakened_event.is_set():
time.sleep(0.5)
finally:
audio_thread.join(timeout=1.0)
visual_thread.join(timeout=1.0)
return wakeUp.last_wake_reason
def listen_with_environment_capture() -> tuple[str, str | None]:
"""Listen to the user while capturing a fresh camera frame in parallel."""
image_result: dict[str, str | None] = {"path": None}
def capture_environment() -> None:
try:
image_result["path"] = capture_image(CONVERSATION_IMAGE_FILE)
except Exception as error:
print(f"[WARN] Conversation photo capture failed: {error}")
photo_thread = threading.Thread(
target=capture_environment,
name="conversation-photo-capture",
daemon=True,
)
print("[INFO] Capturing environment photo while listening.")
photo_thread.start()
user_message = listen()
photo_thread.join(timeout=CONVERSATION_IMAGE_TIMEOUT)
if photo_thread.is_alive():
print("[WARN] Photo capture is still running; sending this message without an image.")
return user_message, None
if image_result["path"]:
print(f"[INFO] Conversation photo ready: {image_result['path']}")
else:
print("[WARN] No conversation photo captured for this turn.")
return user_message, image_result["path"]
def run_conversation_mode(wake_reason: str = "") -> None:
"""Handle the post-wake voice conversation until the user sends the robot back to sleep."""
print("[INFO] Entering conversation mode.")
if wake_reason:
wake_message = wakeUp.format_wake_speech(wake_reason)
speak(f"Robot awake. {wake_message}. Conversation mode started. I am listening.")
else:
speak("Conversation mode started. I am listening.")
while True:
user_message, image_path = listen_with_environment_capture()
if user_message == "none":
continue
print(f"User: {user_message}")
if is_sleep_command(user_message):
print("[INFO] Sleep command detected. Returning to wake mode.")
speak("Going back to sleep mode.")
return
result = handle_user_message(user_message, speak_reply=True, image_path=image_path)
print(f"Assistant: {result['reply']}")
if result["image_attached"]:
print(f"[INFO] Sent visual context to LLM: {result['image_path']}")
if result["due_reminders"]:
print(f"[INFO] Due reminder at {result['current_image_time']}: {result['due_reminders']}")
if result["file_updated"]:
print(f"[INFO] Updated {result['target_file']} using {result['file_action']}.")
if result["memory_updated"]:
print(f"[INFO] Updated memory.txt using {result['memory_action']}.")
def main() -> None:
"""Run the robot in an endless cycle of wake mode and conversation mode."""
print("[INFO] Starting c_main controller.")
while True:
wake_reason = run_wake_mode()
run_conversation_mode(wake_reason)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n[INFO] Shutdown requested.")