dsh-pf-stream 0.2.4 → 0.3.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.
Files changed (80) hide show
  1. package/README.en.md +145 -33
  2. package/README.md +142 -30
  3. package/client.js +1156 -0
  4. package/icon.svg +18 -0
  5. package/lib/asr/catalog.d.ts +74 -0
  6. package/lib/asr/catalog.js +168 -0
  7. package/lib/asr/catalog.js.map +1 -0
  8. package/lib/asr/detect.d.ts +33 -0
  9. package/lib/asr/detect.js +117 -0
  10. package/lib/asr/detect.js.map +1 -0
  11. package/lib/asr/engine.d.ts +43 -0
  12. package/lib/asr/engine.js +143 -0
  13. package/lib/asr/engine.js.map +1 -0
  14. package/lib/asr/install.d.ts +56 -0
  15. package/lib/asr/install.js +317 -0
  16. package/lib/asr/install.js.map +1 -0
  17. package/lib/asr/verify.d.ts +22 -0
  18. package/lib/asr/verify.js +174 -0
  19. package/lib/asr/verify.js.map +1 -0
  20. package/lib/audio/acousticVad.d.ts +45 -0
  21. package/lib/audio/acousticVad.js +179 -0
  22. package/lib/audio/acousticVad.js.map +1 -0
  23. package/lib/audio/asrProviders.d.ts +51 -0
  24. package/lib/audio/asrProviders.js +251 -0
  25. package/lib/audio/asrProviders.js.map +1 -0
  26. package/lib/audio/asrRouter.d.ts +30 -0
  27. package/lib/audio/asrRouter.js +187 -0
  28. package/lib/audio/asrRouter.js.map +1 -0
  29. package/lib/audio/hallucinationGuard.d.ts +18 -0
  30. package/lib/audio/hallucinationGuard.js +97 -0
  31. package/lib/audio/hallucinationGuard.js.map +1 -0
  32. package/lib/audio/sidecar.d.ts +76 -0
  33. package/lib/audio/sidecar.js +362 -0
  34. package/lib/audio/sidecar.js.map +1 -0
  35. package/lib/audio/subtitleExtractor.d.ts +36 -0
  36. package/lib/audio/subtitleExtractor.js +218 -0
  37. package/lib/audio/subtitleExtractor.js.map +1 -0
  38. package/lib/audio/transcriptCache.d.ts +33 -0
  39. package/lib/audio/transcriptCache.js +126 -0
  40. package/lib/audio/transcriptCache.js.map +1 -0
  41. package/lib/audio/types.d.ts +136 -0
  42. package/lib/audio/types.js +10 -0
  43. package/lib/audio/types.js.map +1 -0
  44. package/lib/host/api.d.ts +23 -0
  45. package/lib/host/api.js +286 -0
  46. package/lib/host/api.js.map +1 -0
  47. package/lib/host/runtime.d.ts +167 -0
  48. package/lib/host/runtime.js +335 -0
  49. package/lib/host/runtime.js.map +1 -0
  50. package/lib/index.d.ts +229 -1
  51. package/lib/index.js +103 -2
  52. package/lib/index.js.map +1 -1
  53. package/lib/session/state.js +4 -0
  54. package/lib/session/state.js.map +1 -1
  55. package/lib/stage0/decoder.d.ts +1 -9
  56. package/lib/stage0/decoder.js +15 -45
  57. package/lib/stage0/decoder.js.map +1 -1
  58. package/lib/stage2/stateMachine.d.ts +4 -1
  59. package/lib/stage2/stateMachine.js +7 -1
  60. package/lib/stage2/stateMachine.js.map +1 -1
  61. package/lib/stage3/deterministicRouter.js +3 -3
  62. package/lib/stage3/deterministicRouter.js.map +1 -1
  63. package/lib/stage3/streamSampler.d.ts +9 -2
  64. package/lib/stage3/streamSampler.js +37 -16
  65. package/lib/stage3/streamSampler.js.map +1 -1
  66. package/lib/stage6/history.d.ts +2 -1
  67. package/lib/stage6/history.js +4 -1
  68. package/lib/stage6/history.js.map +1 -1
  69. package/lib/tool/handler.d.ts +9 -0
  70. package/lib/tool/handler.js +33 -3
  71. package/lib/tool/handler.js.map +1 -1
  72. package/lib/tool/schema.js +15 -2
  73. package/lib/tool/schema.js.map +1 -1
  74. package/lib/tool/streamCall.d.ts +11 -0
  75. package/lib/tool/streamCall.js +122 -9
  76. package/lib/tool/streamCall.js.map +1 -1
  77. package/lib/types.d.ts +9 -0
  78. package/locale/en.json +6 -0
  79. package/locale/zh.json +6 -0
  80. package/package.json +17 -2
@@ -0,0 +1,33 @@
1
+ /**
2
+ * 磁盘转写缓存。
3
+ *
4
+ * 键 = sha256(小写绝对路径 + mtime + size) + 引擎指纹(服务商/模型/语言)。
5
+ * 视频变化或换引擎都会自动失效;密钥不参与指纹。
6
+ * 值 = 已完成转写的区间列表(subtitle 提取为本地快操作,不走缓存)。
7
+ */
8
+ import type { AsrSettings, TranscriptSegment } from './types.js';
9
+ export interface TranscriptInterval {
10
+ startMs: number;
11
+ endMs: number;
12
+ source: 'asr';
13
+ segments: TranscriptSegment[];
14
+ }
15
+ /** 视频指纹:路径小写 + mtime + size 的 SHA-256 前 32 位。 */
16
+ export declare function videoFingerprint(videoPath: string): Promise<string>;
17
+ /**
18
+ * 引擎指纹:同一段音频用本地或云端得到的结果不同,缓存不能混用。
19
+ * 只含影响转写结果的参数;apiKey 不参与(换密钥不失效)。
20
+ */
21
+ export declare function engineFingerprint(settings: AsrSettings): string;
22
+ export declare function readTranscriptCache(cacheDir: string, fingerprint: string): Promise<TranscriptInterval[] | null>;
23
+ /** 原子写入:先写 .tmp 再 rename。 */
24
+ export declare function writeTranscriptCache(cacheDir: string, fingerprint: string, intervals: TranscriptInterval[]): Promise<void>;
25
+ /** 命中部分:与窗口相交的缓存区间按时间序拼接出的可用段。 */
26
+ export declare function cachedSegmentsFor(intervals: TranscriptInterval[], window: [number, number]): TranscriptSegment[];
27
+ /**
28
+ * 缺口计算:窗口减去已覆盖区间(允许 1s 重叠缝合)。
29
+ * 返回需要重新转写的子窗口列表。
30
+ */
31
+ export declare function missingRanges(intervals: TranscriptInterval[], window: [number, number], marginMs?: number): Array<[number, number]>;
32
+ /** 新区间并入缓存文档(相邻重叠合并,段去重按起点)。 */
33
+ export declare function mergeInterval(intervals: TranscriptInterval[], addition: TranscriptInterval): TranscriptInterval[];
@@ -0,0 +1,126 @@
1
+ /**
2
+ * 磁盘转写缓存。
3
+ *
4
+ * 键 = sha256(小写绝对路径 + mtime + size) + 引擎指纹(服务商/模型/语言)。
5
+ * 视频变化或换引擎都会自动失效;密钥不参与指纹。
6
+ * 值 = 已完成转写的区间列表(subtitle 提取为本地快操作,不走缓存)。
7
+ */
8
+ import { createHash } from 'node:crypto';
9
+ import { existsSync } from 'node:fs';
10
+ import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
11
+ import { stat } from 'node:fs/promises';
12
+ import path from 'node:path';
13
+ const CACHE_VERSION = 2;
14
+ /** 视频指纹:路径小写 + mtime + size 的 SHA-256 前 32 位。 */
15
+ export async function videoFingerprint(videoPath) {
16
+ const abs = path.resolve(videoPath);
17
+ const st = await stat(abs);
18
+ const digest = createHash('sha256')
19
+ .update(abs.toLowerCase())
20
+ .update(`|${Math.floor(st.mtimeMs)}|${st.size}`)
21
+ .digest('hex');
22
+ return digest.slice(0, 32);
23
+ }
24
+ /**
25
+ * 引擎指纹:同一段音频用本地或云端得到的结果不同,缓存不能混用。
26
+ * 只含影响转写结果的参数;apiKey 不参与(换密钥不失效)。
27
+ */
28
+ export function engineFingerprint(settings) {
29
+ const digest = createHash('sha256')
30
+ .update(`${settings.provider}|${settings.baseUrl ?? ''}|${settings.model ?? ''}|${settings.language}`)
31
+ .update(`|${(settings.args ?? []).join('\u0001')}`)
32
+ .digest('hex');
33
+ return digest.slice(0, 16);
34
+ }
35
+ function cacheFileFor(cacheDir, fingerprint) {
36
+ return path.join(cacheDir, `${fingerprint}.json`);
37
+ }
38
+ export async function readTranscriptCache(cacheDir, fingerprint) {
39
+ const file = cacheFileFor(cacheDir, fingerprint);
40
+ if (!existsSync(file))
41
+ return null;
42
+ try {
43
+ const doc = JSON.parse(await readFile(file, 'utf8'));
44
+ if (doc.version !== CACHE_VERSION || doc.fingerprint !== fingerprint)
45
+ return null;
46
+ if (!Array.isArray(doc.intervals))
47
+ return null;
48
+ return doc.intervals;
49
+ }
50
+ catch {
51
+ return null;
52
+ }
53
+ }
54
+ /** 原子写入:先写 .tmp 再 rename。 */
55
+ export async function writeTranscriptCache(cacheDir, fingerprint, intervals) {
56
+ const doc = { version: CACHE_VERSION, fingerprint, intervals };
57
+ await mkdir(cacheDir, { recursive: true });
58
+ const file = cacheFileFor(cacheDir, fingerprint);
59
+ const tmp = `${file}.${process.pid}.tmp`;
60
+ await writeFile(tmp, JSON.stringify(doc), 'utf8');
61
+ try {
62
+ await rename(tmp, file);
63
+ }
64
+ catch (error) {
65
+ await rm(tmp, { force: true });
66
+ throw error;
67
+ }
68
+ }
69
+ /** 命中部分:与窗口相交的缓存区间按时间序拼接出的可用段。 */
70
+ export function cachedSegmentsFor(intervals, window) {
71
+ const out = [];
72
+ for (const it of intervals) {
73
+ if (it.endMs <= window[0] || it.startMs >= window[1])
74
+ continue;
75
+ for (const seg of it.segments) {
76
+ if (seg.endMs <= window[0] || seg.startMs >= window[1])
77
+ continue;
78
+ out.push(seg);
79
+ }
80
+ }
81
+ return out.sort((a, b) => a.startMs - b.startMs);
82
+ }
83
+ /**
84
+ * 缺口计算:窗口减去已覆盖区间(允许 1s 重叠缝合)。
85
+ * 返回需要重新转写的子窗口列表。
86
+ */
87
+ export function missingRanges(intervals, window, marginMs = 1000) {
88
+ const sorted = [...intervals]
89
+ .filter((it) => it.endMs > window[0] && it.startMs < window[1])
90
+ .sort((a, b) => a.startMs - b.startMs);
91
+ const gaps = [];
92
+ let cursor = window[0];
93
+ for (const it of sorted) {
94
+ const start = it.startMs - marginMs;
95
+ const end = it.endMs + marginMs;
96
+ if (start > cursor)
97
+ gaps.push([cursor, Math.min(start, window[1])]);
98
+ cursor = Math.max(cursor, end);
99
+ if (cursor >= window[1])
100
+ break;
101
+ }
102
+ if (cursor < window[1])
103
+ gaps.push([cursor, window[1]]);
104
+ return gaps.filter(([a, b]) => b - a > 50);
105
+ }
106
+ /** 新区间并入缓存文档(相邻重叠合并,段去重按起点)。 */
107
+ export function mergeInterval(intervals, addition) {
108
+ const merged = [...intervals, addition].sort((a, b) => a.startMs - b.startMs);
109
+ const out = [];
110
+ for (const it of merged) {
111
+ const last = out[out.length - 1];
112
+ if (last && it.startMs <= last.endMs + 100) {
113
+ const seen = new Set(last.segments.map((s) => s.startMs));
114
+ last.endMs = Math.max(last.endMs, it.endMs);
115
+ for (const seg of it.segments)
116
+ if (!seen.has(seg.startMs))
117
+ last.segments.push(seg);
118
+ last.segments.sort((a, b) => a.startMs - b.startMs);
119
+ }
120
+ else {
121
+ out.push({ ...it, segments: [...it.segments] });
122
+ }
123
+ }
124
+ return out;
125
+ }
126
+ //# sourceMappingURL=transcriptCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcriptCache.js","sourceRoot":"","sources":["../../src/audio/transcriptCache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * 视听融合(Audio-Transcript Sidecar)共享类型。
3
+ *
4
+ * 术语:
5
+ * - 通道(source):字幕(外挂/内嵌)或 ASR 转写;
6
+ * - 覆盖区间(interval):磁盘转写缓存中已完成的 [startMs, endMs] 片段;
7
+ * - 挂载(mount):把台词段映射到某个画布包(±300ms 交集 + 中心归属)。
8
+ */
9
+ export type AudioSourceKind = 'external_subtitle' | 'embedded_subtitle' | 'asr';
10
+ export type AudioStatus = 'ok' | 'partial' | 'silent' | 'no_audio' | 'disabled' | 'no_subtitle_asr_unconfigured' | 'timeout_skipped' | 'error';
11
+ /** 台词段(PTS 毫秒,全片时间轴)。 */
12
+ export interface TranscriptSegment {
13
+ segId: number;
14
+ startMs: number;
15
+ endMs: number;
16
+ text: string;
17
+ source: AudioSourceKind;
18
+ /** ASR 置信度线索(字幕为 null)。 */
19
+ noSpeechProb?: number | undefined;
20
+ avgLogprob?: number | undefined;
21
+ compressionRatio?: number | undefined;
22
+ }
23
+ /** 字幕轨道定位结果(A0)。 */
24
+ export interface SubtitleTimeline {
25
+ status: 'external_subtitle' | 'embedded_subtitle' | 'none';
26
+ language: string | null;
27
+ segments: TranscriptSegment[];
28
+ }
29
+ /** 声学扫描结果(A1)。 */
30
+ export interface VadResult {
31
+ /** 静音区间(窗口内,PTS 毫秒)。 */
32
+ silence: Array<[number, number]>;
33
+ /** 语音活跃岛(窗口内,PTS 毫秒)。 */
34
+ islands: Array<[number, number]>;
35
+ /** 窗口均方根电平(dBFS;探测失败为 null)。 */
36
+ rmsDb: number | null;
37
+ /** 窗口峰值电平(dBFS;探测失败为 null)。 */
38
+ peakDb: number | null;
39
+ /** 活跃占比(0-1)。 */
40
+ activeRatio: number;
41
+ }
42
+ export type AsrProviderKind = 'openai_verbose' | 'openai_basic' | 'local_cli';
43
+ /** ASR 运行时设置(env > Config 解析后的产物)。 */
44
+ export interface AsrSettings {
45
+ provider: AsrProviderKind;
46
+ baseUrl: string | null;
47
+ model: string | null;
48
+ apiKey: string | null;
49
+ language: string | null;
50
+ /** local_cli 附加参数:{audio}/{out} 令牌;无 {audio} 时音频路径追加末尾。 */
51
+ args: readonly string[] | null;
52
+ /** 单请求超时(毫秒)。 */
53
+ timeoutMs: number;
54
+ /** 并发上限。 */
55
+ maxConcurrency: number;
56
+ }
57
+ /** 音频通道运行时设置(Config + intent 合并后的产物)。 */
58
+ export interface AudioSettings {
59
+ mode: 'auto' | 'off';
60
+ extractSubtitles: boolean;
61
+ assistFocus: boolean;
62
+ sliceCodec: 'mp3' | 'opus';
63
+ cacheEnabled: boolean;
64
+ cacheDir: string;
65
+ /** 视觉结果返回前的音频宽限(毫秒)。 */
66
+ graceMs: number;
67
+ asr: AsrSettings | null;
68
+ }
69
+ /** 插件 Config 的 audio 块(schemavery 填充后的形态)。 */
70
+ export interface AudioPluginConfig {
71
+ mode: 'auto' | 'off';
72
+ extractSubtitles: boolean;
73
+ assistFocus: boolean;
74
+ sliceCodec: 'mp3' | 'opus';
75
+ cacheDir: string;
76
+ graceMs: number;
77
+ asr: {
78
+ /** 引擎选择(0.3.0):auto/local/cloud/off/legacy;缺省按 auto 解释。 */
79
+ engine?: string | undefined;
80
+ /** 云端服务商预设 id(openai/groq/custom)。 */
81
+ preset?: string | undefined;
82
+ provider: AsrProviderKind | 'none';
83
+ baseUrl: string | undefined;
84
+ model: string | undefined;
85
+ apiKey: string | undefined;
86
+ language: string | undefined;
87
+ /** local_cli 附加参数(置于音频文件参数前;支持 {audio}/{out} 令牌)。 */
88
+ args: string[] | undefined;
89
+ /** 本地转写引擎(0.3.0 托管安装):可执行文件/模型路径与线程数。 */
90
+ local?: {
91
+ binPath?: string | undefined;
92
+ modelPath?: string | undefined;
93
+ modelId?: string | undefined;
94
+ threads?: number | undefined;
95
+ /** 本地转写单请求超时(毫秒);CPU 转写远慢于云端。 */
96
+ timeoutMs?: number | undefined;
97
+ } | undefined;
98
+ timeoutMs: number;
99
+ maxConcurrency: number;
100
+ };
101
+ }
102
+ /** 意图层的 audio 子对象(schema 展示给模型的最小面)。 */
103
+ export interface IntentAudioDirective {
104
+ mode?: 'auto' | 'off';
105
+ language?: string;
106
+ extract_subtitles?: boolean;
107
+ assist_focus?: boolean;
108
+ }
109
+ /** 单次窗口的音频上下文(工具返回根级 audio 字段)。 */
110
+ export interface AudioContextSummary {
111
+ status: AudioStatus;
112
+ source: AudioSourceKind | null;
113
+ language: string | null;
114
+ speechRatio: number | null;
115
+ rmsDb: number | null;
116
+ speechRateCps: number | null;
117
+ segmentsInWindow: number;
118
+ mountedPackets: number;
119
+ telemetry: {
120
+ cacheHit: boolean;
121
+ chunks: number;
122
+ requests: number;
123
+ droppedByGuard: number;
124
+ costMs: number;
125
+ };
126
+ }
127
+ /** 画布包级挂载结果(packets[].audio 字段与冷区引用行数据源)。 */
128
+ export interface PacketAudioMount {
129
+ status: AudioStatus;
130
+ source: AudioSourceKind | null;
131
+ language: string | null;
132
+ /** 挂载段(alignedUnitIds:±300ms 相交的画布单元;冷区引用可缺省)。 */
133
+ segments: Array<TranscriptSegment & {
134
+ alignedUnitIds?: number[] | undefined;
135
+ }>;
136
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 视听融合(Audio-Transcript Sidecar)共享类型。
3
+ *
4
+ * 术语:
5
+ * - 通道(source):字幕(外挂/内嵌)或 ASR 转写;
6
+ * - 覆盖区间(interval):磁盘转写缓存中已完成的 [startMs, endMs] 片段;
7
+ * - 挂载(mount):把台词段映射到某个画布包(±300ms 交集 + 中心归属)。
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/audio/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * 插件设置页的 Host API。
3
+ *
4
+ * 为什么是 HTTP 而不是 IPC:持久 bundle 的浏览器半只有 `fetch` 可用
5
+ * (`harness.handle` 只属于 agent 运行时里的动态插件)。dshmarket 与
6
+ * billion-context 都走同一条路,宿主 `webServer` 提供同源路由。
7
+ *
8
+ * 路由全部在 `/dsh-pf-stream/api` 前缀下,只做本插件自己的事:
9
+ * 状态、安装、取消、验证、写配置、存密钥、清缓存。
10
+ */
11
+ import type { HostRuntime, WebServerService } from './runtime.js';
12
+ export declare const API_PREFIX = "/dsh-pf-stream/api";
13
+ interface ApiDeps {
14
+ runtime: HostRuntime;
15
+ /** 注册路由;返回 disposer。 */
16
+ webServer: WebServerService;
17
+ }
18
+ /**
19
+ * 注册全部路由。一次 `prefix` 注册即可,内部再按 pathname 分发,
20
+ * 减少与宿主路由表的耦合面。
21
+ */
22
+ export declare function registerApi(deps: ApiDeps): () => void;
23
+ export {};
@@ -0,0 +1,286 @@
1
+ /**
2
+ * 插件设置页的 Host API。
3
+ *
4
+ * 为什么是 HTTP 而不是 IPC:持久 bundle 的浏览器半只有 `fetch` 可用
5
+ * (`harness.handle` 只属于 agent 运行时里的动态插件)。dshmarket 与
6
+ * billion-context 都走同一条路,宿主 `webServer` 提供同源路由。
7
+ *
8
+ * 路由全部在 `/dsh-pf-stream/api` 前缀下,只做本插件自己的事:
9
+ * 状态、安装、取消、验证、写配置、存密钥、清缓存。
10
+ */
11
+ import { existsSync } from 'node:fs';
12
+ import { resolveBinPaths } from '../utils/ffmpegBin.js';
13
+ import { cloudPreset, CLOUD_PRESETS, LOCAL_ENGINES } from '../asr/catalog.js';
14
+ import { locateOnPath } from '../asr/detect.js';
15
+ import { resolveAsr } from '../asr/engine.js';
16
+ import { verifyCloud, verifyLocal } from '../asr/verify.js';
17
+ export const API_PREFIX = '/dsh-pf-stream/api';
18
+ /** 只接受 POST 的路由;不在此表也不是 GET /status 的路径一律 404。 */
19
+ const POST_ROUTES = new Set(['/install', '/install/cancel', '/config', '/key', '/test', '/cache/clear', '/detect']);
20
+ const MAX_BODY_BYTES = 64 * 1024;
21
+ function send(response, status, payload) {
22
+ const body = JSON.stringify(payload);
23
+ response.writeHead(status, {
24
+ 'content-type': 'application/json; charset=utf-8',
25
+ 'cache-control': 'no-store',
26
+ });
27
+ response.end(body);
28
+ }
29
+ function readBody(request) {
30
+ return new Promise((resolve, reject) => {
31
+ const chunks = [];
32
+ let size = 0;
33
+ request.on('data', (chunk) => {
34
+ size += chunk.length;
35
+ if (size > MAX_BODY_BYTES) {
36
+ reject(new Error('请求体过大'));
37
+ return;
38
+ }
39
+ chunks.push(chunk);
40
+ });
41
+ request.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
42
+ request.on('error', (error) => reject(error));
43
+ });
44
+ }
45
+ /** 同源校验:带 Origin 的请求必须与 Host 同源(防跨站写入)。 */
46
+ function sameOrigin(request) {
47
+ const origin = request.headers.origin;
48
+ const value = Array.isArray(origin) ? origin[0] : origin;
49
+ if (value === undefined || value === '')
50
+ return true;
51
+ const host = request.headers.host;
52
+ const hostValue = Array.isArray(host) ? host[0] : host;
53
+ if (hostValue === undefined)
54
+ return false;
55
+ try {
56
+ return new URL(value).host === hostValue;
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
62
+ const ENGINE_MODES = new Set(['auto', 'local', 'cloud', 'off', 'legacy']);
63
+ function shortString(value) {
64
+ return typeof value === 'string' && value.length <= 300;
65
+ }
66
+ /** 设置页只允许改这些字段(其余走 cordis.patch.yml 或高级配置)。 */
67
+ const CONFIG_FIELDS = {
68
+ mode: {
69
+ path: ['audio', 'mode'],
70
+ validate: (value) => value === 'auto' || value === 'off',
71
+ normalize: (value) => value,
72
+ },
73
+ engine: {
74
+ path: ['audio', 'asr', 'engine'],
75
+ validate: (value) => typeof value === 'string' && ENGINE_MODES.has(value),
76
+ normalize: (value) => value,
77
+ },
78
+ preset: {
79
+ path: ['audio', 'asr', 'preset'],
80
+ validate: (value) => CLOUD_PRESETS.some((preset) => preset.id === value),
81
+ normalize: (value) => value,
82
+ },
83
+ baseUrl: {
84
+ path: ['audio', 'asr', 'baseUrl'],
85
+ validate: shortString,
86
+ normalize: (value) => (typeof value === 'string' ? value.trim() : value),
87
+ },
88
+ model: {
89
+ path: ['audio', 'asr', 'model'],
90
+ validate: shortString,
91
+ normalize: (value) => (typeof value === 'string' ? value.trim() : value),
92
+ },
93
+ language: {
94
+ path: ['audio', 'asr', 'language'],
95
+ validate: shortString,
96
+ normalize: (value) => (typeof value === 'string' ? value.trim() : value),
97
+ },
98
+ modelId: {
99
+ path: ['audio', 'asr', 'local', 'modelId'],
100
+ validate: (value) => typeof value === 'string' && ['base-q5_1', 'small-q5_1', 'medium-q5_0'].includes(value),
101
+ normalize: (value) => value,
102
+ },
103
+ threads: {
104
+ path: ['audio', 'asr', 'local', 'threads'],
105
+ validate: (value) => typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 32,
106
+ normalize: (value) => Math.trunc(value),
107
+ },
108
+ };
109
+ function nestPatch(path, value) {
110
+ const root = {};
111
+ let cursor = root;
112
+ path.forEach((key, index) => {
113
+ if (index === path.length - 1) {
114
+ cursor[key] = value;
115
+ return;
116
+ }
117
+ const next = {};
118
+ cursor[key] = next;
119
+ cursor = next;
120
+ });
121
+ return root;
122
+ }
123
+ async function statusPayload(runtime) {
124
+ const config = runtime.currentConfig();
125
+ const bins = resolveBinPaths({ ffmpegPath: config.ffmpegPath, ffprobePath: config.ffprobePath });
126
+ const ffmpegOk = existsSync(bins.ffmpeg) || locateOnPath(['ffmpeg']) !== null;
127
+ const ffprobeOk = existsSync(bins.ffprobe) || locateOnPath(['ffprobe']) !== null;
128
+ const status = await runtime.status();
129
+ const keys = await runtime.keys();
130
+ return {
131
+ ...status,
132
+ ffmpeg: {
133
+ available: ffmpegOk && ffprobeOk,
134
+ ffmpeg: bins.ffmpeg,
135
+ ffprobe: bins.ffprobe,
136
+ },
137
+ presets: CLOUD_PRESETS.map((preset) => ({
138
+ id: preset.id,
139
+ label: preset.label,
140
+ baseUrl: preset.baseUrl,
141
+ model: preset.model,
142
+ keyUrl: preset.keyUrl,
143
+ editable: preset.editable,
144
+ keyConfigured: (keys[preset.id] ?? null) !== null,
145
+ })),
146
+ engines: LOCAL_ENGINES.map((engine) => ({ id: engine.id, label: engine.label })),
147
+ };
148
+ }
149
+ /**
150
+ * 注册全部路由。一次 `prefix` 注册即可,内部再按 pathname 分发,
151
+ * 减少与宿主路由表的耦合面。
152
+ */
153
+ export function registerApi(deps) {
154
+ const { runtime } = deps;
155
+ const handler = (request, response) => {
156
+ void (async () => {
157
+ const method = (request.method ?? 'GET').toUpperCase();
158
+ const url = new URL(request.url ?? '/', 'http://localhost');
159
+ if (!url.pathname.startsWith(API_PREFIX)) {
160
+ send(response, 404, { ok: false, error: 'not_found' });
161
+ return;
162
+ }
163
+ const route = url.pathname.slice(API_PREFIX.length) || '/';
164
+ if (!sameOrigin(request)) {
165
+ send(response, 403, { ok: false, error: 'cross_origin' });
166
+ return;
167
+ }
168
+ if (method === 'GET' && route === '/status') {
169
+ send(response, 200, { ok: true, data: await statusPayload(runtime) });
170
+ return;
171
+ }
172
+ const known = route === '/status' || POST_ROUTES.has(route);
173
+ if (!known) {
174
+ send(response, 404, { ok: false, error: 'not_found' });
175
+ return;
176
+ }
177
+ if (method !== 'POST') {
178
+ send(response, 405, { ok: false, error: 'method_not_allowed' });
179
+ return;
180
+ }
181
+ const contentType = String(request.headers['content-type'] ?? '');
182
+ if (!contentType.includes('application/json')) {
183
+ send(response, 415, { ok: false, error: 'json_required' });
184
+ return;
185
+ }
186
+ let body = {};
187
+ const raw = await readBody(request);
188
+ if (raw.trim() !== '') {
189
+ const parsed = JSON.parse(raw);
190
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
191
+ send(response, 400, { ok: false, error: 'invalid_body' });
192
+ return;
193
+ }
194
+ body = parsed;
195
+ }
196
+ if (route === '/install') {
197
+ const target = body.target === 'model' || body.target === 'engine' ? body.target : 'all';
198
+ const job = runtime.startInstall(target);
199
+ send(response, 200, { ok: true, data: job });
200
+ return;
201
+ }
202
+ if (route === '/install/cancel') {
203
+ runtime.installer.cancel();
204
+ send(response, 200, { ok: true, data: runtime.installer.current() });
205
+ return;
206
+ }
207
+ if (route === '/config') {
208
+ const field = typeof body.field === 'string' ? body.field : '';
209
+ const entry = CONFIG_FIELDS[field];
210
+ if (entry === undefined || !entry.validate(body.value)) {
211
+ send(response, 400, { ok: false, error: 'invalid_field' });
212
+ return;
213
+ }
214
+ const result = await runtime.patchConfig(nestPatch(entry.path, entry.normalize(body.value)));
215
+ send(response, result.ok ? 200 : 409, result);
216
+ return;
217
+ }
218
+ if (route === '/key') {
219
+ const presetId = typeof body.preset === 'string' ? body.preset : '';
220
+ const preset = CLOUD_PRESETS.find((entry) => entry.id === presetId);
221
+ if (preset === undefined) {
222
+ send(response, 400, { ok: false, error: 'unknown_preset' });
223
+ return;
224
+ }
225
+ const key = typeof body.key === 'string' ? body.key : '';
226
+ if (key.length > 4096) {
227
+ send(response, 400, { ok: false, error: 'key_too_long' });
228
+ return;
229
+ }
230
+ try {
231
+ await runtime.setKey(preset.id, key);
232
+ const info = await runtime.keyInfo(preset.id);
233
+ send(response, 200, { ok: true, data: info });
234
+ }
235
+ catch (error) {
236
+ send(response, 409, {
237
+ ok: false,
238
+ error: 'credential_rejected',
239
+ message: error instanceof Error ? error.message : String(error),
240
+ });
241
+ }
242
+ return;
243
+ }
244
+ if (route === '/test') {
245
+ const facts = await runtime.facts();
246
+ const config = runtime.currentConfig();
247
+ const resolution = resolveAsr(config.audio.asr, undefined, process.env, facts);
248
+ if (resolution.settings === null) {
249
+ send(response, 409, {
250
+ ok: false,
251
+ error: resolution.reason ?? 'not_ready',
252
+ message: resolution.detail ?? '转写引擎尚未就绪',
253
+ });
254
+ return;
255
+ }
256
+ const settings = resolution.settings;
257
+ const engine = facts.detection.engine;
258
+ const label = resolution.kind === 'cloud'
259
+ ? `云端 ${cloudPreset(config.audio.asr.preset ?? null).label}`
260
+ : (LOCAL_ENGINES.find((entry) => entry.id === engine)?.label ?? engine);
261
+ const result = resolution.kind === 'cloud' ? await verifyCloud(settings) : await verifyLocal(settings);
262
+ send(response, 200, { ok: true, data: { ...result, engine: label, durationMs: result.latencyMs } });
263
+ return;
264
+ }
265
+ if (route === '/cache/clear') {
266
+ const cleared = runtime.clearCache();
267
+ send(response, 200, { ok: true, data: cleared });
268
+ return;
269
+ }
270
+ if (route === '/detect') {
271
+ runtime.invalidate();
272
+ send(response, 200, { ok: true, data: await statusPayload(runtime) });
273
+ return;
274
+ }
275
+ send(response, 404, { ok: false, error: 'not_found' });
276
+ })().catch((error) => {
277
+ send(response, 500, {
278
+ ok: false,
279
+ error: 'internal_error',
280
+ message: error instanceof Error ? error.message : String(error),
281
+ });
282
+ });
283
+ };
284
+ return deps.webServer.register({ kind: 'prefix', path: API_PREFIX, handler });
285
+ }
286
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/host/api.ts"],"names":[],"mappings":"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"}