dsh-pf-stream 0.2.3 → 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.
- package/README.en.md +119 -95
- package/README.md +119 -96
- package/client.js +1156 -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 +23 -3
- 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 +17 -2
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 宿主侧运行时:探测结果、云端密钥、安装任务与设置命名空间的唯一持有者。
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要它:设置页要看到「现在到底能不能转写」,而工具调用要拿到同样
|
|
5
|
+
* 的结论。两边共用一份事实,避免页面显示就绪、实际调用却回退。
|
|
6
|
+
*/
|
|
7
|
+
import type { PfStreamPluginConfig } from '../types.js';
|
|
8
|
+
import { type LocalEngineSnapshot } from '../asr/detect.js';
|
|
9
|
+
import type { AsrRuntimeFacts } from '../asr/engine.js';
|
|
10
|
+
import { LocalAsrInstaller, type InstallJob, type InstallTarget } from '../asr/install.js';
|
|
11
|
+
export interface CredentialsService {
|
|
12
|
+
resolve(ref: string): Promise<{
|
|
13
|
+
value: string;
|
|
14
|
+
source?: string;
|
|
15
|
+
} | undefined>;
|
|
16
|
+
describe(ref: string): Promise<{
|
|
17
|
+
configured: boolean;
|
|
18
|
+
source?: string;
|
|
19
|
+
writable: boolean;
|
|
20
|
+
}>;
|
|
21
|
+
set(ref: string, value: string): Promise<void>;
|
|
22
|
+
unset(ref: string): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
/** Loader 条目(只取设置页需要的字段)。 */
|
|
25
|
+
export interface ConfigEntry {
|
|
26
|
+
options: {
|
|
27
|
+
id: string;
|
|
28
|
+
name?: string;
|
|
29
|
+
config?: Record<string, unknown>;
|
|
30
|
+
};
|
|
31
|
+
fiber?: unknown;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 完整配置编辑器:写入 profile patch 并走正常 Loader 路径。
|
|
35
|
+
* 为什么不用 settings:它只投影 volatile 字段,而我们的面板要改的是普通配置项。
|
|
36
|
+
*/
|
|
37
|
+
export interface ConfigEditorService {
|
|
38
|
+
entries(): ConfigEntry[];
|
|
39
|
+
edit(entry: ConfigEntry, change: (current: Record<string, unknown>, inherited: Record<string, unknown>) => Record<string, unknown>): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
export interface WebRequestLike {
|
|
42
|
+
method?: string | undefined;
|
|
43
|
+
url?: string | undefined;
|
|
44
|
+
headers: Record<string, string | string[] | undefined>;
|
|
45
|
+
on(event: 'data', listener: (chunk: Buffer) => void): void;
|
|
46
|
+
on(event: 'end', listener: () => void): void;
|
|
47
|
+
on(event: 'error', listener: (error: Error) => void): void;
|
|
48
|
+
}
|
|
49
|
+
export interface WebResponseLike {
|
|
50
|
+
writeHead(status: number, headers?: Record<string, string>): void;
|
|
51
|
+
end(body?: string): void;
|
|
52
|
+
}
|
|
53
|
+
export interface WebRoute {
|
|
54
|
+
kind: 'exact' | 'prefix';
|
|
55
|
+
path: string;
|
|
56
|
+
handler: (request: WebRequestLike, response: WebResponseLike) => void;
|
|
57
|
+
}
|
|
58
|
+
export interface WebServerService {
|
|
59
|
+
register(route: WebRoute): () => void;
|
|
60
|
+
}
|
|
61
|
+
export interface HostServices {
|
|
62
|
+
credentials?: CredentialsService | undefined;
|
|
63
|
+
/** 首选写入通道:完整配置编辑(无需 volatile)。 */
|
|
64
|
+
configEditor?: ConfigEditorService | undefined;
|
|
65
|
+
webServer?: WebServerService | undefined;
|
|
66
|
+
}
|
|
67
|
+
export interface CloudStatus {
|
|
68
|
+
preset: string;
|
|
69
|
+
label: string;
|
|
70
|
+
baseUrl: string;
|
|
71
|
+
model: string;
|
|
72
|
+
keyConfigured: boolean;
|
|
73
|
+
editable: boolean;
|
|
74
|
+
}
|
|
75
|
+
export interface AsrStatus {
|
|
76
|
+
engine: LocalEngineSnapshot;
|
|
77
|
+
/** 用户配置的引擎模式(auto/local/cloud/off/legacy)。 */
|
|
78
|
+
mode: string;
|
|
79
|
+
cloud: CloudStatus;
|
|
80
|
+
/** 旧版 provider 直连配置是否存在(0.2.x 兼容)。 */
|
|
81
|
+
legacyProvider: string;
|
|
82
|
+
/** 缓存目录与占用(字节)。 */
|
|
83
|
+
cacheDir: string;
|
|
84
|
+
cacheBytes: number;
|
|
85
|
+
/** 本地资源路径(不保证存在,供页面展示)。 */
|
|
86
|
+
managed: {
|
|
87
|
+
exe: string;
|
|
88
|
+
modelDir: string;
|
|
89
|
+
};
|
|
90
|
+
modelId: string;
|
|
91
|
+
modelLabel: string;
|
|
92
|
+
/** 当前生效的配置值,供页面回填表单。 */
|
|
93
|
+
config: {
|
|
94
|
+
engine: string;
|
|
95
|
+
language: string;
|
|
96
|
+
threads: number;
|
|
97
|
+
modelId: string;
|
|
98
|
+
};
|
|
99
|
+
install: InstallJob | null;
|
|
100
|
+
/** profile 里的配置条目 id(能写入时非 null)。 */
|
|
101
|
+
configNamespace: string | null;
|
|
102
|
+
configWritable: boolean;
|
|
103
|
+
/** 当前实际会使用的引擎(auto 解析结果),供页面如实显示。 */
|
|
104
|
+
active: {
|
|
105
|
+
kind: 'cloud' | 'local' | 'none';
|
|
106
|
+
preset: string;
|
|
107
|
+
presetLabel: string;
|
|
108
|
+
};
|
|
109
|
+
/** 一句话结论:现在能否转写。 */
|
|
110
|
+
ready: boolean;
|
|
111
|
+
summary: string;
|
|
112
|
+
}
|
|
113
|
+
export declare class HostRuntime {
|
|
114
|
+
private readonly getConfig;
|
|
115
|
+
private readonly services;
|
|
116
|
+
private detectionCache;
|
|
117
|
+
private keyCache;
|
|
118
|
+
private lastFacts;
|
|
119
|
+
/**
|
|
120
|
+
* 本会话内已保存的配置补丁。configEditor 负责持久化,但运行中的插件实例
|
|
121
|
+
* 不会立刻拿到新配置,所以这里保留一份覆盖层,保证保存后面板与工具立即生效。
|
|
122
|
+
*/
|
|
123
|
+
private overrides;
|
|
124
|
+
readonly installer: LocalAsrInstaller;
|
|
125
|
+
constructor(getConfig: () => PfStreamPluginConfig, services: HostServices);
|
|
126
|
+
private config;
|
|
127
|
+
/** 供 HTTP 层读取当前配置(只读)。 */
|
|
128
|
+
currentConfig(): PfStreamPluginConfig;
|
|
129
|
+
invalidate(): void;
|
|
130
|
+
/** 按最新配置同步安装器参数后再开始安装(模型大小可能刚被改过)。 */
|
|
131
|
+
startInstall(target?: InstallTarget): InstallJob;
|
|
132
|
+
detection(): LocalEngineSnapshot;
|
|
133
|
+
/** 读取各云端预设的密钥(不返回值给页面,只给「是否配置」)。 */
|
|
134
|
+
keys(): Promise<Record<string, string | null>>;
|
|
135
|
+
facts(): Promise<AsrRuntimeFacts>;
|
|
136
|
+
/**
|
|
137
|
+
* 同步取事实(工具调用路径用):密钥刷新是异步的,这里用最近一次快照,
|
|
138
|
+
* 首次调用前由 apply 期 refresh() 预热;缺快照时按空密钥处理。
|
|
139
|
+
* 探测必须每次现算:刚装完模型就调用,不能继续用安装前的旧快照。
|
|
140
|
+
*/
|
|
141
|
+
syncFacts(): AsrRuntimeFacts;
|
|
142
|
+
/** 预热/刷新密钥快照。 */
|
|
143
|
+
refresh(): Promise<void>;
|
|
144
|
+
setKey(presetId: string, value: string): Promise<void>;
|
|
145
|
+
keyInfo(presetId: string): Promise<{
|
|
146
|
+
configured: boolean;
|
|
147
|
+
source: string | null;
|
|
148
|
+
}>;
|
|
149
|
+
/** 本插件在 profile 里的配置条目:按条目 id 或包名匹配。 */
|
|
150
|
+
private resolveConfigEntry;
|
|
151
|
+
/** 当前可写入的配置条目 id;不可写时为 null。 */
|
|
152
|
+
resolveConfigNamespace(): string | null;
|
|
153
|
+
/**
|
|
154
|
+
* 写配置:把 patch 深合并进当前 raw config,再由 Loader 持久化。
|
|
155
|
+
* 只写用户改动的字段,其余配置(含 40 余项高级项)原样保留。
|
|
156
|
+
*/
|
|
157
|
+
patchConfig(patch: Record<string, unknown>): Promise<{
|
|
158
|
+
ok: boolean;
|
|
159
|
+
message?: string;
|
|
160
|
+
}>;
|
|
161
|
+
status(): Promise<AsrStatus>;
|
|
162
|
+
/** 清理转写缓存(仅根目录的指纹 JSON/临时文件,保留 asr/ 下的模型与引擎)。 */
|
|
163
|
+
clearCache(): {
|
|
164
|
+
removed: number;
|
|
165
|
+
bytes: number;
|
|
166
|
+
};
|
|
167
|
+
}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 宿主侧运行时:探测结果、云端密钥、安装任务与设置命名空间的唯一持有者。
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要它:设置页要看到「现在到底能不能转写」,而工具调用要拿到同样
|
|
5
|
+
* 的结论。两边共用一份事实,避免页面显示就绪、实际调用却回退。
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readdirSync, rmSync, statSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { CLOUD_PRESETS, cloudPreset, managedPaths, modelPreset } from '../asr/catalog.js';
|
|
10
|
+
import { detectLocalEngine } from '../asr/detect.js';
|
|
11
|
+
import { resolveAsr } from '../asr/engine.js';
|
|
12
|
+
import { LocalAsrInstaller } from '../asr/install.js';
|
|
13
|
+
const DETECT_TTL_MS = 5_000;
|
|
14
|
+
const KEY_TTL_MS = 10_000;
|
|
15
|
+
export class HostRuntime {
|
|
16
|
+
getConfig;
|
|
17
|
+
services;
|
|
18
|
+
detectionCache = null;
|
|
19
|
+
keyCache = null;
|
|
20
|
+
lastFacts = null;
|
|
21
|
+
/**
|
|
22
|
+
* 本会话内已保存的配置补丁。configEditor 负责持久化,但运行中的插件实例
|
|
23
|
+
* 不会立刻拿到新配置,所以这里保留一份覆盖层,保证保存后面板与工具立即生效。
|
|
24
|
+
*/
|
|
25
|
+
overrides = {};
|
|
26
|
+
installer;
|
|
27
|
+
constructor(getConfig, services) {
|
|
28
|
+
this.getConfig = getConfig;
|
|
29
|
+
this.services = services;
|
|
30
|
+
const config = this.getConfig();
|
|
31
|
+
this.installer = new LocalAsrInstaller({
|
|
32
|
+
cacheDir: config.audio.cacheDir,
|
|
33
|
+
modelId: config.audio.asr.local?.modelId ?? 'small-q5_1',
|
|
34
|
+
onFinished: () => this.invalidate(),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
config() {
|
|
38
|
+
const base = this.getConfig();
|
|
39
|
+
if (Object.keys(this.overrides).length === 0)
|
|
40
|
+
return base;
|
|
41
|
+
return mergeConfig(base, this.overrides);
|
|
42
|
+
}
|
|
43
|
+
/** 供 HTTP 层读取当前配置(只读)。 */
|
|
44
|
+
currentConfig() {
|
|
45
|
+
return this.config();
|
|
46
|
+
}
|
|
47
|
+
invalidate() {
|
|
48
|
+
this.detectionCache = null;
|
|
49
|
+
this.keyCache = null;
|
|
50
|
+
}
|
|
51
|
+
/** 按最新配置同步安装器参数后再开始安装(模型大小可能刚被改过)。 */
|
|
52
|
+
startInstall(target = 'all') {
|
|
53
|
+
const config = this.config();
|
|
54
|
+
this.installer.update({
|
|
55
|
+
cacheDir: config.audio.cacheDir,
|
|
56
|
+
modelId: config.audio.asr.local?.modelId ?? 'small-q5_1',
|
|
57
|
+
});
|
|
58
|
+
return this.installer.start(target);
|
|
59
|
+
}
|
|
60
|
+
detection() {
|
|
61
|
+
const now = Date.now();
|
|
62
|
+
if (this.detectionCache !== null && now - this.detectionCache.at < DETECT_TTL_MS) {
|
|
63
|
+
return this.detectionCache.value;
|
|
64
|
+
}
|
|
65
|
+
const config = this.config();
|
|
66
|
+
const value = detectLocalEngine({
|
|
67
|
+
cacheDir: config.audio.cacheDir,
|
|
68
|
+
binPath: config.audio.asr.local?.binPath,
|
|
69
|
+
modelPath: config.audio.asr.local?.modelPath,
|
|
70
|
+
modelId: config.audio.asr.local?.modelId,
|
|
71
|
+
});
|
|
72
|
+
this.detectionCache = { at: now, value };
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
/** 读取各云端预设的密钥(不返回值给页面,只给「是否配置」)。 */
|
|
76
|
+
async keys() {
|
|
77
|
+
const now = Date.now();
|
|
78
|
+
if (this.keyCache !== null && now - this.keyCache.at < KEY_TTL_MS) {
|
|
79
|
+
return this.keyCache.value;
|
|
80
|
+
}
|
|
81
|
+
const value = {};
|
|
82
|
+
const credentials = this.services.credentials;
|
|
83
|
+
for (const preset of CLOUD_PRESETS) {
|
|
84
|
+
if (credentials === undefined) {
|
|
85
|
+
value[preset.id] = null;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const hit = await credentials.resolve(preset.keyRef);
|
|
90
|
+
value[preset.id] = hit?.value?.trim() ?? null;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
value[preset.id] = null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
this.keyCache = { at: now, value };
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
async facts() {
|
|
100
|
+
const value = {
|
|
101
|
+
detection: this.detection(),
|
|
102
|
+
keys: await this.keys(),
|
|
103
|
+
localTimeoutMs: this.config().audio.asr.local?.timeoutMs ?? 300_000,
|
|
104
|
+
localThreads: this.config().audio.asr.local?.threads ?? 0,
|
|
105
|
+
};
|
|
106
|
+
this.lastFacts = value;
|
|
107
|
+
return value;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* 同步取事实(工具调用路径用):密钥刷新是异步的,这里用最近一次快照,
|
|
111
|
+
* 首次调用前由 apply 期 refresh() 预热;缺快照时按空密钥处理。
|
|
112
|
+
* 探测必须每次现算:刚装完模型就调用,不能继续用安装前的旧快照。
|
|
113
|
+
*/
|
|
114
|
+
syncFacts() {
|
|
115
|
+
const value = {
|
|
116
|
+
detection: this.detection(),
|
|
117
|
+
keys: this.keyCache?.value ?? this.lastFacts?.keys ?? {},
|
|
118
|
+
localTimeoutMs: this.config().audio.asr.local?.timeoutMs ?? 300_000,
|
|
119
|
+
localThreads: this.config().audio.asr.local?.threads ?? 0,
|
|
120
|
+
};
|
|
121
|
+
this.lastFacts = value;
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
/** 预热/刷新密钥快照。 */
|
|
125
|
+
async refresh() {
|
|
126
|
+
await this.facts();
|
|
127
|
+
}
|
|
128
|
+
async setKey(presetId, value) {
|
|
129
|
+
const credentials = this.services.credentials;
|
|
130
|
+
if (credentials === undefined)
|
|
131
|
+
throw new Error('宿主没有提供凭据服务,无法保存密钥');
|
|
132
|
+
const preset = cloudPreset(presetId);
|
|
133
|
+
const trimmed = value.trim();
|
|
134
|
+
if (trimmed === '') {
|
|
135
|
+
await credentials.unset(preset.keyRef);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
await credentials.set(preset.keyRef, trimmed);
|
|
139
|
+
}
|
|
140
|
+
this.keyCache = null;
|
|
141
|
+
}
|
|
142
|
+
async keyInfo(presetId) {
|
|
143
|
+
const credentials = this.services.credentials;
|
|
144
|
+
if (credentials === undefined)
|
|
145
|
+
return { configured: false, source: null };
|
|
146
|
+
try {
|
|
147
|
+
const info = await credentials.describe(cloudPreset(presetId).keyRef);
|
|
148
|
+
return { configured: info.configured, source: info.source ?? null };
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return { configured: false, source: null };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/** 本插件在 profile 里的配置条目:按条目 id 或包名匹配。 */
|
|
155
|
+
resolveConfigEntry() {
|
|
156
|
+
const editor = this.services.configEditor;
|
|
157
|
+
if (editor === undefined)
|
|
158
|
+
return null;
|
|
159
|
+
try {
|
|
160
|
+
const entries = editor.entries();
|
|
161
|
+
return (entries.find((entry) => entry.options.id === 'include:dsh-pf-stream') ??
|
|
162
|
+
entries.find((entry) => entry.options.id.includes('dsh-pf-stream')) ??
|
|
163
|
+
entries.find((entry) => entry.options.name === 'dsh-pf-stream') ??
|
|
164
|
+
entries.find((entry) => (entry.options.name ?? '').includes('dsh-pf-stream')) ??
|
|
165
|
+
null);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/** 当前可写入的配置条目 id;不可写时为 null。 */
|
|
172
|
+
resolveConfigNamespace() {
|
|
173
|
+
const entry = this.resolveConfigEntry();
|
|
174
|
+
return entry === null ? null : entry.options.id;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* 写配置:把 patch 深合并进当前 raw config,再由 Loader 持久化。
|
|
178
|
+
* 只写用户改动的字段,其余配置(含 40 余项高级项)原样保留。
|
|
179
|
+
*/
|
|
180
|
+
async patchConfig(patch) {
|
|
181
|
+
const editor = this.services.configEditor;
|
|
182
|
+
const entry = this.resolveConfigEntry();
|
|
183
|
+
if (editor === undefined || entry === null) {
|
|
184
|
+
return { ok: false, message: '宿主未暴露配置编辑服务,请直接编辑 cordis.patch.yml' };
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
await editor.edit(entry, (current) => mergeConfig(current, patch));
|
|
188
|
+
// 持久化已完成;覆盖层让当前运行实例立即读到新值。
|
|
189
|
+
this.overrides = mergeConfig(this.overrides, patch);
|
|
190
|
+
this.invalidate();
|
|
191
|
+
const next = this.config();
|
|
192
|
+
this.installer.update({ modelId: next.audio.asr.local?.modelId ?? 'small-q5_1' });
|
|
193
|
+
return { ok: true };
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
return { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
async status() {
|
|
200
|
+
const config = this.config();
|
|
201
|
+
const detection = this.detection();
|
|
202
|
+
const keys = await this.keys();
|
|
203
|
+
const preset = cloudPreset(config.audio.asr.preset ?? null);
|
|
204
|
+
const keyConfigured = (keys[preset.id] ?? null) !== null;
|
|
205
|
+
const cloudBase = preset.editable ? config.audio.asr.baseUrl?.trim() ?? '' : preset.baseUrl;
|
|
206
|
+
const cloudModel = preset.editable ? config.audio.asr.model?.trim() ?? '' : preset.model;
|
|
207
|
+
const model = modelPreset(detection.modelId);
|
|
208
|
+
const managed = managedPaths(config.audio.cacheDir);
|
|
209
|
+
const mode = config.audio.asr.engine ?? 'auto';
|
|
210
|
+
const namespace = this.resolveConfigNamespace();
|
|
211
|
+
const legacy = config.audio.asr.provider;
|
|
212
|
+
const resolution = resolveAsr(config.audio.asr, undefined, process.env, {
|
|
213
|
+
detection,
|
|
214
|
+
keys,
|
|
215
|
+
localTimeoutMs: config.audio.asr.local?.timeoutMs ?? 300_000,
|
|
216
|
+
localThreads: config.audio.asr.local?.threads ?? 0,
|
|
217
|
+
});
|
|
218
|
+
const ready = config.audio.mode !== 'off' && resolution.settings !== null;
|
|
219
|
+
const summary = ready
|
|
220
|
+
? resolution.kind === 'cloud'
|
|
221
|
+
? `云端转写就绪(${preset.label})`
|
|
222
|
+
: `本地转写就绪(${detection.engine})`
|
|
223
|
+
: mode === 'off'
|
|
224
|
+
? '转写已关闭'
|
|
225
|
+
: '还不能转写语音:安装本地模型或配置云端密钥';
|
|
226
|
+
const activeKind = resolution.kind === 'legacy'
|
|
227
|
+
? resolution.settings?.provider === 'local_cli'
|
|
228
|
+
? 'local'
|
|
229
|
+
: 'cloud'
|
|
230
|
+
: resolution.kind;
|
|
231
|
+
return {
|
|
232
|
+
engine: detection,
|
|
233
|
+
mode,
|
|
234
|
+
cloud: {
|
|
235
|
+
preset: preset.id,
|
|
236
|
+
label: preset.label,
|
|
237
|
+
baseUrl: cloudBase,
|
|
238
|
+
model: cloudModel,
|
|
239
|
+
keyConfigured,
|
|
240
|
+
editable: preset.editable,
|
|
241
|
+
},
|
|
242
|
+
legacyProvider: legacy,
|
|
243
|
+
cacheDir: config.audio.cacheDir,
|
|
244
|
+
cacheBytes: cacheFileBytes(config.audio.cacheDir),
|
|
245
|
+
managed,
|
|
246
|
+
modelId: model.id,
|
|
247
|
+
modelLabel: model.label,
|
|
248
|
+
config: {
|
|
249
|
+
engine: mode,
|
|
250
|
+
language: config.audio.asr.language ?? '',
|
|
251
|
+
threads: config.audio.asr.local?.threads ?? 0,
|
|
252
|
+
modelId: model.id,
|
|
253
|
+
},
|
|
254
|
+
install: this.installer.current(),
|
|
255
|
+
configNamespace: namespace,
|
|
256
|
+
configWritable: namespace !== null,
|
|
257
|
+
active: {
|
|
258
|
+
kind: activeKind,
|
|
259
|
+
preset: preset.id,
|
|
260
|
+
presetLabel: preset.label,
|
|
261
|
+
},
|
|
262
|
+
ready,
|
|
263
|
+
summary,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
/** 清理转写缓存(仅根目录的指纹 JSON/临时文件,保留 asr/ 下的模型与引擎)。 */
|
|
267
|
+
clearCache() {
|
|
268
|
+
const dir = this.config().audio.cacheDir;
|
|
269
|
+
let removed = 0;
|
|
270
|
+
let bytes = 0;
|
|
271
|
+
try {
|
|
272
|
+
for (const name of readdirSync(dir)) {
|
|
273
|
+
if (!/^[0-9a-f]{32}(-[0-9a-f]{16})?\.(json|tmp)$/.test(name) && !/\.json\.tmp$/.test(name))
|
|
274
|
+
continue;
|
|
275
|
+
const path = join(dir, name);
|
|
276
|
+
try {
|
|
277
|
+
const size = statSync(path).size;
|
|
278
|
+
rmSync(path, { force: true });
|
|
279
|
+
removed += 1;
|
|
280
|
+
bytes += size;
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
// 单文件失败不阻断整体清理
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
return { removed: 0, bytes: 0 };
|
|
289
|
+
}
|
|
290
|
+
return { removed, bytes };
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* 转写缓存占用(只算根目录指纹文件,不含 asr/ 下的模型与引擎)。
|
|
295
|
+
* 与 clearCache 的口径一致,避免把 181MB 模型误报成“缓存”。
|
|
296
|
+
*/
|
|
297
|
+
function cacheFileBytes(dir) {
|
|
298
|
+
let bytes = 0;
|
|
299
|
+
try {
|
|
300
|
+
for (const name of readdirSync(dir)) {
|
|
301
|
+
if (!/^[0-9a-f]{32}(-[0-9a-f]{16})?\.(json|tmp)$/.test(name) && !/\.json\.tmp$/.test(name))
|
|
302
|
+
continue;
|
|
303
|
+
try {
|
|
304
|
+
bytes += statSync(join(dir, name)).size;
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
// 单文件失败不影响统计
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
return 0;
|
|
313
|
+
}
|
|
314
|
+
return bytes;
|
|
315
|
+
}
|
|
316
|
+
/** 深合并配置 patch:只覆盖给出的叶子,其余字段(含高级项)原样保留。 */
|
|
317
|
+
function mergeConfig(current, patch) {
|
|
318
|
+
const next = { ...current };
|
|
319
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
320
|
+
const existing = next[key];
|
|
321
|
+
if (value !== null &&
|
|
322
|
+
typeof value === 'object' &&
|
|
323
|
+
!Array.isArray(value) &&
|
|
324
|
+
existing !== null &&
|
|
325
|
+
typeof existing === 'object' &&
|
|
326
|
+
!Array.isArray(existing)) {
|
|
327
|
+
next[key] = mergeConfig(existing, value);
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
next[key] = value;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return next;
|
|
334
|
+
}
|
|
335
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/host/runtime.ts"],"names":[],"mappings":"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"}
|