Mic software gain, VAD threshold 0.5, speech event logging, greeting on connect
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LzKpYaEsuWDevuNnvSjcFW
This commit is contained in:
@@ -73,10 +73,11 @@ class Assistant:
|
||||
def __init__(self, cfg: Config) -> None:
|
||||
self.cfg = cfg
|
||||
self.client = AsyncOpenAI(api_key=cfg.openai_api_key)
|
||||
self.mic = Mic(cfg.mic_device)
|
||||
self.mic = Mic(cfg.mic_device, cfg.mic_gain)
|
||||
self.speaker = Speaker(cfg.speaker_device)
|
||||
self.conn = None
|
||||
self.jobs: set[asyncio.Task] = set()
|
||||
self.greeted = False
|
||||
|
||||
# ---------- alati ----------
|
||||
async def tool_wikipedia(self, args: dict) -> str:
|
||||
@@ -203,12 +204,21 @@ class Assistant:
|
||||
if item.get("type") == "function_call":
|
||||
await self.handle_function_call(item)
|
||||
elif t == "input_audio_buffer.speech_started":
|
||||
log.info("govor počeo")
|
||||
if self.speaker.is_playing(0.0):
|
||||
await self.speaker.clear()
|
||||
elif t == "input_audio_buffer.speech_stopped":
|
||||
log.info("govor stao")
|
||||
elif t == "error":
|
||||
log.error("realtime greška: %s", event.error)
|
||||
elif t in ("session.created", "session.updated"):
|
||||
elif t == "session.created":
|
||||
log.info("sesija: %s", t)
|
||||
elif t == "session.updated":
|
||||
log.info("sesija: %s", t)
|
||||
if not self.greeted:
|
||||
self.greeted = True
|
||||
await self.conn.send({"type": "response.create", "response": {
|
||||
"instructions": "Kratko se predstavi na bosanskom u jednoj ili dvije rečenice: ti si Idriz, i reci da možeš odštampati sažetak o nekoj temi ili bojanku."}})
|
||||
|
||||
async def session(self) -> None:
|
||||
async with self.client.realtime.connect(model=self.cfg.realtime_model) as conn:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Mikrofon i zvučnik preko PipeWire-a (pacat), PCM16 mono 24 kHz kako traži Realtime API."""
|
||||
import array
|
||||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
@@ -17,9 +18,20 @@ def _pacat_args(mode: str, device: str) -> list[str]:
|
||||
return args
|
||||
|
||||
|
||||
def apply_gain(pcm: bytes, gain: float) -> bytes:
|
||||
if gain == 1.0:
|
||||
return pcm
|
||||
samples = array.array("h", pcm)
|
||||
for i, v in enumerate(samples):
|
||||
x = int(v * gain)
|
||||
samples[i] = 32767 if x > 32767 else (-32768 if x < -32768 else x)
|
||||
return samples.tobytes()
|
||||
|
||||
|
||||
class Mic:
|
||||
def __init__(self, device: str = "") -> None:
|
||||
def __init__(self, device: str = "", gain: float = 1.0) -> None:
|
||||
self.device = device
|
||||
self.gain = gain
|
||||
self.proc: asyncio.subprocess.Process | None = None
|
||||
|
||||
async def start(self) -> None:
|
||||
@@ -32,7 +44,7 @@ class Mic:
|
||||
|
||||
async def read(self) -> bytes:
|
||||
assert self.proc and self.proc.stdout
|
||||
return await self.proc.stdout.read(CHUNK)
|
||||
return apply_gain(await self.proc.stdout.read(CHUNK), self.gain)
|
||||
|
||||
async def stop(self) -> None:
|
||||
if self.proc and self.proc.returncode is None:
|
||||
|
||||
@@ -23,7 +23,8 @@ class Config:
|
||||
max_pages: int = field(default_factory=lambda: int(_env("IDRIZ_MAX_PAGES", "2")))
|
||||
dry_run: bool = field(default_factory=lambda: _env("IDRIZ_DRY_RUN", "0") == "1")
|
||||
vad_silence_ms: int = field(default_factory=lambda: int(_env("IDRIZ_VAD_SILENCE_MS", "900")))
|
||||
vad_threshold: float = field(default_factory=lambda: float(_env("IDRIZ_VAD_THRESHOLD", "0.6")))
|
||||
mic_gain: float = field(default_factory=lambda: float(_env("IDRIZ_MIC_GAIN", "3.0")))
|
||||
vad_threshold: float = field(default_factory=lambda: float(_env("IDRIZ_VAD_THRESHOLD", "0.5")))
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
self.out_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
Reference in New Issue
Block a user