Files
Kevin 4c3f9a367b feat(voice-client): PySide6 desktop client and Windows build scripts
Add voice_confirmation_client (poll, TTS MP3 playback, mic WAV resolve),
PyInstaller spec, start/build helpers, and API unit tests.

Pending manual testing: end-to-end on OR workstations and packaged exe.

Made-with: Cursor
2026-04-27 09:52:10 +08:00

62 lines
1.6 KiB
Python

"""Play MP3 bytes via system player or bundled ffplay."""
from __future__ import annotations
import base64
import os
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
from voice_confirmation_client.core.paths import find_ffplay
def play_mp3_from_base64(b64: str) -> None:
raw_b64 = "".join((b64 or "").split())
if not raw_b64:
raise ValueError("empty prompt_audio_mp3_base64")
data = base64.b64decode(raw_b64, validate=False)
with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as f:
f.write(data)
tmp = f.name
try:
_play_mp3_path(Path(tmp))
finally:
try:
os.unlink(tmp)
except OSError:
pass
def _play_mp3_path(path: Path) -> None:
bundled = find_ffplay()
if bundled and bundled.is_file():
subprocess.run(
[str(bundled), "-nodisp", "-autoexit", "-loglevel", "quiet", str(path)],
check=True,
timeout=600,
)
return
ffplay = shutil.which("ffplay")
if ffplay:
subprocess.run(
[ffplay, "-nodisp", "-autoexit", "-loglevel", "quiet", str(path)],
check=True,
timeout=600,
)
return
if sys.platform == "darwin":
subprocess.run(["afplay", str(path)], check=True, timeout=600)
return
if os.name == "nt":
os.startfile(str(path)) # type: ignore[attr-defined]
import time
time.sleep(5)
return
raise RuntimeError(
"No MP3 player found. Install ffmpeg (ffplay) or run on macOS with afplay."
)