dsh-pf-stream 0.2.4 → 0.3.1
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.en.md +171 -34
- package/README.md +168 -31
- package/client.js +1193 -0
- package/icon.svg +18 -0
- package/lib/asr/catalog.d.ts +74 -0
- package/lib/asr/catalog.js +168 -0
- package/lib/asr/catalog.js.map +1 -0
- package/lib/asr/detect.d.ts +33 -0
- package/lib/asr/detect.js +117 -0
- package/lib/asr/detect.js.map +1 -0
- package/lib/asr/engine.d.ts +43 -0
- package/lib/asr/engine.js +143 -0
- package/lib/asr/engine.js.map +1 -0
- package/lib/asr/install.d.ts +56 -0
- package/lib/asr/install.js +317 -0
- package/lib/asr/install.js.map +1 -0
- package/lib/asr/verify.d.ts +22 -0
- package/lib/asr/verify.js +174 -0
- package/lib/asr/verify.js.map +1 -0
- package/lib/audio/acousticVad.d.ts +45 -0
- package/lib/audio/acousticVad.js +179 -0
- package/lib/audio/acousticVad.js.map +1 -0
- package/lib/audio/asrProviders.d.ts +51 -0
- package/lib/audio/asrProviders.js +251 -0
- package/lib/audio/asrProviders.js.map +1 -0
- package/lib/audio/asrRouter.d.ts +30 -0
- package/lib/audio/asrRouter.js +187 -0
- package/lib/audio/asrRouter.js.map +1 -0
- package/lib/audio/hallucinationGuard.d.ts +18 -0
- package/lib/audio/hallucinationGuard.js +97 -0
- package/lib/audio/hallucinationGuard.js.map +1 -0
- package/lib/audio/sidecar.d.ts +76 -0
- package/lib/audio/sidecar.js +362 -0
- package/lib/audio/sidecar.js.map +1 -0
- package/lib/audio/subtitleExtractor.d.ts +36 -0
- package/lib/audio/subtitleExtractor.js +218 -0
- package/lib/audio/subtitleExtractor.js.map +1 -0
- package/lib/audio/transcriptCache.d.ts +33 -0
- package/lib/audio/transcriptCache.js +126 -0
- package/lib/audio/transcriptCache.js.map +1 -0
- package/lib/audio/types.d.ts +136 -0
- package/lib/audio/types.js +10 -0
- package/lib/audio/types.js.map +1 -0
- package/lib/host/api.d.ts +23 -0
- package/lib/host/api.js +286 -0
- package/lib/host/api.js.map +1 -0
- package/lib/host/runtime.d.ts +167 -0
- package/lib/host/runtime.js +335 -0
- package/lib/host/runtime.js.map +1 -0
- package/lib/index.d.ts +229 -1
- package/lib/index.js +103 -2
- package/lib/index.js.map +1 -1
- package/lib/session/state.js +4 -0
- package/lib/session/state.js.map +1 -1
- package/lib/stage0/decoder.d.ts +1 -9
- package/lib/stage0/decoder.js +15 -45
- package/lib/stage0/decoder.js.map +1 -1
- package/lib/stage2/stateMachine.d.ts +4 -1
- package/lib/stage2/stateMachine.js +7 -1
- package/lib/stage2/stateMachine.js.map +1 -1
- package/lib/stage3/deterministicRouter.js +3 -3
- package/lib/stage3/deterministicRouter.js.map +1 -1
- package/lib/stage3/streamSampler.d.ts +9 -2
- package/lib/stage3/streamSampler.js +37 -16
- package/lib/stage3/streamSampler.js.map +1 -1
- package/lib/stage6/history.d.ts +2 -1
- package/lib/stage6/history.js +4 -1
- package/lib/stage6/history.js.map +1 -1
- package/lib/tool/handler.d.ts +9 -0
- package/lib/tool/handler.js +33 -3
- package/lib/tool/handler.js.map +1 -1
- package/lib/tool/schema.js +15 -2
- package/lib/tool/schema.js.map +1 -1
- package/lib/tool/streamCall.d.ts +11 -0
- package/lib/tool/streamCall.js +122 -9
- package/lib/tool/streamCall.js.map +1 -1
- package/lib/types.d.ts +9 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +23 -2
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ASR 路由:缓存缺口 → 切分 → 切片编码 → provider(verbose 优先,
|
|
3
|
+
* 400 拒绝时降级 basic)→ PTS 锚定 → 幻觉清洗 → 缓存回写。
|
|
4
|
+
*
|
|
5
|
+
* 失败语义:单块失败计入 failedChunks(partial),不中断其余块;
|
|
6
|
+
* verbose 被兼容端拒绝时整窗自动降级 basic(VAD 岛切分 + 整块文本锚定)。
|
|
7
|
+
*/
|
|
8
|
+
import { planChunks, planIslandChunks, sliceAudio, } from './acousticVad.js';
|
|
9
|
+
import { transcribeBasic, transcribeVerbose, AsrRequestError } from './asrProviders.js';
|
|
10
|
+
import { guardSegments } from './hallucinationGuard.js';
|
|
11
|
+
import { cachedSegmentsFor, engineFingerprint, mergeInterval, missingRanges, videoFingerprint, } from './transcriptCache.js';
|
|
12
|
+
async function runChunks(videoPath, chunks, provider, options) {
|
|
13
|
+
const outcomes = [];
|
|
14
|
+
let failed = 0;
|
|
15
|
+
let requests = 0;
|
|
16
|
+
let verboseRejected = false;
|
|
17
|
+
const maxInFlight = Math.max(1, options.settings.maxConcurrency);
|
|
18
|
+
let cursor = 0;
|
|
19
|
+
const workers = [];
|
|
20
|
+
const vadOpts = { ffmpegPath: options.ffmpegPath, signal: options.signal };
|
|
21
|
+
const runOne = async () => {
|
|
22
|
+
for (;;) {
|
|
23
|
+
const index = cursor++;
|
|
24
|
+
if (index >= chunks.length)
|
|
25
|
+
return;
|
|
26
|
+
const range = chunks[index];
|
|
27
|
+
if (range === undefined)
|
|
28
|
+
return;
|
|
29
|
+
try {
|
|
30
|
+
requests++;
|
|
31
|
+
const audio = await sliceAudio(videoPath, range, options.sliceCodec, vadOpts);
|
|
32
|
+
const input = {
|
|
33
|
+
startMs: range[0],
|
|
34
|
+
endMs: range[1],
|
|
35
|
+
bytes: audio.bytes,
|
|
36
|
+
mimeType: audio.mimeType,
|
|
37
|
+
};
|
|
38
|
+
let raw;
|
|
39
|
+
if (provider === 'openai_verbose') {
|
|
40
|
+
try {
|
|
41
|
+
raw = await transcribeVerbose(input, { settings: options.settings, signal: options.signal });
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (error instanceof AsrRequestError && error.code === 'ASR_VERBOSE_REJECTED') {
|
|
45
|
+
verboseRejected = true;
|
|
46
|
+
raw = await transcribeBasic(input, { settings: options.settings, signal: options.signal });
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else if (provider === 'openai_basic') {
|
|
54
|
+
raw = await transcribeBasic(input, { settings: options.settings, signal: options.signal });
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const { transcribeLocalCli } = await import('./asrProviders.js');
|
|
58
|
+
raw = await transcribeLocalCli(input, { settings: options.settings, signal: options.signal }, options.tempDir);
|
|
59
|
+
}
|
|
60
|
+
outcomes.push({ range, raw, anchorStartMs: range[0] });
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
failed++;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
for (let i = 0; i < Math.min(maxInFlight, chunks.length); i++)
|
|
68
|
+
workers.push(runOne());
|
|
69
|
+
await Promise.all(workers);
|
|
70
|
+
return { outcomes, failed, requests, verboseRejected };
|
|
71
|
+
}
|
|
72
|
+
/** 相对毫秒 → 绝对 PTS 毫秒(clamp 到块区间)。 */
|
|
73
|
+
function anchor(outcome) {
|
|
74
|
+
const span = outcome.range[1] - outcome.range[0];
|
|
75
|
+
return outcome.raw
|
|
76
|
+
.map((r) => ({
|
|
77
|
+
segId: 0,
|
|
78
|
+
startMs: outcome.anchorStartMs + Math.max(0, Math.min(span, r.startMs)),
|
|
79
|
+
endMs: outcome.anchorStartMs + Math.max(0, Math.min(span, r.endMs)),
|
|
80
|
+
text: r.text,
|
|
81
|
+
source: 'asr',
|
|
82
|
+
noSpeechProb: r.noSpeechProb,
|
|
83
|
+
avgLogprob: r.avgLogprob,
|
|
84
|
+
compressionRatio: r.compressionRatio,
|
|
85
|
+
}))
|
|
86
|
+
.filter((s) => s.endMs > s.startMs && s.text.length > 0);
|
|
87
|
+
}
|
|
88
|
+
export async function transcribeWindow(videoPath, window, vad, options) {
|
|
89
|
+
const fingerprint = `${await videoFingerprint(videoPath)}-${engineFingerprint(options.settings)}`;
|
|
90
|
+
let intervals = [];
|
|
91
|
+
let cacheHit = false;
|
|
92
|
+
if (options.cacheEnabled) {
|
|
93
|
+
const { readTranscriptCache, writeTranscriptCache } = await import('./transcriptCache.js');
|
|
94
|
+
intervals = (await readTranscriptCache(options.cacheDir, fingerprint)) ?? [];
|
|
95
|
+
cacheHit = intervals.length > 0;
|
|
96
|
+
const gaps = missingRanges(intervals, window);
|
|
97
|
+
if (gaps.length === 0 || gaps.every(([a, b]) => b - a <= 500)) {
|
|
98
|
+
const cached = cachedSegmentsFor(intervals, window);
|
|
99
|
+
return {
|
|
100
|
+
segments: cached,
|
|
101
|
+
failedChunks: 0,
|
|
102
|
+
requests: 0,
|
|
103
|
+
droppedByGuard: 0,
|
|
104
|
+
cacheHit,
|
|
105
|
+
degradedToBasic: false,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const chunks = planChunksFor(gaps, vad);
|
|
109
|
+
const result = await runChunks(videoPath, chunks, options.settings.provider, options);
|
|
110
|
+
let segments = [];
|
|
111
|
+
let droppedByGuard = 0;
|
|
112
|
+
for (const outcome of result.outcomes.sort((a, b) => a.anchorStartMs - b.anchorStartMs)) {
|
|
113
|
+
const anchored = anchor(outcome);
|
|
114
|
+
const guarded = guardSegments(anchored, vad);
|
|
115
|
+
droppedByGuard += guarded.dropped;
|
|
116
|
+
segments = segments.concat(guarded.segments);
|
|
117
|
+
}
|
|
118
|
+
// 缓存记录锚定后的段(清洗前锚定,清洗后回写)——以清洗后为准,保证幂等
|
|
119
|
+
for (const outcome of result.outcomes.sort((a, b) => a.anchorStartMs - b.anchorStartMs)) {
|
|
120
|
+
const guarded = guardSegments(anchor(outcome), vad);
|
|
121
|
+
if (guarded.segments.length > 0 || outcome.range[1] > outcome.range[0]) {
|
|
122
|
+
intervals = mergeInterval(intervals, {
|
|
123
|
+
startMs: outcome.range[0],
|
|
124
|
+
endMs: outcome.range[1],
|
|
125
|
+
source: 'asr',
|
|
126
|
+
segments: guarded.segments.map((s, i) => ({ ...s, segId: i + 1 })),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
await writeTranscriptCache(options.cacheDir, fingerprint, intervals).catch(() => undefined);
|
|
131
|
+
const merged = cachedSegmentsFor(intervals, window);
|
|
132
|
+
return {
|
|
133
|
+
segments: merged.length > 0 ? merged : segments,
|
|
134
|
+
failedChunks: result.failed,
|
|
135
|
+
requests: result.requests,
|
|
136
|
+
droppedByGuard,
|
|
137
|
+
cacheHit,
|
|
138
|
+
degradedToBasic: result.verboseRejected,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
// 无缓存路径:整窗直转
|
|
142
|
+
const chunks = planChunksFor([window], vad);
|
|
143
|
+
const result = await runChunks(videoPath, chunks, options.settings.provider, options);
|
|
144
|
+
let segments = [];
|
|
145
|
+
let droppedByGuard = 0;
|
|
146
|
+
for (const outcome of result.outcomes.sort((a, b) => a.anchorStartMs - b.anchorStartMs)) {
|
|
147
|
+
const guarded = guardSegments(anchor(outcome), vad);
|
|
148
|
+
droppedByGuard += guarded.dropped;
|
|
149
|
+
segments = segments.concat(guarded.segments);
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
segments,
|
|
153
|
+
failedChunks: result.failed,
|
|
154
|
+
requests: result.requests,
|
|
155
|
+
droppedByGuard,
|
|
156
|
+
cacheHit: false,
|
|
157
|
+
degradedToBasic: result.verboseRejected,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function planChunksFor(ranges, vad) {
|
|
161
|
+
const out = [];
|
|
162
|
+
for (const range of ranges) {
|
|
163
|
+
out.push(...planChunks(range, vad));
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
/** basic/无时间戳 provider 的岛切分包装。 */
|
|
168
|
+
export async function transcribeWindowByIslands(videoPath, window, vad, options) {
|
|
169
|
+
const islands = planIslandChunks(window, vad);
|
|
170
|
+
const result = await runChunks(videoPath, islands, options.settings.provider, options);
|
|
171
|
+
let segments = [];
|
|
172
|
+
let droppedByGuard = 0;
|
|
173
|
+
for (const outcome of result.outcomes.sort((a, b) => a.anchorStartMs - b.anchorStartMs)) {
|
|
174
|
+
const guarded = guardSegments(anchor(outcome), vad);
|
|
175
|
+
droppedByGuard += guarded.dropped;
|
|
176
|
+
segments = segments.concat(guarded.segments);
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
segments,
|
|
180
|
+
failedChunks: result.failed,
|
|
181
|
+
requests: result.requests,
|
|
182
|
+
droppedByGuard,
|
|
183
|
+
cacheHit: false,
|
|
184
|
+
degradedToBasic: false,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=asrRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asrRouter.js","sourceRoot":"","sources":["../../src/audio/asrRouter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ASR 幻觉清洗(四重,按序执行)。
|
|
3
|
+
*
|
|
4
|
+
* 1. 能量前置:完全落在 VAD 静音区(±100ms 余量)的段剔除;
|
|
5
|
+
* 2. 置信度门控:no_speech_prob>0.65 且 avg_logprob<-0.8,或 compression_ratio>2.4 剔除;
|
|
6
|
+
* 3. n-gram 复读折叠:单字/单词连续 ≥3 次折叠为一次,整段复读剔除;
|
|
7
|
+
* 4. 黑名单:字幕组/平台水印仅在「静音区命中」或「短独立句」时精准拦截。
|
|
8
|
+
*/
|
|
9
|
+
import type { TranscriptSegment, VadResult } from './types.js';
|
|
10
|
+
export interface GuardResult {
|
|
11
|
+
segments: TranscriptSegment[];
|
|
12
|
+
dropped: number;
|
|
13
|
+
}
|
|
14
|
+
/** 单字符(CJK)与拉丁词的连续复读折叠。 */
|
|
15
|
+
export declare function foldRepeats(text: string): string | null;
|
|
16
|
+
export declare function guardSegments(segments: TranscriptSegment[], vad: VadResult | null): GuardResult;
|
|
17
|
+
/** 语速(字符/秒):去空白字符数 ÷ 语音岛总时长。 */
|
|
18
|
+
export declare function speechRateCps(segments: TranscriptSegment[], vad: VadResult | null): number | null;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ASR 幻觉清洗(四重,按序执行)。
|
|
3
|
+
*
|
|
4
|
+
* 1. 能量前置:完全落在 VAD 静音区(±100ms 余量)的段剔除;
|
|
5
|
+
* 2. 置信度门控:no_speech_prob>0.65 且 avg_logprob<-0.8,或 compression_ratio>2.4 剔除;
|
|
6
|
+
* 3. n-gram 复读折叠:单字/单词连续 ≥3 次折叠为一次,整段复读剔除;
|
|
7
|
+
* 4. 黑名单:字幕组/平台水印仅在「静音区命中」或「短独立句」时精准拦截。
|
|
8
|
+
*/
|
|
9
|
+
const CONF_NO_SPEECH = 0.65;
|
|
10
|
+
const CONF_LOGPROB = -0.8;
|
|
11
|
+
const CONF_COMPRESSION = 2.4;
|
|
12
|
+
const BLOCKLIST = [
|
|
13
|
+
'字幕由',
|
|
14
|
+
'字幕制作',
|
|
15
|
+
'amara.org',
|
|
16
|
+
'amara',
|
|
17
|
+
'请不吝点赞',
|
|
18
|
+
'订阅频道',
|
|
19
|
+
'关注订阅',
|
|
20
|
+
'thank you for watching',
|
|
21
|
+
'thanks for watching',
|
|
22
|
+
'仅供学习',
|
|
23
|
+
'供学习交流',
|
|
24
|
+
'benefitted from',
|
|
25
|
+
];
|
|
26
|
+
/** 相对静音判定:段与任一静音区重叠比例 ≥80%。 */
|
|
27
|
+
function inSilence(seg, silence) {
|
|
28
|
+
if (silence.length === 0)
|
|
29
|
+
return false;
|
|
30
|
+
for (const [a, b] of silence) {
|
|
31
|
+
const s = Math.max(seg.startMs, a - 100);
|
|
32
|
+
const e = Math.min(seg.endMs, b + 100);
|
|
33
|
+
if (e > s && e - s >= 0.8 * (seg.endMs - seg.startMs))
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
function confidenceFail(seg) {
|
|
39
|
+
if (seg.noSpeechProb !== undefined && seg.avgLogprob !== undefined) {
|
|
40
|
+
if (seg.noSpeechProb > CONF_NO_SPEECH && seg.avgLogprob < CONF_LOGPROB)
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (seg.compressionRatio !== undefined && seg.compressionRatio > CONF_COMPRESSION)
|
|
44
|
+
return true;
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
/** 单字符(CJK)与拉丁词的连续复读折叠。 */
|
|
48
|
+
export function foldRepeats(text) {
|
|
49
|
+
const cjk = text.replace(/([\u4e00-\u9fff])\1{2,}/g, '$1');
|
|
50
|
+
const latin = cjk.replace(/\b(\w+)(\s+\1\b){2,}/gi, '$1');
|
|
51
|
+
// 折叠后空文本 → 整段复读
|
|
52
|
+
if (latin.replace(/[\s,.\u3002\uff0c!?!?]/g, '').length === 0)
|
|
53
|
+
return null;
|
|
54
|
+
return latin;
|
|
55
|
+
}
|
|
56
|
+
function blocklistHit(seg, silence) {
|
|
57
|
+
const hit = BLOCKLIST.find((w) => seg.text.toLowerCase().includes(w));
|
|
58
|
+
if (!hit)
|
|
59
|
+
return false;
|
|
60
|
+
return inSilence(seg, silence) || seg.text.length <= 40;
|
|
61
|
+
}
|
|
62
|
+
export function guardSegments(segments, vad) {
|
|
63
|
+
const silence = vad?.silence ?? [];
|
|
64
|
+
const kept = [];
|
|
65
|
+
let dropped = 0;
|
|
66
|
+
for (const seg of segments) {
|
|
67
|
+
if (inSilence(seg, silence)) {
|
|
68
|
+
dropped++;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (confidenceFail(seg)) {
|
|
72
|
+
dropped++;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const folded = foldRepeats(seg.text);
|
|
76
|
+
if (folded === null) {
|
|
77
|
+
dropped++;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const candidate = { ...seg, text: folded };
|
|
81
|
+
if (blocklistHit(candidate, silence)) {
|
|
82
|
+
dropped++;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
kept.push(candidate);
|
|
86
|
+
}
|
|
87
|
+
return { segments: kept, dropped };
|
|
88
|
+
}
|
|
89
|
+
/** 语速(字符/秒):去空白字符数 ÷ 语音岛总时长。 */
|
|
90
|
+
export function speechRateCps(segments, vad) {
|
|
91
|
+
const speechMs = vad ? vad.islands.reduce((acc, [a, b]) => acc + (b - a), 0) : 0;
|
|
92
|
+
if (speechMs <= 0 || segments.length === 0)
|
|
93
|
+
return null;
|
|
94
|
+
const chars = segments.reduce((acc, s) => acc + s.text.replace(/\s/g, '').length, 0);
|
|
95
|
+
return chars / (speechMs / 1000);
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=hallucinationGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hallucinationGuard.js","sourceRoot":"","sources":["../../src/audio/hallucinationGuard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio Sidecar 门面:三级获取顺位(字幕 → VAD+ASR → 跳过)、
|
|
3
|
+
* 软截止并行编排、画布包挂载与提示行生成。
|
|
4
|
+
*
|
|
5
|
+
* 铁律:任何音频路径异常都折叠为 status='error'/'timeout_skipped',
|
|
6
|
+
* 不向视觉主链路抛错;无音轨时视觉输出与无本模块时逐字节一致。
|
|
7
|
+
*/
|
|
8
|
+
import { type AsrRuntimeFacts } from '../asr/engine.js';
|
|
9
|
+
import type { AudioContextSummary, AudioPluginConfig, AudioSourceKind, AudioSettings, AudioStatus, PacketAudioMount, TranscriptSegment, VadResult } from './types.js';
|
|
10
|
+
import type { ProbeResult, IntentDirective } from '../types.js';
|
|
11
|
+
export declare const ASSIST_FOCUS_CONSTANTS: {
|
|
12
|
+
staticMs: number;
|
|
13
|
+
sinceFMs: number;
|
|
14
|
+
pauseAfterIslandMs: number;
|
|
15
|
+
islandRecentMs: number;
|
|
16
|
+
denseIslandMs: number;
|
|
17
|
+
denseCps: number;
|
|
18
|
+
minSumD: number;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* env(DSH_ASR_API_KEY)> 凭据存储 > Config;引擎按 engine 语义解析
|
|
22
|
+
* (auto:旧 provider → 云端密钥 → 本地引擎 → 未配置)。
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveAudioSettings(config: AudioPluginConfig, intent: IntentDirective | undefined, env: NodeJS.ProcessEnv, facts?: AsrRuntimeFacts | undefined): AudioSettings;
|
|
25
|
+
export interface SidecarDeps {
|
|
26
|
+
videoPath: string;
|
|
27
|
+
probe: ProbeResult;
|
|
28
|
+
ffmpegPath: string;
|
|
29
|
+
settings: AudioSettings;
|
|
30
|
+
tempDir?: string | undefined;
|
|
31
|
+
signal?: AbortSignal | undefined;
|
|
32
|
+
/** 调用方预扫的 VAD 结果(assistFocus 前置扫描复用;null 表示无)。 */
|
|
33
|
+
precomputedVad?: VadResult | null | undefined;
|
|
34
|
+
}
|
|
35
|
+
export interface SidecarResult {
|
|
36
|
+
context: AudioContextSummary;
|
|
37
|
+
/** 窗口内全部台词段(时间序)。 */
|
|
38
|
+
segments: TranscriptSegment[];
|
|
39
|
+
/** assistFocus 判定输入(窗口绝对 PTS 语音岛 + 语速)。 */
|
|
40
|
+
islands: Array<[number, number]>;
|
|
41
|
+
speechRate: number | null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 窗口音频上下文(三级顺位)。
|
|
45
|
+
*
|
|
46
|
+
* deadlineAt 为墙钟时刻(Date.now()):到达软截止仍有未完成块时返回
|
|
47
|
+
* timeout_skipped/partial,后台继续补缓存(fire-and-forget)。
|
|
48
|
+
*/
|
|
49
|
+
export declare function runAudioSidecar(deps: SidecarDeps, window: [number, number], deadlineAt: number): Promise<SidecarResult>;
|
|
50
|
+
export interface PacketWindow {
|
|
51
|
+
packetId: number;
|
|
52
|
+
startMs: number;
|
|
53
|
+
endMs: number;
|
|
54
|
+
unitIds: Array<{
|
|
55
|
+
globalId: number;
|
|
56
|
+
timestampMs: number;
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
59
|
+
/** ±300ms 交集 + 重叠最大归属;跨包段的第二副本加 (cont.) 前缀。 */
|
|
60
|
+
export declare function mountSegments(packets: PacketWindow[], segments: TranscriptSegment[], status: AudioStatus, source: AudioSourceKind | null, language: string | null): Map<number, PacketAudioMount>;
|
|
61
|
+
/** 提示行:`Audio @Packet #N: [12.1s-12.9s] "台词" | …(+2 more)`。 */
|
|
62
|
+
export declare function audioHintLine(packetId: number, mount: PacketAudioMount): string;
|
|
63
|
+
/** 冷区引用行:`[Audio@#N] K segment(s) retained`。 */
|
|
64
|
+
export declare function coldRefAudioHintLine(sourcePacketId: number, count: number): string;
|
|
65
|
+
export interface AssistContext {
|
|
66
|
+
/** 窗口绝对 PTS 语音岛。 */
|
|
67
|
+
islands: Array<[number, number]>;
|
|
68
|
+
speechRate: number | null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 触发条件(全部满足):
|
|
72
|
+
* STATIC >10s;距上一张 F >3s;Σd_t(自上 F) >0.15;
|
|
73
|
+
* 存在密集语音岛(≥2s 或语速 >5cps),岛结束后 0.4s~5s 处于停顿谷底。
|
|
74
|
+
*/
|
|
75
|
+
export declare function assistFocusShouldFire(ctx: AssistContext, tMs: number, staticSinceMs: number, lastFMs: number | null, sumD: number, firedIslandEnd: number | null): number | null;
|
|
76
|
+
export declare function sourceLabel(source: AudioSourceKind | null, language: string | null): string;
|