Update 2026-04-22 11:43:20
This commit is contained in:
parent
2e3cc1ba5b
commit
3122a52966
@ -47,10 +47,10 @@ from Core.config_loader import load_config
|
|||||||
LOG_DIR = os.path.join(PROJECT_ROOT, "logs")
|
LOG_DIR = os.path.join(PROJECT_ROOT, "logs")
|
||||||
os.makedirs(LOG_DIR, exist_ok=True)
|
os.makedirs(LOG_DIR, exist_ok=True)
|
||||||
|
|
||||||
# logging.basicConfig is idempotent per process: if marcus_voice configured
|
# All voice-subsystem logs go ONLY to logs/voice.log, not stdout — the
|
||||||
# the root logger first, this call is a no-op and both modules share the same
|
# terminal REPL needs a clean `Command:` prompt. Anything the operator
|
||||||
# RotatingFileHandler (stdlib FileHandlers hold an internal lock, so concurrent
|
# needs to see is print()-ed explicitly from the callback sites.
|
||||||
# writes to voice.log are safe). Rotation caps voice.log at 5 MB × 3 backups.
|
# basicConfig is idempotent (no-op if marcus_voice installed handlers first).
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
|
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
|
||||||
@ -59,7 +59,6 @@ logging.basicConfig(
|
|||||||
os.path.join(LOG_DIR, "voice.log"),
|
os.path.join(LOG_DIR, "voice.log"),
|
||||||
maxBytes=5_000_000, backupCount=3, encoding="utf-8",
|
maxBytes=5_000_000, backupCount=3, encoding="utf-8",
|
||||||
),
|
),
|
||||||
logging.StreamHandler(),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
log = logging.getLogger("audio_api")
|
log = logging.getLogger("audio_api")
|
||||||
|
|||||||
@ -172,7 +172,10 @@ def _init_voice():
|
|||||||
text = (text or "").strip()
|
text = (text or "").strip()
|
||||||
if not text:
|
if not text:
|
||||||
return
|
return
|
||||||
print(f" [Voice] {text}")
|
# One clean, distinctive line so the operator can see exactly
|
||||||
|
# what Whisper transcribed before the brain reacts. Everything
|
||||||
|
# else from the voice subsystem is file-only.
|
||||||
|
print(f' [Sanad] heard: "{text}"')
|
||||||
try:
|
try:
|
||||||
result = process_command(text)
|
result = process_command(text)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -182,10 +185,12 @@ def _init_voice():
|
|||||||
sp = (result.get("speak") or "").strip()
|
sp = (result.get("speak") or "").strip()
|
||||||
if sp and _audio_api:
|
if sp and _audio_api:
|
||||||
_audio_api.speak(sp)
|
_audio_api.speak(sp)
|
||||||
|
# Redraw the Command: prompt that our print clobbered
|
||||||
|
print("Command: ", end="", flush=True)
|
||||||
|
|
||||||
_voice_module = VoiceModule(_audio_api, on_command=_on_command)
|
_voice_module = VoiceModule(_audio_api, on_command=_on_command)
|
||||||
_voice_module.start()
|
_voice_module.start()
|
||||||
print(" [Voice] Always listening (Whisper + G1 mic + TtsMaker)")
|
print(" [Voice] listening in background — say \"Sanad\" + your command")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" [Voice] Init failed: {e} — continuing without voice")
|
print(f" [Voice] Init failed: {e} — continuing without voice")
|
||||||
_audio_api = None
|
_audio_api = None
|
||||||
@ -477,13 +482,15 @@ def run_terminal():
|
|||||||
|
|
||||||
status = get_brain_status()
|
status = get_brain_status()
|
||||||
print()
|
print()
|
||||||
print("=" * 48)
|
print("=" * 54)
|
||||||
print(" SANAD AI BRAIN — READY")
|
print(" SANAD AI BRAIN — READY")
|
||||||
print("=" * 48)
|
print("=" * 54)
|
||||||
for k, v in status.items():
|
for k, v in status.items():
|
||||||
print(f" {k:<10}: {v}")
|
print(f" {k:<12}: {v}")
|
||||||
print("=" * 48)
|
print("-" * 54)
|
||||||
print(" help | example | yolo | patrol | auto on/off | q")
|
print(" Type a command, or say \"Sanad, <command>\".")
|
||||||
|
print(" Shortcuts: help | example | yolo | patrol | auto on/off | q")
|
||||||
|
print("=" * 54)
|
||||||
print()
|
print()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -40,9 +40,11 @@ from Core.config_loader import load_config
|
|||||||
LOG_DIR = os.path.join(PROJECT_ROOT, "logs")
|
LOG_DIR = os.path.join(PROJECT_ROOT, "logs")
|
||||||
os.makedirs(LOG_DIR, exist_ok=True)
|
os.makedirs(LOG_DIR, exist_ok=True)
|
||||||
|
|
||||||
# basicConfig is idempotent. Whichever of audio_api / marcus_voice imports
|
# Voice runs as a background subsystem — its INFO/DEBUG logs go ONLY to
|
||||||
# first installs the rotating handler; the other no-ops. Both loggers then
|
# logs/voice.log so they don't drown out the interactive `Command:` prompt.
|
||||||
# share the same file handle with stdlib's per-handler thread lock.
|
# Anything the user needs to see (wake-word fired, command heard) is
|
||||||
|
# print()-ed explicitly from the callbacks below.
|
||||||
|
# basicConfig is idempotent; audio_api may have already called it.
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
|
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
|
||||||
@ -51,7 +53,6 @@ logging.basicConfig(
|
|||||||
os.path.join(LOG_DIR, "voice.log"),
|
os.path.join(LOG_DIR, "voice.log"),
|
||||||
maxBytes=5_000_000, backupCount=3, encoding="utf-8",
|
maxBytes=5_000_000, backupCount=3, encoding="utf-8",
|
||||||
),
|
),
|
||||||
logging.StreamHandler(),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
log = logging.getLogger("marcus_voice")
|
log = logging.getLogger("marcus_voice")
|
||||||
@ -248,6 +249,11 @@ class VoiceModule:
|
|||||||
|
|
||||||
if self._check_wake_word(text):
|
if self._check_wake_word(text):
|
||||||
log.info("Wake word detected!")
|
log.info("Wake word detected!")
|
||||||
|
# One clean line to the terminal so the operator knows voice
|
||||||
|
# actually heard them, even though all other voice logs are
|
||||||
|
# file-only. \n leads because we may be painting over a
|
||||||
|
# half-drawn `Command:` prompt.
|
||||||
|
print("\n [Sanad] wake heard — recording command…")
|
||||||
self._state = State.WAKE_HEARD
|
self._state = State.WAKE_HEARD
|
||||||
|
|
||||||
# Acknowledge
|
# Acknowledge
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user