@staff0rd/assist 0.751.0 → 0.752.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -20
- package/allowed.cli-reads +0 -1
- package/allowed.cli-writes +0 -1
- package/claude/settings.json +1 -22
- package/claude/skills/review-ci/scripts/review.mjs +111 -111
- package/dist/allowed.cli-reads +0 -1
- package/dist/allowed.cli-writes +0 -1
- package/dist/commands/sessions/web/bundle.js +1 -1
- package/dist/index.js +1717 -2222
- package/package.json +1 -1
- package/claude/commands/handover.md +0 -65
- package/claude/commands/journal.md +0 -74
- package/claude/commands/recall.md +0 -55
- package/claude/commands/standup.md +0 -35
- package/claude/commands/voice-logs.md +0 -5
- package/claude/commands/voice-setup.md +0 -5
- package/claude/commands/voice-start.md +0 -5
- package/claude/commands/voice-status.md +0 -5
- package/claude/commands/voice-stop.md +0 -5
- package/dist/commands/voice/python/CLAUDE.md +0 -11
- package/dist/commands/voice/python/audio_capture.py +0 -52
- package/dist/commands/voice/python/check_mi.py +0 -21
- package/dist/commands/voice/python/dispatch.py +0 -14
- package/dist/commands/voice/python/keyboard.py +0 -73
- package/dist/commands/voice/python/list_devices.py +0 -20
- package/dist/commands/voice/python/logger.py +0 -38
- package/dist/commands/voice/python/pyproject.toml +0 -26
- package/dist/commands/voice/python/setup_models.py +0 -91
- package/dist/commands/voice/python/smart_turn.py +0 -63
- package/dist/commands/voice/python/stt.py +0 -54
- package/dist/commands/voice/python/uv.lock +0 -5946
- package/dist/commands/voice/python/vad.py +0 -50
- package/dist/commands/voice/python/voice_daemon.py +0 -528
- package/dist/commands/voice/python/wake_word.py +0 -26
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
"""Smart Turn end-of-utterance detection (ONNX) via pipecat-ai/smart-turn."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
|
|
5
|
-
import numpy as np
|
|
6
|
-
import onnxruntime as ort
|
|
7
|
-
from transformers import WhisperFeatureExtractor
|
|
8
|
-
|
|
9
|
-
from logger import log
|
|
10
|
-
|
|
11
|
-
END_THRESHOLD = 0.5
|
|
12
|
-
CHUNK_SECONDS = 8
|
|
13
|
-
SAMPLE_RATE = 16000
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def _truncate_or_pad(audio: np.ndarray) -> np.ndarray:
|
|
17
|
-
max_samples = CHUNK_SECONDS * SAMPLE_RATE
|
|
18
|
-
if len(audio) > max_samples:
|
|
19
|
-
return audio[-max_samples:]
|
|
20
|
-
if len(audio) < max_samples:
|
|
21
|
-
padding = max_samples - len(audio)
|
|
22
|
-
return np.pad(audio, (padding, 0), mode="constant", constant_values=0)
|
|
23
|
-
return audio
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class SmartTurn:
|
|
27
|
-
def __init__(self):
|
|
28
|
-
model_path = os.environ.get("VOICE_MODEL_SMART_TURN")
|
|
29
|
-
if not model_path:
|
|
30
|
-
models_dir = os.environ.get(
|
|
31
|
-
"VOICE_MODELS_DIR",
|
|
32
|
-
os.path.expanduser("~/.assist/voice/models"),
|
|
33
|
-
)
|
|
34
|
-
model_path = os.path.join(models_dir, "smart-turn-v3.2-cpu.onnx")
|
|
35
|
-
|
|
36
|
-
log("smart_turn_init", f"model={model_path}")
|
|
37
|
-
so = ort.SessionOptions()
|
|
38
|
-
so.execution_mode = ort.ExecutionMode.ORT_SEQUENTIAL
|
|
39
|
-
so.inter_op_num_threads = 1
|
|
40
|
-
so.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
|
|
41
|
-
self._session = ort.InferenceSession(
|
|
42
|
-
model_path, sess_options=so, providers=["CPUExecutionProvider"]
|
|
43
|
-
)
|
|
44
|
-
self._feature_extractor = WhisperFeatureExtractor(chunk_length=CHUNK_SECONDS)
|
|
45
|
-
self.threshold = END_THRESHOLD
|
|
46
|
-
|
|
47
|
-
def is_end_of_turn(self, audio: np.ndarray) -> bool:
|
|
48
|
-
"""Check if the accumulated audio indicates end of utterance."""
|
|
49
|
-
audio = _truncate_or_pad(audio)
|
|
50
|
-
inputs = self._feature_extractor(
|
|
51
|
-
audio,
|
|
52
|
-
sampling_rate=SAMPLE_RATE,
|
|
53
|
-
return_tensors="np",
|
|
54
|
-
padding="max_length",
|
|
55
|
-
max_length=CHUNK_SECONDS * SAMPLE_RATE,
|
|
56
|
-
truncation=True,
|
|
57
|
-
do_normalize=True,
|
|
58
|
-
)
|
|
59
|
-
features = inputs.input_features.squeeze(0).astype(np.float32)
|
|
60
|
-
features = np.expand_dims(features, axis=0)
|
|
61
|
-
outputs = self._session.run(None, {"input_features": features})
|
|
62
|
-
prob = float(outputs[0][0].item())
|
|
63
|
-
return prob > self.threshold
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
"""Parakeet NeMo STT wrapper (GPU)."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import numpy as np
|
|
5
|
-
import torch
|
|
6
|
-
|
|
7
|
-
from logger import log
|
|
8
|
-
|
|
9
|
-
DEFAULT_MODEL = "nvidia/parakeet-ctc-1.1b"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class ParakeetSTT:
|
|
13
|
-
def __init__(self):
|
|
14
|
-
model_name = os.environ.get("VOICE_MODEL_STT", DEFAULT_MODEL)
|
|
15
|
-
self._device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
16
|
-
log("stt_init", f"model={model_name} device={self._device}")
|
|
17
|
-
|
|
18
|
-
import nemo.collections.asr as nemo_asr
|
|
19
|
-
|
|
20
|
-
self._model = nemo_asr.models.EncDecCTCModelBPE.from_pretrained(model_name)
|
|
21
|
-
self._model = self._model.to(self._device)
|
|
22
|
-
self._model.eval()
|
|
23
|
-
log("stt_ready")
|
|
24
|
-
|
|
25
|
-
def transcribe(self, audio: np.ndarray, sample_rate: int = 16000) -> str:
|
|
26
|
-
"""Transcribe audio buffer to text via direct forward pass."""
|
|
27
|
-
audio_tensor = (
|
|
28
|
-
torch.tensor(audio, dtype=torch.float32).unsqueeze(0).to(self._device)
|
|
29
|
-
)
|
|
30
|
-
audio_len = torch.tensor([audio.shape[0]], dtype=torch.long).to(self._device)
|
|
31
|
-
|
|
32
|
-
with torch.no_grad():
|
|
33
|
-
logits, logits_len, _ = self._model.forward(
|
|
34
|
-
input_signal=audio_tensor, input_signal_length=audio_len
|
|
35
|
-
)
|
|
36
|
-
# Greedy CTC decode
|
|
37
|
-
preds = torch.argmax(logits, dim=-1)
|
|
38
|
-
text = self._model.decoding.ctc_decoder_predictions_tensor(
|
|
39
|
-
preds, decoder_lengths=logits_len
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
# Result may be nested: tuple of lists of Hypothesis objects
|
|
43
|
-
if isinstance(text, tuple):
|
|
44
|
-
text = text[0]
|
|
45
|
-
if isinstance(text, list):
|
|
46
|
-
text = text[0]
|
|
47
|
-
# NeMo returns Hypothesis namedtuples with a .text field
|
|
48
|
-
if hasattr(text, "text"):
|
|
49
|
-
text = text.text
|
|
50
|
-
if not isinstance(text, str):
|
|
51
|
-
text = str(text)
|
|
52
|
-
|
|
53
|
-
log("stt_result", text)
|
|
54
|
-
return text
|