P4
This commit is contained in:
+51
-1
@@ -8,6 +8,8 @@ const Agent = require(path.join(harnessPath, 'index.js'));
|
||||
|
||||
let loadPromise = null;
|
||||
let ownerCount = 0;
|
||||
let operationTail = Promise.resolve();
|
||||
const auxiliaryModels = new Map();
|
||||
|
||||
export const QVAC_MASTER = Object.freeze({
|
||||
configPath: process.env.QVAC_CONFIG_PATH,
|
||||
@@ -55,10 +57,58 @@ export async function acquireQvac() {
|
||||
return loadPromise;
|
||||
}
|
||||
|
||||
export async function qvacSdk() {
|
||||
return Agent.engine.ensureInit();
|
||||
}
|
||||
|
||||
export function withQvacMaster(task) {
|
||||
const operation = operationTail.then(task, task);
|
||||
operationTail = operation.catch(() => {});
|
||||
return operation;
|
||||
}
|
||||
|
||||
function resolveSdkAsset(sdk, name) {
|
||||
if (name && typeof name !== 'string') return name;
|
||||
return sdk[name] || sdk.models?.[name] || name;
|
||||
}
|
||||
|
||||
function resolveModelConfigAssets(sdk, config) {
|
||||
const copy = { ...config };
|
||||
for (const key of ['vadModelSrc', 'projectionModelSrc', 'vocabModelSrc']) {
|
||||
if (typeof copy[key] === 'string') copy[key] = resolveSdkAsset(sdk, copy[key]);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Load ASR/TTS models in the same SDK worker and under the same master lock.
|
||||
* These are auxiliary model IDs; they do not create another QVAC runtime. */
|
||||
export async function loadAuxiliaryModel(name, modelConfig = {}) {
|
||||
if (!name) throw new Error('auxiliary QVAC model name is required');
|
||||
const existing = auxiliaryModels.get(String(name));
|
||||
if (existing) return existing;
|
||||
const sdk = await qvacSdk();
|
||||
if (typeof sdk.loadModel !== 'function') throw new Error('QVAC SDK does not expose loadModel()');
|
||||
const modelId = await withQvacMaster(() => sdk.loadModel({
|
||||
modelSrc: resolveSdkAsset(sdk, name),
|
||||
modelConfig: { ...resolveModelConfigAssets(sdk, modelConfig), device: 'gpu', gpu_layers: QVAC_MASTER.gpuLayers, 'mmproj-use-gpu': true },
|
||||
}));
|
||||
auxiliaryModels.set(String(name), modelId);
|
||||
return modelId;
|
||||
}
|
||||
|
||||
export async function unloadAuxiliaryModel(modelId) {
|
||||
if (!modelId) return;
|
||||
const sdk = await qvacSdk();
|
||||
if (typeof sdk.unloadModel === 'function') await withQvacMaster(() => sdk.unloadModel({ modelId }));
|
||||
for (const [name, id] of auxiliaryModels) if (id === modelId) auxiliaryModels.delete(name);
|
||||
}
|
||||
|
||||
export function releaseQvac() { ownerCount = Math.max(0, ownerCount - 1); }
|
||||
|
||||
export async function closeQvac() {
|
||||
if (ownerCount > 0) return;
|
||||
for (const modelId of auxiliaryModels.values()) await unloadAuxiliaryModel(modelId).catch(() => {});
|
||||
auxiliaryModels.clear();
|
||||
loadPromise = null;
|
||||
await Agent.engine.close();
|
||||
}
|
||||
@@ -101,7 +151,7 @@ export async function callQvac(method, input) {
|
||||
}
|
||||
|
||||
export function qvacStatus() {
|
||||
return { ...QVAC_MASTER, owners: ownerCount, loaded: Agent.engine.getLoaded() };
|
||||
return { ...QVAC_MASTER, owners: ownerCount, loaded: Agent.engine.getLoaded(), auxiliaryModels: auxiliaryModels.size };
|
||||
}
|
||||
|
||||
export { Agent };
|
||||
|
||||
Reference in New Issue
Block a user