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")
|
||||
os.makedirs(LOG_DIR, exist_ok=True)
|
||||
|
||||
# logging.basicConfig is idempotent per process: if marcus_voice configured
|
||||
# the root logger first, this call is a no-op and both modules share the same
|
||||
# RotatingFileHandler (stdlib FileHandlers hold an internal lock, so concurrent
|
||||
# writes to voice.log are safe). Rotation caps voice.log at 5 MB × 3 backups.
|
||||
# All voice-subsystem logs go ONLY to logs/voice.log, not stdout — the
|
||||
# terminal REPL needs a clean `Command:` prompt. Anything the operator
|
||||
# needs to see is print()-ed explicitly from the callback sites.
|
||||
# basicConfig is idempotent (no-op if marcus_voice installed handlers first).
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
|
||||
@ -59,7 +59,6 @@ logging.basicConfig(
|
||||
os.path.join(LOG_DIR, "voice.log"),
|
||||
maxBytes=5_000_000, backupCount=3, encoding="utf-8",
|
||||
),
|
||||
logging.StreamHandler(),
|
||||
],
|
||||
)
|
||||
log = logging.getLogger("audio_api")
|
||||
|
||||
@ -172,7 +172,10 @@ def _init_voice():
|
||||
text = (text or "").strip()
|
||||
if not text:
|
||||
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:
|
||||
result = process_command(text)
|
||||
except Exception as e:
|
||||
@ -182,10 +185,12 @@ def _init_voice():
|
||||
sp = (result.get("speak") or "").strip()
|
||||
if sp and _audio_api:
|
||||
_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.start()
|
||||
print(" [Voice] Always listening (Whisper + G1 mic + TtsMaker)")
|
||||
print(" [Voice] listening in background — say \"Sanad\" + your command")
|
||||
except Exception as e:
|
||||
print(f" [Voice] Init failed: {e} — continuing without voice")
|
||||
_audio_api = None
|
||||
@ -477,13 +482,15 @@ def run_terminal():
|
||||
|
||||
status = get_brain_status()
|
||||
print()
|
||||
print("=" * 48)
|
||||
print(" SANAD AI BRAIN — READY")
|
||||
print("=" * 48)
|
||||
print("=" * 54)
|
||||
print(" SANAD AI BRAIN — READY")
|
||||
print("=" * 54)
|
||||
for k, v in status.items():
|
||||
print(f" {k:<10}: {v}")
|
||||
print("=" * 48)
|
||||
print(" help | example | yolo | patrol | auto on/off | q")
|
||||
print(f" {k:<12}: {v}")
|
||||
print("-" * 54)
|
||||
print(" Type a command, or say \"Sanad, <command>\".")
|
||||
print(" Shortcuts: help | example | yolo | patrol | auto on/off | q")
|
||||
print("=" * 54)
|
||||
print()
|
||||
|
||||
try:
|
||||
|
||||
@ -40,9 +40,11 @@ from Core.config_loader import load_config
|
||||
LOG_DIR = os.path.join(PROJECT_ROOT, "logs")
|
||||
os.makedirs(LOG_DIR, exist_ok=True)
|
||||
|
||||
# basicConfig is idempotent. Whichever of audio_api / marcus_voice imports
|
||||
# first installs the rotating handler; the other no-ops. Both loggers then
|
||||
# share the same file handle with stdlib's per-handler thread lock.
|
||||
# Voice runs as a background subsystem — its INFO/DEBUG logs go ONLY to
|
||||
# logs/voice.log so they don't drown out the interactive `Command:` prompt.
|
||||
# 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(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
|
||||
@ -51,7 +53,6 @@ logging.basicConfig(
|
||||
os.path.join(LOG_DIR, "voice.log"),
|
||||
maxBytes=5_000_000, backupCount=3, encoding="utf-8",
|
||||
),
|
||||
logging.StreamHandler(),
|
||||
],
|
||||
)
|
||||
log = logging.getLogger("marcus_voice")
|
||||
@ -248,6 +249,11 @@ class VoiceModule:
|
||||
|
||||
if self._check_wake_word(text):
|
||||
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
|
||||
|
||||
# Acknowledge
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user