omnius 1.0.408 → 1.0.409
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/dist/index.js +422 -122
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -41519,7 +41519,7 @@ function formatTime(seconds) {
|
|
|
41519
41519
|
const s2 = Math.floor(seconds % 60);
|
|
41520
41520
|
return `${String(m2).padStart(2, "0")}:${String(s2).padStart(2, "0")}`;
|
|
41521
41521
|
}
|
|
41522
|
-
var AUDIO_EXTS, VIDEO_EXTS, MAX_TRANSCRIBE_URL_BYTES, _tcModule, _tcChecked, TranscribeFileTool, YT_DLP_VENV, TranscribeUrlTool, YouTubeDownloadTool;
|
|
41522
|
+
var AUDIO_EXTS, VIDEO_EXTS, MAX_TRANSCRIBE_URL_BYTES, MANAGED_ASR_VENV, _tcModule, _tcChecked, _managedAsrReady, TranscribeFileTool, YT_DLP_VENV, TranscribeUrlTool, YouTubeDownloadTool;
|
|
41523
41523
|
var init_transcribe_tool = __esm({
|
|
41524
41524
|
"packages/execution/dist/tools/transcribe-tool.js"() {
|
|
41525
41525
|
"use strict";
|
|
@@ -41550,8 +41550,10 @@ var init_transcribe_tool = __esm({
|
|
|
41550
41550
|
".ts"
|
|
41551
41551
|
]);
|
|
41552
41552
|
MAX_TRANSCRIBE_URL_BYTES = 100 * 1024 * 1024;
|
|
41553
|
+
MANAGED_ASR_VENV = join40(homedir11(), ".omnius", "runtimes", "asr", ".venv-whisper");
|
|
41553
41554
|
_tcModule = null;
|
|
41554
41555
|
_tcChecked = false;
|
|
41556
|
+
_managedAsrReady = false;
|
|
41555
41557
|
TranscribeFileTool = class {
|
|
41556
41558
|
name = "transcribe_file";
|
|
41557
41559
|
description = "Transcribe a local audio or video file to text using Whisper (faster-whisper). Supports MP3, WAV, FLAC, AAC, M4A, OGG, MP4, MKV, AVI, MOV, WebM. Returns the full transcription text with optional speaker diarization. Transcription is 100% local — no API keys needed.";
|
|
@@ -41625,102 +41627,131 @@ var init_transcribe_tool = __esm({
|
|
|
41625
41627
|
}
|
|
41626
41628
|
if (effectiveModel !== askedModel)
|
|
41627
41629
|
model = effectiveModel;
|
|
41630
|
+
const failures = [];
|
|
41628
41631
|
const tc = await loadTranscribeCli();
|
|
41629
|
-
if (
|
|
41630
|
-
|
|
41631
|
-
|
|
41632
|
+
if (tc) {
|
|
41633
|
+
try {
|
|
41634
|
+
const result = await withProcessEnv(transcriptionPythonEnv(), () => tc.transcribe(filePath, {
|
|
41635
|
+
model,
|
|
41636
|
+
format: "json",
|
|
41637
|
+
diarize,
|
|
41638
|
+
wordTimestamps: true
|
|
41639
|
+
}));
|
|
41640
|
+
return this.formatTranscriptionResult(filePath, model, result, start2, "transcribe-cli");
|
|
41641
|
+
} catch (err) {
|
|
41642
|
+
failures.push(`transcribe-cli module: ${err instanceof Error ? err.message : String(err)}`);
|
|
41643
|
+
}
|
|
41644
|
+
}
|
|
41645
|
+
const cli = await this.execViaCli(filePath, model, diarize, start2);
|
|
41646
|
+
if (cli.success)
|
|
41647
|
+
return cli;
|
|
41648
|
+
if (cli.error)
|
|
41649
|
+
failures.push(cli.error);
|
|
41650
|
+
const managed = await this.execViaManagedWhisper(filePath, model, start2);
|
|
41651
|
+
if (managed.success)
|
|
41652
|
+
return managed;
|
|
41653
|
+
if (managed.error)
|
|
41654
|
+
failures.push(managed.error);
|
|
41655
|
+
return {
|
|
41656
|
+
success: false,
|
|
41657
|
+
output: "",
|
|
41658
|
+
error: `Transcription failed after all ASR backends. ${failures.join(" | ").slice(0, 1200)}`,
|
|
41659
|
+
durationMs: performance.now() - start2
|
|
41660
|
+
};
|
|
41661
|
+
}
|
|
41662
|
+
formatTranscriptionResult(filePath, model, result, start2, backend) {
|
|
41663
|
+
const segments = Array.isArray(result.segments) ? result.segments : [];
|
|
41664
|
+
const text2 = String(result.text ?? result.fullText ?? "").trim();
|
|
41665
|
+
const speakers = Array.isArray(result.speakers) ? result.speakers : [];
|
|
41666
|
+
const wordCount2 = Number(result.wordCount ?? (text2 ? text2.split(/\s+/).filter(Boolean).length : 0));
|
|
41667
|
+
const transcriptDir = join40(this.workingDir, ".omnius", "transcripts");
|
|
41668
|
+
mkdirSync22(transcriptDir, { recursive: true });
|
|
41669
|
+
const fileBase = basename7(filePath).replace(/\.[^.]+$/, "");
|
|
41670
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
41671
|
+
const txtFile = join40(transcriptDir, `${fileBase}-${timestamp}.txt`);
|
|
41672
|
+
const jsonFile = join40(transcriptDir, `${fileBase}-${timestamp}.json`);
|
|
41673
|
+
writeFileSync21(txtFile, text2, "utf-8");
|
|
41674
|
+
const structured = {
|
|
41675
|
+
source: filePath,
|
|
41676
|
+
model,
|
|
41677
|
+
backend,
|
|
41678
|
+
language: result.language,
|
|
41679
|
+
duration: result.duration,
|
|
41680
|
+
wordCount: wordCount2,
|
|
41681
|
+
speakers,
|
|
41682
|
+
transcribedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
41683
|
+
segments: segments.map((seg) => ({
|
|
41684
|
+
start: Number(seg.start ?? 0),
|
|
41685
|
+
end: Number(seg.end ?? seg.start ?? 0),
|
|
41686
|
+
text: String(seg.text ?? ""),
|
|
41687
|
+
speaker: seg.speaker || void 0
|
|
41688
|
+
})),
|
|
41689
|
+
fullText: text2
|
|
41690
|
+
};
|
|
41691
|
+
writeFileSync21(jsonFile, JSON.stringify(structured, null, 2), "utf-8");
|
|
41632
41692
|
try {
|
|
41633
|
-
const
|
|
41634
|
-
|
|
41635
|
-
|
|
41636
|
-
|
|
41637
|
-
wordTimestamps: true
|
|
41638
|
-
// Always get timestamps for structured output
|
|
41639
|
-
}));
|
|
41640
|
-
const transcriptDir = join40(this.workingDir, ".omnius", "transcripts");
|
|
41641
|
-
mkdirSync22(transcriptDir, { recursive: true });
|
|
41642
|
-
const fileBase = basename7(filePath).replace(/\.[^.]+$/, "");
|
|
41643
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
41644
|
-
const txtFile = join40(transcriptDir, `${fileBase}-${timestamp}.txt`);
|
|
41645
|
-
writeFileSync21(txtFile, result.text, "utf-8");
|
|
41646
|
-
const jsonFile = join40(transcriptDir, `${fileBase}-${timestamp}.json`);
|
|
41647
|
-
const structured = {
|
|
41648
|
-
source: filePath,
|
|
41649
|
-
model,
|
|
41650
|
-
language: result.language,
|
|
41651
|
-
duration: result.duration,
|
|
41652
|
-
wordCount: result.wordCount,
|
|
41653
|
-
speakers: result.speakers,
|
|
41654
|
-
transcribedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
41655
|
-
segments: result.segments.map((seg) => ({
|
|
41656
|
-
start: seg.start,
|
|
41657
|
-
end: seg.end,
|
|
41658
|
-
text: seg.text,
|
|
41659
|
-
speaker: seg.speaker || void 0
|
|
41660
|
-
})),
|
|
41661
|
-
fullText: result.text
|
|
41662
|
-
};
|
|
41663
|
-
writeFileSync21(jsonFile, JSON.stringify(structured, null, 2), "utf-8");
|
|
41693
|
+
const memDir = join40(this.workingDir, ".omnius", "memory");
|
|
41694
|
+
mkdirSync22(memDir, { recursive: true });
|
|
41695
|
+
const memFile = join40(memDir, "transcripts.json");
|
|
41696
|
+
let memEntries = [];
|
|
41664
41697
|
try {
|
|
41665
|
-
|
|
41666
|
-
mkdirSync22(memDir, { recursive: true });
|
|
41667
|
-
const memFile = join40(memDir, "transcripts.json");
|
|
41668
|
-
let memEntries = [];
|
|
41669
|
-
try {
|
|
41670
|
-
memEntries = JSON.parse(readFileSync30(memFile, "utf-8"));
|
|
41671
|
-
} catch {
|
|
41672
|
-
}
|
|
41673
|
-
memEntries.push({
|
|
41674
|
-
source: basename7(filePath),
|
|
41675
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
41676
|
-
duration: result.duration,
|
|
41677
|
-
wordCount: result.wordCount,
|
|
41678
|
-
language: result.language,
|
|
41679
|
-
summary: result.text.slice(0, 200),
|
|
41680
|
-
jsonPath: jsonFile,
|
|
41681
|
-
txtPath: txtFile
|
|
41682
|
-
});
|
|
41683
|
-
if (memEntries.length > 50)
|
|
41684
|
-
memEntries = memEntries.slice(-50);
|
|
41685
|
-
writeFileSync21(memFile, JSON.stringify(memEntries, null, 2), "utf-8");
|
|
41698
|
+
memEntries = JSON.parse(readFileSync30(memFile, "utf-8"));
|
|
41686
41699
|
} catch {
|
|
41687
41700
|
}
|
|
41688
|
-
|
|
41689
|
-
|
|
41690
|
-
|
|
41691
|
-
|
|
41692
|
-
|
|
41693
|
-
|
|
41694
|
-
|
|
41695
|
-
|
|
41696
|
-
|
|
41697
|
-
|
|
41698
|
-
}
|
|
41699
|
-
if (
|
|
41700
|
-
|
|
41701
|
-
|
|
41702
|
-
|
|
41703
|
-
|
|
41704
|
-
|
|
41705
|
-
|
|
41706
|
-
|
|
41701
|
+
memEntries.push({
|
|
41702
|
+
source: basename7(filePath),
|
|
41703
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
41704
|
+
duration: result.duration,
|
|
41705
|
+
wordCount: wordCount2,
|
|
41706
|
+
language: result.language,
|
|
41707
|
+
backend,
|
|
41708
|
+
summary: text2.slice(0, 200),
|
|
41709
|
+
jsonPath: jsonFile,
|
|
41710
|
+
txtPath: txtFile
|
|
41711
|
+
});
|
|
41712
|
+
if (memEntries.length > 50)
|
|
41713
|
+
memEntries = memEntries.slice(-50);
|
|
41714
|
+
writeFileSync21(memFile, JSON.stringify(memEntries, null, 2), "utf-8");
|
|
41715
|
+
} catch {
|
|
41716
|
+
}
|
|
41717
|
+
const lines = [
|
|
41718
|
+
`Transcription of: ${basename7(filePath)}`,
|
|
41719
|
+
`Backend: ${backend}`,
|
|
41720
|
+
`Model: ${model} | Language: ${result.language ?? "unknown"} | Duration: ${result.duration ? `${Number(result.duration).toFixed(1)}s` : "unknown"}`,
|
|
41721
|
+
`Words: ${wordCount2} | Segments: ${segments.length}`,
|
|
41722
|
+
`Saved: ${txtFile} (text) + ${jsonFile} (structured with timestamps)`,
|
|
41723
|
+
""
|
|
41724
|
+
];
|
|
41725
|
+
if (speakers.length > 1) {
|
|
41726
|
+
lines.push(`Speakers: ${speakers.join(", ")}`);
|
|
41727
|
+
lines.push("");
|
|
41728
|
+
}
|
|
41729
|
+
if (segments.length > 0) {
|
|
41730
|
+
for (const seg of segments) {
|
|
41731
|
+
const ts = `[${formatTime(Number(seg.start ?? 0))} → ${formatTime(Number(seg.end ?? seg.start ?? 0))}]`;
|
|
41732
|
+
const speaker = seg.speaker ? `${seg.speaker}: ` : "";
|
|
41733
|
+
lines.push(`${ts} ${speaker}${String(seg.text ?? "").trim()}`);
|
|
41707
41734
|
}
|
|
41708
|
-
|
|
41709
|
-
|
|
41710
|
-
|
|
41711
|
-
|
|
41712
|
-
|
|
41713
|
-
|
|
41735
|
+
} else {
|
|
41736
|
+
lines.push(text2 || "[silent — no speech detected]");
|
|
41737
|
+
}
|
|
41738
|
+
return {
|
|
41739
|
+
success: true,
|
|
41740
|
+
output: lines.join("\n"),
|
|
41741
|
+
llmContent: text2,
|
|
41742
|
+
durationMs: performance.now() - start2
|
|
41743
|
+
};
|
|
41744
|
+
}
|
|
41745
|
+
/** Fallback: invoke transcribe-cli as a subprocess. */
|
|
41746
|
+
async execViaCli(filePath, model, diarize, start2) {
|
|
41747
|
+
if (!await commandExists("transcribe-cli", 1500)) {
|
|
41714
41748
|
return {
|
|
41715
41749
|
success: false,
|
|
41716
41750
|
output: "",
|
|
41717
|
-
error:
|
|
41751
|
+
error: "transcribe-cli command unavailable",
|
|
41718
41752
|
durationMs: performance.now() - start2
|
|
41719
41753
|
};
|
|
41720
41754
|
}
|
|
41721
|
-
}
|
|
41722
|
-
/** Fallback: invoke transcribe-cli as a subprocess. */
|
|
41723
|
-
async execViaCli(filePath, model, diarize, start2) {
|
|
41724
41755
|
try {
|
|
41725
41756
|
const args = [filePath, "-m", model, "-f", "txt"];
|
|
41726
41757
|
if (diarize)
|
|
@@ -41734,6 +41765,7 @@ var init_transcribe_tool = __esm({
|
|
|
41734
41765
|
return {
|
|
41735
41766
|
success: true,
|
|
41736
41767
|
output: output.trim() || "(empty transcription)",
|
|
41768
|
+
llmContent: output.trim() || "",
|
|
41737
41769
|
durationMs: performance.now() - start2
|
|
41738
41770
|
};
|
|
41739
41771
|
} catch (err) {
|
|
@@ -41747,6 +41779,112 @@ var init_transcribe_tool = __esm({
|
|
|
41747
41779
|
};
|
|
41748
41780
|
}
|
|
41749
41781
|
}
|
|
41782
|
+
async ensureManagedWhisperRuntime() {
|
|
41783
|
+
const python = venvPython(MANAGED_ASR_VENV);
|
|
41784
|
+
if (!existsSync38(python)) {
|
|
41785
|
+
mkdirSync22(join40(homedir11(), ".omnius", "runtimes", "asr"), { recursive: true });
|
|
41786
|
+
await execFileText("python3", ["-m", "venv", MANAGED_ASR_VENV], {
|
|
41787
|
+
timeout: 6e4,
|
|
41788
|
+
env: transcriptionPythonEnv()
|
|
41789
|
+
});
|
|
41790
|
+
}
|
|
41791
|
+
if (_managedAsrReady)
|
|
41792
|
+
return python;
|
|
41793
|
+
try {
|
|
41794
|
+
await execFileText(python, ["-c", "import whisper, numpy"], {
|
|
41795
|
+
timeout: 1e4,
|
|
41796
|
+
env: transcriptionPythonEnv()
|
|
41797
|
+
});
|
|
41798
|
+
_managedAsrReady = true;
|
|
41799
|
+
return python;
|
|
41800
|
+
} catch {
|
|
41801
|
+
await execFileText(python, [
|
|
41802
|
+
"-m",
|
|
41803
|
+
"pip",
|
|
41804
|
+
"install",
|
|
41805
|
+
"-U",
|
|
41806
|
+
"pip",
|
|
41807
|
+
"wheel",
|
|
41808
|
+
"setuptools",
|
|
41809
|
+
"numpy",
|
|
41810
|
+
"openai-whisper"
|
|
41811
|
+
], {
|
|
41812
|
+
timeout: 9e5,
|
|
41813
|
+
env: transcriptionPythonEnv()
|
|
41814
|
+
});
|
|
41815
|
+
_managedAsrReady = true;
|
|
41816
|
+
return python;
|
|
41817
|
+
}
|
|
41818
|
+
}
|
|
41819
|
+
async execViaManagedWhisper(filePath, model, start2) {
|
|
41820
|
+
const scriptPath2 = join40(this.workingDir, ".omnius", "tmp", `managed-whisper-${Date.now()}.py`);
|
|
41821
|
+
mkdirSync22(join40(this.workingDir, ".omnius", "tmp"), { recursive: true });
|
|
41822
|
+
const script = `
|
|
41823
|
+
import json, os, warnings
|
|
41824
|
+
warnings.filterwarnings("ignore")
|
|
41825
|
+
os.environ.setdefault("TF_CPP_MIN_LOG_LEVEL", "3")
|
|
41826
|
+
audio_file = ${JSON.stringify(filePath)}
|
|
41827
|
+
model_name = ${JSON.stringify(model)}
|
|
41828
|
+
try:
|
|
41829
|
+
import whisper
|
|
41830
|
+
device = "cpu"
|
|
41831
|
+
try:
|
|
41832
|
+
import torch
|
|
41833
|
+
if torch.cuda.is_available():
|
|
41834
|
+
device = "cuda"
|
|
41835
|
+
except Exception:
|
|
41836
|
+
pass
|
|
41837
|
+
m = whisper.load_model(model_name, device=device)
|
|
41838
|
+
result = m.transcribe(audio_file, fp16=(device == "cuda"), condition_on_previous_text=False)
|
|
41839
|
+
segments = []
|
|
41840
|
+
for seg in result.get("segments", []) or []:
|
|
41841
|
+
segments.append({"start": float(seg.get("start", 0)), "end": float(seg.get("end", seg.get("start", 0))), "text": str(seg.get("text", "")).strip()})
|
|
41842
|
+
text = str(result.get("text", "")).strip()
|
|
41843
|
+
print(json.dumps({
|
|
41844
|
+
"ok": True,
|
|
41845
|
+
"text": text,
|
|
41846
|
+
"language": result.get("language"),
|
|
41847
|
+
"duration": segments[-1]["end"] if segments else None,
|
|
41848
|
+
"wordCount": len([w for w in text.split() if w]),
|
|
41849
|
+
"speakers": [],
|
|
41850
|
+
"segments": segments,
|
|
41851
|
+
}))
|
|
41852
|
+
except Exception as exc:
|
|
41853
|
+
print(json.dumps({"ok": False, "error": str(exc)}))
|
|
41854
|
+
`;
|
|
41855
|
+
try {
|
|
41856
|
+
writeFileSync21(scriptPath2, script, "utf-8");
|
|
41857
|
+
const python = await this.ensureManagedWhisperRuntime();
|
|
41858
|
+
const raw = await execFileText(python, [scriptPath2], {
|
|
41859
|
+
timeout: 6e5,
|
|
41860
|
+
cwd: this.workingDir,
|
|
41861
|
+
env: transcriptionPythonEnv({ PYTHONUNBUFFERED: "1" }),
|
|
41862
|
+
maxBuffer: 16 * 1024 * 1024
|
|
41863
|
+
});
|
|
41864
|
+
const parsed = JSON.parse(raw.trim().split("\n").reverse().find((line) => line.trim().startsWith("{")) ?? "{}");
|
|
41865
|
+
if (!parsed.ok) {
|
|
41866
|
+
return {
|
|
41867
|
+
success: false,
|
|
41868
|
+
output: "",
|
|
41869
|
+
error: `managed openai-whisper failed: ${parsed.error || raw.slice(-500)}`,
|
|
41870
|
+
durationMs: performance.now() - start2
|
|
41871
|
+
};
|
|
41872
|
+
}
|
|
41873
|
+
return this.formatTranscriptionResult(filePath, model, parsed, start2, "managed openai-whisper");
|
|
41874
|
+
} catch (err) {
|
|
41875
|
+
return {
|
|
41876
|
+
success: false,
|
|
41877
|
+
output: "",
|
|
41878
|
+
error: `managed openai-whisper failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
41879
|
+
durationMs: performance.now() - start2
|
|
41880
|
+
};
|
|
41881
|
+
} finally {
|
|
41882
|
+
try {
|
|
41883
|
+
unlinkSync5(scriptPath2);
|
|
41884
|
+
} catch {
|
|
41885
|
+
}
|
|
41886
|
+
}
|
|
41887
|
+
}
|
|
41750
41888
|
};
|
|
41751
41889
|
YT_DLP_VENV = join40(homedir11(), ".omnius", "runtimes", "media-tools", ".venv-ytdlp");
|
|
41752
41890
|
TranscribeUrlTool = class {
|
|
@@ -547804,17 +547942,23 @@ except Exception as e:
|
|
|
547804
547942
|
const audioFile = await this.ensureAudioFile(args);
|
|
547805
547943
|
if (!audioFile)
|
|
547806
547944
|
return { success: false, output: "", error: "No audio available.", durationMs: performance.now() - start2 };
|
|
547807
|
-
await this.ensureVenv(["torch", "
|
|
547945
|
+
await this.ensureVenv(["torch", "numpy", "soundfile", "resampy"]);
|
|
547808
547946
|
const audioLiteral = JSON.stringify(audioFile);
|
|
547809
547947
|
const script = `
|
|
547810
547948
|
import sys, json, numpy as np
|
|
547811
547949
|
try:
|
|
547812
|
-
import torch,
|
|
547950
|
+
import torch, soundfile as sf, resampy
|
|
547813
547951
|
|
|
547814
547952
|
model, utils = torch.hub.load(repo_or_dir='snakers4/silero-vad', model='silero_vad', force_reload=False, trust_repo=True)
|
|
547815
|
-
(get_speech_timestamps,
|
|
547953
|
+
(get_speech_timestamps, *_) = utils
|
|
547816
547954
|
|
|
547817
|
-
|
|
547955
|
+
audio, sr = sf.read(${audioLiteral})
|
|
547956
|
+
if len(getattr(audio, "shape", [])) > 1:
|
|
547957
|
+
audio = audio.mean(axis=1)
|
|
547958
|
+
if sr != 16000:
|
|
547959
|
+
audio = resampy.resample(audio, sr, 16000)
|
|
547960
|
+
audio = audio.astype(np.float32)
|
|
547961
|
+
wav = torch.from_numpy(audio)
|
|
547818
547962
|
speech_timestamps = get_speech_timestamps(wav, model, sampling_rate=16000, threshold=0.5)
|
|
547819
547963
|
|
|
547820
547964
|
total_samples = len(wav)
|
|
@@ -547825,6 +547969,7 @@ try:
|
|
|
547825
547969
|
|
|
547826
547970
|
print(json.dumps({
|
|
547827
547971
|
"success": True,
|
|
547972
|
+
"backend": "silero-vad",
|
|
547828
547973
|
"voice_detected": len(speech_timestamps) > 0,
|
|
547829
547974
|
"speech_percentage": round(speech_pct, 1),
|
|
547830
547975
|
"speech_segments": len(speech_timestamps),
|
|
@@ -547832,7 +547977,57 @@ try:
|
|
|
547832
547977
|
"segments": segments[:10]
|
|
547833
547978
|
}))
|
|
547834
547979
|
except Exception as e:
|
|
547835
|
-
|
|
547980
|
+
try:
|
|
547981
|
+
import soundfile as sf
|
|
547982
|
+
import resampy
|
|
547983
|
+
audio, sr = sf.read(${audioLiteral})
|
|
547984
|
+
if len(getattr(audio, "shape", [])) > 1:
|
|
547985
|
+
audio = audio.mean(axis=1)
|
|
547986
|
+
if sr != 16000:
|
|
547987
|
+
audio = resampy.resample(audio, sr, 16000)
|
|
547988
|
+
audio = audio.astype(np.float32)
|
|
547989
|
+
frame = max(1, int(0.03 * 16000))
|
|
547990
|
+
hop = max(1, int(0.01 * 16000))
|
|
547991
|
+
rms = []
|
|
547992
|
+
for i in range(0, max(1, len(audio) - frame + 1), hop):
|
|
547993
|
+
chunk = audio[i:i+frame]
|
|
547994
|
+
if len(chunk) == 0:
|
|
547995
|
+
continue
|
|
547996
|
+
rms.append(float(np.sqrt(np.mean(chunk * chunk))))
|
|
547997
|
+
arr = np.array(rms, dtype=np.float32)
|
|
547998
|
+
if len(arr) == 0:
|
|
547999
|
+
active = np.array([], dtype=bool)
|
|
548000
|
+
else:
|
|
548001
|
+
floor = float(np.percentile(arr, 35))
|
|
548002
|
+
peak = float(np.max(arr))
|
|
548003
|
+
threshold = max(0.008, floor * 2.5, peak * 0.12)
|
|
548004
|
+
active = arr > threshold
|
|
548005
|
+
segments = []
|
|
548006
|
+
start_idx = None
|
|
548007
|
+
for idx, flag in enumerate(active.tolist()):
|
|
548008
|
+
if flag and start_idx is None:
|
|
548009
|
+
start_idx = idx
|
|
548010
|
+
if (not flag or idx == len(active) - 1) and start_idx is not None:
|
|
548011
|
+
end_idx = idx if not flag else idx + 1
|
|
548012
|
+
start_s = start_idx * hop / 16000.0
|
|
548013
|
+
end_s = min(len(audio) / 16000.0, (end_idx * hop + frame) / 16000.0)
|
|
548014
|
+
if end_s - start_s >= 0.12:
|
|
548015
|
+
segments.append({"start_s": start_s, "end_s": end_s, "duration_s": end_s - start_s})
|
|
548016
|
+
start_idx = None
|
|
548017
|
+
speech_duration = sum(seg["duration_s"] for seg in segments)
|
|
548018
|
+
total_duration = len(audio) / 16000.0 if len(audio) else 0
|
|
548019
|
+
print(json.dumps({
|
|
548020
|
+
"success": True,
|
|
548021
|
+
"backend": "energy-vad-fallback",
|
|
548022
|
+
"warning": "silero unavailable: " + str(e),
|
|
548023
|
+
"voice_detected": len(segments) > 0,
|
|
548024
|
+
"speech_percentage": round((speech_duration / total_duration * 100) if total_duration else 0, 1),
|
|
548025
|
+
"speech_segments": len(segments),
|
|
548026
|
+
"total_duration_s": round(total_duration, 2),
|
|
548027
|
+
"segments": segments[:10]
|
|
548028
|
+
}))
|
|
548029
|
+
except Exception as fallback:
|
|
548030
|
+
print(json.dumps({"success": False, "error": str(e) + "; fallback failed: " + str(fallback)}))
|
|
547836
548031
|
`;
|
|
547837
548032
|
return await this.runPythonScript(script, start2, "Voice activity detection");
|
|
547838
548033
|
}
|
|
@@ -555516,6 +555711,9 @@ function summarizeObjects(objects) {
|
|
|
555516
555711
|
}
|
|
555517
555712
|
return [...counts.entries()].sort((a2, b) => b[1].count - a2[1].count).slice(0, 12).map(([label, value2]) => `${label} x${value2.count} mean_conf=${(value2.confidence / Math.max(1, value2.count)).toFixed(2)}`);
|
|
555518
555713
|
}
|
|
555714
|
+
function isDiagnosticAudioEvidence(text2) {
|
|
555715
|
+
return /^(?:ASR|VAD|Audio comprehension)\s+(?:failed|unavailable|completed)|No module named ['"]?transcribe_cli|torchcodec|torchaudio version|no speech detected|empty transcription/i.test(text2.trim());
|
|
555716
|
+
}
|
|
555519
555717
|
function observationsFromResult(result, extraText) {
|
|
555520
555718
|
const observations = [];
|
|
555521
555719
|
for (const obj of result.objects) {
|
|
@@ -555541,6 +555739,8 @@ function observationsFromResult(result, extraText) {
|
|
|
555541
555739
|
});
|
|
555542
555740
|
}
|
|
555543
555741
|
for (const text2 of extraText) {
|
|
555742
|
+
if (isDiagnosticAudioEvidence(text2))
|
|
555743
|
+
continue;
|
|
555544
555744
|
observations.push({
|
|
555545
555745
|
type: "transcript",
|
|
555546
555746
|
confidence: 0.75,
|
|
@@ -555958,7 +556158,12 @@ var init_live_media_loop = __esm({
|
|
|
555958
556158
|
try {
|
|
555959
556159
|
const transcribe = new TranscribeFileTool(this.workingDir);
|
|
555960
556160
|
const asr = await transcribe.execute({ path: result.media_path, model: "tiny" });
|
|
555961
|
-
|
|
556161
|
+
if (asr.success) {
|
|
556162
|
+
const transcript = typeof asr.llmContent === "string" ? asr.llmContent.trim() : "";
|
|
556163
|
+
audioEvidence.push(transcript ? transcript.slice(0, 3e3) : "ASR completed: no speech detected");
|
|
556164
|
+
} else {
|
|
556165
|
+
audioEvidence.push(`ASR unavailable: ${asr.error}`);
|
|
556166
|
+
}
|
|
555962
556167
|
} catch (err) {
|
|
555963
556168
|
audioEvidence.push(`ASR failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
555964
556169
|
}
|
|
@@ -601694,10 +601899,13 @@ function defaultAsciiPreviewSize(dimensions) {
|
|
|
601694
601899
|
const columns = process.stdout.columns || 100;
|
|
601695
601900
|
const rows = process.stdout.rows || 32;
|
|
601696
601901
|
const width = clamp7(columns - 14, 42, 96);
|
|
601697
|
-
const
|
|
601698
|
-
const height = clamp7(Math.min(Math.round(width * imageAspect * TERMINAL_CELL_ASPECT), rows - 10), 8, 42);
|
|
601902
|
+
const height = defaultAsciiPreviewHeight(width, dimensions, rows);
|
|
601699
601903
|
return { width, height };
|
|
601700
601904
|
}
|
|
601905
|
+
function defaultAsciiPreviewHeight(width, dimensions, rows = process.stdout.rows || 32) {
|
|
601906
|
+
const imageAspect = dimensions && dimensions.width > 0 && dimensions.height > 0 ? dimensions.height / dimensions.width : 1;
|
|
601907
|
+
return clamp7(Math.min(Math.round(width * imageAspect * TERMINAL_CELL_ASPECT), rows - 10), 8, 42);
|
|
601908
|
+
}
|
|
601701
601909
|
function readImageDimensions2(imagePath) {
|
|
601702
601910
|
try {
|
|
601703
601911
|
const buf = readFileSync87(imagePath);
|
|
@@ -601959,7 +602167,7 @@ async function buildImageAsciiPreview(inputPath, options2 = {}) {
|
|
|
601959
602167
|
const dimensions = readImageDimensions2(imagePath);
|
|
601960
602168
|
const defaults3 = defaultAsciiPreviewSize(dimensions);
|
|
601961
602169
|
const width = clamp7(options2.width ?? defaults3.width, 24, 140);
|
|
601962
|
-
const height = clamp7(options2.height ??
|
|
602170
|
+
const height = clamp7(options2.height ?? defaultAsciiPreviewHeight(width, dimensions), 6, 60);
|
|
601963
602171
|
const timeoutMs = clamp7(options2.timeoutMs ?? 5e3, 500, 3e4);
|
|
601964
602172
|
if (options2.preferPackage !== false) {
|
|
601965
602173
|
const result = await convertWithImageToAscii(imagePath, width, height, timeoutMs);
|
|
@@ -602189,9 +602397,66 @@ function compactSourceId(source) {
|
|
|
602189
602397
|
return source.replace(/^\/dev\//, "");
|
|
602190
602398
|
}
|
|
602191
602399
|
function truncateCell(value2, width) {
|
|
602400
|
+
value2 = stripDashboardAnsi(String(value2 ?? "")).replace(/\r?\n/g, " ");
|
|
602192
602401
|
if (width <= 1) return value2.slice(0, Math.max(0, width));
|
|
602193
602402
|
return value2.length <= width ? value2.padEnd(width, " ") : `${value2.slice(0, Math.max(1, width - 1))}…`;
|
|
602194
602403
|
}
|
|
602404
|
+
function stripDashboardAnsi(value2) {
|
|
602405
|
+
return value2.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "");
|
|
602406
|
+
}
|
|
602407
|
+
function dashboardPreviewLines(camera) {
|
|
602408
|
+
const raw = camera.plainAscii || camera.ascii || "";
|
|
602409
|
+
return raw.replace(/\r/g, "").split("\n").map((line) => stripDashboardAnsi(line).replace(/\s+$/g, "")).filter((line) => line.trim().length > 0).slice(0, 10);
|
|
602410
|
+
}
|
|
602411
|
+
function centerDashboardCell(value2, width) {
|
|
602412
|
+
const text2 = stripDashboardAnsi(String(value2 ?? "")).replace(/\r?\n/g, " ");
|
|
602413
|
+
if (width <= 1) return text2.slice(0, Math.max(0, width));
|
|
602414
|
+
const clipped = text2.length > width ? `${text2.slice(0, Math.max(1, width - 1))}…` : text2;
|
|
602415
|
+
const left = Math.floor((width - clipped.length) / 2);
|
|
602416
|
+
return `${" ".repeat(Math.max(0, left))}${clipped}${" ".repeat(Math.max(0, width - clipped.length - left))}`;
|
|
602417
|
+
}
|
|
602418
|
+
function dashboardPreviewAspect(lines) {
|
|
602419
|
+
const widths = lines.map((line) => stripDashboardAnsi(line).length).filter((n2) => n2 > 0);
|
|
602420
|
+
const maxWidth = Math.max(1, ...widths);
|
|
602421
|
+
return Math.max(0.12, Math.min(1.6, lines.length / maxWidth));
|
|
602422
|
+
}
|
|
602423
|
+
function fitDashboardPane(lines, paneWidth, paneHeight) {
|
|
602424
|
+
const source = lines.length > 0 ? lines : ["preview pending"];
|
|
602425
|
+
const normalized = [];
|
|
602426
|
+
for (let i2 = 0; i2 < paneHeight; i2++) {
|
|
602427
|
+
const sourceIndex = source.length <= paneHeight ? i2 : Math.min(source.length - 1, Math.floor(i2 * source.length / paneHeight));
|
|
602428
|
+
normalized.push(truncateCell(source[sourceIndex] ?? "", paneWidth));
|
|
602429
|
+
}
|
|
602430
|
+
while (normalized.length < paneHeight) normalized.push(" ".repeat(paneWidth));
|
|
602431
|
+
return normalized;
|
|
602432
|
+
}
|
|
602433
|
+
function pushDashboardWrapped(lines, value2, width) {
|
|
602434
|
+
const contentWidth = Math.max(10, width - 2);
|
|
602435
|
+
const words = stripDashboardAnsi(value2).replace(/\s+/g, " ").trim().split(" ").filter(Boolean);
|
|
602436
|
+
if (words.length === 0) {
|
|
602437
|
+
lines.push(`│${" ".repeat(contentWidth)}│`);
|
|
602438
|
+
return;
|
|
602439
|
+
}
|
|
602440
|
+
let current = "";
|
|
602441
|
+
for (const word2 of words) {
|
|
602442
|
+
if (!current) {
|
|
602443
|
+
current = word2.length > contentWidth ? word2.slice(0, contentWidth) : word2;
|
|
602444
|
+
continue;
|
|
602445
|
+
}
|
|
602446
|
+
if (current.length + 1 + word2.length <= contentWidth) {
|
|
602447
|
+
current += ` ${word2}`;
|
|
602448
|
+
} else {
|
|
602449
|
+
lines.push(`│${truncateCell(` ${current}`, contentWidth)}│`);
|
|
602450
|
+
current = word2.length > contentWidth ? word2.slice(0, contentWidth) : word2;
|
|
602451
|
+
}
|
|
602452
|
+
}
|
|
602453
|
+
if (current) lines.push(`│${truncateCell(` ${current}`, contentWidth)}│`);
|
|
602454
|
+
}
|
|
602455
|
+
function isAudioFailureText(value2) {
|
|
602456
|
+
const text2 = String(value2 ?? "").trim();
|
|
602457
|
+
if (!text2) return false;
|
|
602458
|
+
return /^(?:ASR|VAD|Transcription)\s+(?:failed|unavailable)|No module named ['"]?transcribe_cli|torchcodec|torchaudio version/i.test(text2);
|
|
602459
|
+
}
|
|
602195
602460
|
function summarizeInference(value2) {
|
|
602196
602461
|
if (!value2) return "objects: pending";
|
|
602197
602462
|
const lines = value2.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
@@ -602224,38 +602489,54 @@ function formatLiveDashboardFromSnapshot(snapshot, opts = {}) {
|
|
|
602224
602489
|
if (cameras.length === 0) {
|
|
602225
602490
|
lines.push(`│${truncateCell(" no camera frames captured yet", width - 2)}│`);
|
|
602226
602491
|
}
|
|
602492
|
+
if (cameras.length > 0) {
|
|
602493
|
+
lines.push(`├${horizontal}┤`);
|
|
602494
|
+
const paneCount = Math.min(cameras.length, width >= 116 ? 3 : width >= 78 ? 2 : 1);
|
|
602495
|
+
const innerWidth = width - 2;
|
|
602496
|
+
const gutter = paneCount - 1;
|
|
602497
|
+
const paneWidth = Math.max(24, Math.floor((innerWidth - gutter) / paneCount));
|
|
602498
|
+
for (let start2 = 0; start2 < cameras.length; start2 += paneCount) {
|
|
602499
|
+
const group = cameras.slice(start2, start2 + paneCount);
|
|
602500
|
+
const sourceLines = group.map((camera) => dashboardPreviewLines(camera));
|
|
602501
|
+
const paneHeight = Math.max(7, Math.min(22, Math.round(paneWidth * Math.max(...sourceLines.map(dashboardPreviewAspect)))));
|
|
602502
|
+
const panes = sourceLines.map((previewLines) => fitDashboardPane(previewLines, paneWidth, paneHeight));
|
|
602503
|
+
for (let row = 0; row < paneHeight; row++) {
|
|
602504
|
+
const body = panes.map((pane) => pane[row] ?? " ".repeat(paneWidth)).join(" ");
|
|
602505
|
+
lines.push(`│${truncateCell(body, innerWidth)}│`);
|
|
602506
|
+
}
|
|
602507
|
+
const labels = group.map((camera) => {
|
|
602508
|
+
const age = Math.max(0, Math.round((now2 - camera.updatedAt) / 1e3));
|
|
602509
|
+
return centerDashboardCell(`${compactSourceId(camera.source)} age=${age}s`, paneWidth);
|
|
602510
|
+
}).join(" ");
|
|
602511
|
+
lines.push(`│${truncateCell(labels, innerWidth)}│`);
|
|
602512
|
+
}
|
|
602513
|
+
}
|
|
602514
|
+
if (cameras.length > 0) {
|
|
602515
|
+
lines.push(`├${horizontal}┤`);
|
|
602516
|
+
lines.push(`│${truncateCell(" camera observations", width - 2)}│`);
|
|
602517
|
+
}
|
|
602227
602518
|
for (const camera of cameras) {
|
|
602228
602519
|
const age = Math.max(0, Math.round((now2 - camera.updatedAt) / 1e3));
|
|
602229
602520
|
const rotation = camera.orientation ? formatCameraRotation(camera.orientation.rotation) : "upright/no correction";
|
|
602230
|
-
lines.push(`├${horizontal}┤`);
|
|
602231
|
-
lines.push(`│${truncateCell(` ${compactSourceId(camera.source)} age=${age}s rotation=${rotation}`, width - 2)}│`);
|
|
602232
|
-
const asciiLines = (camera.ascii ?? "").split("\n").filter((line) => line.length > 0).slice(0, 10);
|
|
602233
602521
|
const detailLines = [
|
|
602522
|
+
`${compactSourceId(camera.source)} age=${age}s rotation=${rotation}`,
|
|
602234
602523
|
cameraSnapshotSummary(camera),
|
|
602235
602524
|
camera.framePath ? `frame: ${camera.displayPath || camera.framePath}` : "",
|
|
602236
602525
|
camera.orientation?.evidence ? `orientation: ${trimOneLine(camera.orientation.evidence, 120)}` : ""
|
|
602237
602526
|
].filter(Boolean);
|
|
602238
|
-
|
|
602239
|
-
|
|
602240
|
-
lines.push(`│${truncateCell(` ${detail}`, width - 2)}│`);
|
|
602241
|
-
}
|
|
602242
|
-
continue;
|
|
602243
|
-
}
|
|
602244
|
-
const imageWidth = Math.max(24, Math.min(52, Math.floor((width - 5) * 0.58)));
|
|
602245
|
-
const detailWidth = Math.max(18, width - imageWidth - 5);
|
|
602246
|
-
const rowCount = Math.max(asciiLines.length, detailLines.length);
|
|
602247
|
-
for (let i2 = 0; i2 < rowCount; i2++) {
|
|
602248
|
-
const image = truncateCell(asciiLines[i2] ?? "", imageWidth);
|
|
602249
|
-
const detail = truncateCell(detailLines[i2] ?? "", detailWidth);
|
|
602250
|
-
lines.push(`│ ${image} │ ${detail}│`);
|
|
602527
|
+
for (const detail of detailLines.length ? detailLines : ["preview pending"]) {
|
|
602528
|
+
pushDashboardWrapped(lines, detail, width);
|
|
602251
602529
|
}
|
|
602252
602530
|
}
|
|
602253
602531
|
if (snapshot.audio) {
|
|
602254
602532
|
lines.push(`├${horizontal}┤`);
|
|
602533
|
+
const transcriptFailure = isAudioFailureText(snapshot.audio.transcript) ? snapshot.audio.transcript : "";
|
|
602534
|
+
const transcript = transcriptFailure ? "" : snapshot.audio.transcript;
|
|
602535
|
+
const audioError = [snapshot.audio.error, transcriptFailure].filter(Boolean).join(" | ");
|
|
602255
602536
|
const audioBits = [
|
|
602256
602537
|
`audio input=${snapshot.audio.input || snapshot.config.selectedAudioInput || "none"}`,
|
|
602257
|
-
|
|
602258
|
-
|
|
602538
|
+
audioError ? `error=${trimOneLine(audioError, 120)}` : "",
|
|
602539
|
+
transcript ? `asr=${trimOneLine(transcript, 120)}` : "",
|
|
602259
602540
|
snapshot.audio.analysis ? `sound=${trimOneLine(snapshot.audio.analysis, 120)}` : ""
|
|
602260
602541
|
].filter(Boolean);
|
|
602261
602542
|
for (const item of audioBits.slice(0, 4)) lines.push(`│${truncateCell(` ${item}`, width - 2)}│`);
|
|
@@ -602607,6 +602888,9 @@ function formatLiveSensorContextFromSnapshot(snapshot, opts = {}) {
|
|
|
602607
602888
|
}
|
|
602608
602889
|
}
|
|
602609
602890
|
if (snapshot.audio) {
|
|
602891
|
+
const transcriptFailure = isAudioFailureText(snapshot.audio.transcript) ? snapshot.audio.transcript : "";
|
|
602892
|
+
const transcript = transcriptFailure ? "" : snapshot.audio.transcript;
|
|
602893
|
+
const audioError = [snapshot.audio.error, transcriptFailure].filter(Boolean).join(" | ");
|
|
602610
602894
|
const audioEvents = (snapshot.events ?? []).filter((event) => event.kind === "audio_transcript" || event.kind === "audio_sound").sort((a2, b) => b.observedAt - a2.observedAt).slice(0, 8);
|
|
602611
602895
|
if (audioEvents.length > 0) {
|
|
602612
602896
|
lines.push("");
|
|
@@ -602623,11 +602907,11 @@ function formatLiveSensorContextFromSnapshot(snapshot, opts = {}) {
|
|
|
602623
602907
|
lines.push("");
|
|
602624
602908
|
lines.push("## LIVE AUDIO LATEST SAMPLE");
|
|
602625
602909
|
lines.push(`timestamp: ${nowIso3(snapshot.audio.updatedAt)} age=${Math.max(0, Math.round(age / 1e3))}s${age > maxAgeMs ? " STALE" : ""}`);
|
|
602626
|
-
if (
|
|
602910
|
+
if (audioError) lines.push(`error: ${audioError}`);
|
|
602627
602911
|
if (snapshot.audio.recordingPath) lines.push(`recording: ${snapshot.audio.recordingPath}`);
|
|
602628
|
-
if (
|
|
602912
|
+
if (transcript) {
|
|
602629
602913
|
lines.push("Live ASR:");
|
|
602630
|
-
lines.push(cleanPreview(
|
|
602914
|
+
lines.push(cleanPreview(transcript, 1200));
|
|
602631
602915
|
}
|
|
602632
602916
|
if (snapshot.audio.analysis) {
|
|
602633
602917
|
lines.push("Live sound analysis:");
|
|
@@ -603195,7 +603479,8 @@ var init_live_sensors = __esm({
|
|
|
603195
603479
|
const framePath = extractSavedImagePath(result.output, this.repoRoot);
|
|
603196
603480
|
if (!framePath) return { ok: false, message: "Camera capture succeeded but no saved image path was returned." };
|
|
603197
603481
|
const displayPath = relative11(this.repoRoot, framePath).startsWith("..") ? framePath : relative11(this.repoRoot, framePath);
|
|
603198
|
-
const
|
|
603482
|
+
const previewWidth = Math.max(48, Math.min(96, (process.stdout.columns || 100) - 14));
|
|
603483
|
+
const preview = await buildImageAsciiPreview(framePath, { width: previewWidth });
|
|
603199
603484
|
const asciiContext = preview ? formatImageAsciiContext(preview, displayPath) : void 0;
|
|
603200
603485
|
const observedAt = Date.now();
|
|
603201
603486
|
const cameraView = {
|
|
@@ -603204,6 +603489,7 @@ var init_live_sensors = __esm({
|
|
|
603204
603489
|
framePath,
|
|
603205
603490
|
displayPath,
|
|
603206
603491
|
ascii: preview?.ascii,
|
|
603492
|
+
plainAscii: preview?.plainAscii,
|
|
603207
603493
|
renderer: preview?.renderer,
|
|
603208
603494
|
asciiContext,
|
|
603209
603495
|
rotation,
|
|
@@ -603401,6 +603687,7 @@ ${output}`).join("\n\n");
|
|
|
603401
603687
|
const recordingPath = join124(outputDir2, `audio-${Date.now()}.wav`);
|
|
603402
603688
|
let transcript = "";
|
|
603403
603689
|
let analysis = "";
|
|
603690
|
+
const audioErrors = [];
|
|
603404
603691
|
const capture = await recordAudioSampleWithRecovery(input, this.devices.audioInputs, 3, recordingPath);
|
|
603405
603692
|
if (!capture.ok) {
|
|
603406
603693
|
const message2 = `Audio capture failed from ${input}; tried fallbacks: ${capture.errors.slice(0, 5).join(" | ")}`;
|
|
@@ -603426,9 +603713,13 @@ ${output}`).join("\n\n");
|
|
|
603426
603713
|
if (this.config.asrEnabled) {
|
|
603427
603714
|
try {
|
|
603428
603715
|
const asr = await new TranscribeFileTool(this.repoRoot).execute({ path: recordingPath, model: "tiny" });
|
|
603429
|
-
|
|
603716
|
+
if (asr.success) {
|
|
603717
|
+
transcript = cleanPreview(typeof asr.llmContent === "string" ? asr.llmContent : "", 1600);
|
|
603718
|
+
} else {
|
|
603719
|
+
audioErrors.push(`ASR unavailable: ${asr.error || asr.output || "unknown error"}`);
|
|
603720
|
+
}
|
|
603430
603721
|
} catch (err) {
|
|
603431
|
-
|
|
603722
|
+
audioErrors.push(`ASR unavailable: ${err instanceof Error ? err.message : String(err)}`);
|
|
603432
603723
|
}
|
|
603433
603724
|
}
|
|
603434
603725
|
if (this.config.audioAnalysisEnabled) {
|
|
@@ -603442,9 +603733,10 @@ ${output}`).join("\n\n");
|
|
|
603442
603733
|
}
|
|
603443
603734
|
try {
|
|
603444
603735
|
const vad = await analyzer.execute({ action: "vad", file: recordingPath });
|
|
603445
|
-
|
|
603736
|
+
if (vad.success) parts.push(cleanPreview(vad.output, 700));
|
|
603737
|
+
else audioErrors.push(`VAD unavailable: ${vad.error || vad.output || "unknown error"}`);
|
|
603446
603738
|
} catch (err) {
|
|
603447
|
-
|
|
603739
|
+
audioErrors.push(`VAD unavailable: ${err instanceof Error ? err.message : String(err)}`);
|
|
603448
603740
|
}
|
|
603449
603741
|
analysis = parts.filter(Boolean).join("\n");
|
|
603450
603742
|
}
|
|
@@ -603454,7 +603746,8 @@ ${output}`).join("\n\n");
|
|
|
603454
603746
|
output: this.config.selectedAudioOutput,
|
|
603455
603747
|
recordingPath,
|
|
603456
603748
|
transcript,
|
|
603457
|
-
analysis
|
|
603749
|
+
analysis,
|
|
603750
|
+
error: audioErrors.length > 0 ? audioErrors.join("\n") : void 0
|
|
603458
603751
|
};
|
|
603459
603752
|
const audioEvents = [];
|
|
603460
603753
|
if (transcript) {
|
|
@@ -655292,12 +655585,17 @@ function renderLiveFeedback(ctx3, manager, feedback) {
|
|
|
655292
655585
|
return;
|
|
655293
655586
|
}
|
|
655294
655587
|
const stamp = new Date(feedback.observedAt).toISOString();
|
|
655588
|
+
const explicitImagePreview = (feedback.kind === "camera-frame" || feedback.kind === "face-crop") && feedback.ascii && feedback.displayPath && feedback.renderer;
|
|
655589
|
+
if (ctx3.liveDynamicBlockHost && !explicitImagePreview) {
|
|
655590
|
+
renderLiveDashboard(ctx3, manager);
|
|
655591
|
+
return;
|
|
655592
|
+
}
|
|
655295
655593
|
if (feedback.kind === "error") {
|
|
655296
655594
|
renderWarning(`[live ${stamp}] ${feedback.title}
|
|
655297
655595
|
${feedback.message}`);
|
|
655298
655596
|
return;
|
|
655299
655597
|
}
|
|
655300
|
-
if (
|
|
655598
|
+
if (explicitImagePreview && feedback.displayPath && feedback.ascii && feedback.renderer) {
|
|
655301
655599
|
renderInfo(`[live ${stamp}] ${feedback.message}`);
|
|
655302
655600
|
renderImageAsciiPreview(feedback.title, feedback.displayPath, feedback.ascii, feedback.renderer);
|
|
655303
655601
|
return;
|
|
@@ -733836,6 +734134,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
733836
734134
|
} else {
|
|
733837
734135
|
parts.push("active: no");
|
|
733838
734136
|
}
|
|
734137
|
+
const liveContext = formatLiveSensorContext(repoRoot);
|
|
734138
|
+
if (liveContext) parts.push(liveContext);
|
|
733839
734139
|
return parts.join("\n");
|
|
733840
734140
|
}
|
|
733841
734141
|
},
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.409",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omnius",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.409",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
package/package.json
CHANGED