omnius 1.0.417 → 1.0.419

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.
@@ -165,6 +165,24 @@ def main():
165
165
  window_samples = int(args.window_seconds * SAMPLE_RATE)
166
166
  last_text = ""
167
167
  running = True
168
+ noise_floor = None # EMA of the quietest 0.5s block RMS — adapts to the capture chain
169
+
170
+ def block_energies(samples):
171
+ """RMS of consecutive 0.5s blocks — lets speech anywhere in the
172
+ window register even when most of the window is silence."""
173
+ block = SAMPLE_RATE // 2
174
+ n = max(1, len(samples) // block)
175
+ return [float(np.sqrt(np.mean(samples[i * block:(i + 1) * block] ** 2))) for i in range(n)]
176
+
177
+ def amplify(samples):
178
+ """Bring quiet-but-real speech toward full scale. Whisper performs far
179
+ better near normal levels; quiet capture chains (distant speakers,
180
+ low source gain, beamformed arrays) otherwise force users to shout
181
+ into the mic. Gain capped at 40x (~32dB), output clipped to [-1, 1]."""
182
+ peak = float(np.max(np.abs(samples))) if len(samples) else 0.0
183
+ if 0 < peak < 0.5:
184
+ samples = np.clip(samples * min(40.0, 0.9 / max(peak, 1e-4)), -1.0, 1.0)
185
+ return samples
168
186
 
169
187
  def read_stdin():
170
188
  """Read PCM16 from stdin in a background thread."""
@@ -197,6 +215,26 @@ def main():
197
215
  # Take the last window_seconds of audio
198
216
  window = audio_buf[-window_samples:].copy() if len(audio_buf) > window_samples else audio_buf.copy()
199
217
 
218
+ # Adaptive silence gate: whisper hallucinates repetitive garbage
219
+ # on silent input, but absolute thresholds reject real speech on
220
+ # quiet capture chains. Instead track the noise floor (quietest
221
+ # 0.5s block) and require the loudest block to rise above it.
222
+ energies = block_energies(window)
223
+ quiet = min(energies)
224
+ loud = max(energies)
225
+ if noise_floor is None:
226
+ noise_floor = quiet
227
+ elif quiet < noise_floor:
228
+ noise_floor = 0.7 * noise_floor + 0.3 * quiet # drop fast
229
+ else:
230
+ noise_floor = 0.995 * noise_floor + 0.005 * quiet # creep up slowly
231
+ gate = max(1.5e-4, noise_floor * 2.5) # ≥ ~8dB above floor, ~-76dB min
232
+ if loud < gate:
233
+ continue
234
+
235
+ # Amplify toward full scale before transcription
236
+ window = amplify(window)
237
+
200
238
  # Transcribe
201
239
  try:
202
240
  fp16 = (device == "cuda")
@@ -221,8 +259,11 @@ def main():
221
259
  with buf_lock:
222
260
  full_audio = audio_buf.copy()
223
261
 
224
- if len(full_audio) >= SAMPLE_RATE:
262
+ final_loud = max(block_energies(full_audio)) if len(full_audio) >= SAMPLE_RATE else 0.0
263
+ final_gate = max(1.5e-4, (noise_floor or 0.0) * 2.5)
264
+ if len(full_audio) >= SAMPLE_RATE and final_loud >= final_gate:
225
265
  try:
266
+ full_audio = amplify(full_audio)
226
267
  fp16 = (device == "cuda")
227
268
  result = model.transcribe(
228
269
  full_audio,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.417",
3
+ "version": "1.0.419",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.417",
9
+ "version": "1.0.419",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.417",
3
+ "version": "1.0.419",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",