import { getLocalSpeechModelDir, DEFAULT_LOCAL_STT_MODEL, DEFAULT_LOCAL_TTS_MODEL, LocalSttModelIdSchema, LocalTtsModelIdSchema, } from "./models.js";
import { SherpaOfflineRecognizerEngine } from "./sherpa/sherpa-offline-recognizer.js";
import { SherpaOnnxParakeetSTT } from "./sherpa/sherpa-parakeet-stt.js";
import { SherpaParakeetRealtimeTranscriptionSession } from "./sherpa/sherpa-parakeet-realtime-session.js";
import { SherpaOnnxTTS } from "./sherpa/sherpa-tts.js";
import { ensureSileroVadModel, SherpaSileroTurnDetectionProvider, } from "./sherpa/silero-vad-provider.js";
function buildModelDownloadHint(modelId) {
    return `Use 'paseo speech download --model ${modelId}' to download this model.`;
}
function resolveConfiguredLocalModels(speechConfig) {
    return {
        dictationLocalSttModel: LocalSttModelIdSchema.parse(speechConfig?.local?.models.dictationStt ?? DEFAULT_LOCAL_STT_MODEL),
        voiceLocalSttModel: LocalSttModelIdSchema.parse(speechConfig?.local?.models.voiceStt ?? DEFAULT_LOCAL_STT_MODEL),
        voiceLocalTtsModel: LocalTtsModelIdSchema.parse(speechConfig?.local?.models.voiceTts ?? DEFAULT_LOCAL_TTS_MODEL),
    };
}
export function getLocalSpeechAvailability(speechConfig) {
    const localConfig = speechConfig?.local ?? null;
    return {
        configured: Boolean(localConfig),
        modelsDir: localConfig?.modelsDir ?? null,
    };
}
function computeRequiredLocalModelIds(params) {
    const ids = new Set();
    if (params.providers.dictationStt.enabled !== false &&
        params.providers.dictationStt.provider === "local") {
        ids.add(params.models.dictationLocalSttModel);
    }
    if (params.providers.voiceStt.enabled !== false &&
        params.providers.voiceStt.provider === "local") {
        ids.add(params.models.voiceLocalSttModel);
    }
    if (params.providers.voiceTts.enabled !== false &&
        params.providers.voiceTts.provider === "local") {
        ids.add(params.models.voiceLocalTtsModel);
    }
    return Array.from(ids);
}
async function createLocalSttEngine(params) {
    const { modelId, modelsDir, logger } = params;
    const modelDir = getLocalSpeechModelDir(modelsDir, modelId);
    return new SherpaOfflineRecognizerEngine({
        model: {
            kind: "nemo_transducer",
            encoder: `${modelDir}/encoder.int8.onnx`,
            decoder: `${modelDir}/decoder.int8.onnx`,
            joiner: `${modelDir}/joiner.int8.onnx`,
            tokens: `${modelDir}/tokens.txt`,
        },
        numThreads: 2,
        debug: 0,
    }, logger);
}
function isLocalProviderEnabled(provider) {
    return provider.enabled !== false && provider.provider === "local";
}
async function initializeLocalTurnDetection(localConfig, logger) {
    let vadModelPath;
    if (localConfig) {
        try {
            vadModelPath = await ensureSileroVadModel(localConfig.modelsDir, logger);
        }
        catch (err) {
            logger.warn({ err }, "Failed to provision Silero VAD model, falling back to bundled");
        }
    }
    return new SherpaSileroTurnDetectionProvider({ modelPath: vadModelPath }, logger);
}
async function initializeLocalVoiceStt(params) {
    const { localConfig, modelId, logger, getLocalSttEngine } = params;
    if (!localConfig) {
        logger.warn({ configured: false }, "Local STT selected for voice but local provider config is missing; STT will be unavailable");
        return null;
    }
    const voiceEngine = await getLocalSttEngine(modelId);
    return voiceEngine ? new SherpaOnnxParakeetSTT({ engine: voiceEngine }, logger) : null;
}
async function initializeLocalDictationStt(params) {
    const { localConfig, modelId, logger, getLocalSttEngine } = params;
    if (!localConfig) {
        logger.warn({ configured: false }, "Local STT selected for dictation but local provider config is missing; dictation STT will be unavailable");
        return null;
    }
    const dictationEngine = await getLocalSttEngine(modelId);
    if (dictationEngine) {
        return {
            id: "local",
            createSession: () => new SherpaParakeetRealtimeTranscriptionSession({ engine: dictationEngine }),
        };
    }
    return null;
}
async function initializeLocalVoiceTts(params) {
    const { localConfig, speechConfig, localModels, logger } = params;
    if (!localConfig) {
        logger.warn({ configured: false }, "Local TTS selected for voice but local provider config is missing; TTS will be unavailable");
        return null;
    }
    try {
        const modelDir = getLocalSpeechModelDir(localConfig.modelsDir, localModels.voiceLocalTtsModel);
        return new SherpaOnnxTTS({
            preset: localModels.voiceLocalTtsModel,
            modelDir,
            speakerId: speechConfig?.local?.models.voiceTtsSpeakerId,
            speed: speechConfig?.local?.models.voiceTtsSpeed,
        }, logger);
    }
    catch (err) {
        logger.warn({
            err,
            modelsDir: localConfig.modelsDir,
            modelId: localModels.voiceLocalTtsModel,
            hint: buildModelDownloadHint(localModels.voiceLocalTtsModel),
        }, "Local TTS engine unavailable");
        return null;
    }
}
export async function initializeLocalSpeechServices(params) {
    const { providers, logger, speechConfig } = params;
    const localConfig = speechConfig?.local ?? null;
    const localModels = resolveConfiguredLocalModels(speechConfig);
    let sttService = null;
    let ttsService = null;
    let dictationSttService = null;
    let turnDetectionService = null;
    let localVoiceTtsProvider = null;
    const requiredLocalModelIds = computeRequiredLocalModelIds({
        providers,
        models: localModels,
    });
    const localSttEngines = new Map();
    const getLocalSttEngine = async (modelId) => {
        const existing = localSttEngines.get(modelId);
        if (existing) {
            return existing;
        }
        if (!localConfig) {
            return null;
        }
        try {
            const created = await createLocalSttEngine({
                modelId,
                modelsDir: localConfig.modelsDir,
                logger,
            });
            localSttEngines.set(modelId, created);
            return created;
        }
        catch (err) {
            logger.warn({
                err,
                modelsDir: localConfig.modelsDir,
                modelId,
                hint: buildModelDownloadHint(modelId),
            }, "Local STT engine unavailable");
            return null;
        }
    };
    if (isLocalProviderEnabled(providers.voiceTurnDetection)) {
        turnDetectionService = await initializeLocalTurnDetection(localConfig, logger);
    }
    if (isLocalProviderEnabled(providers.voiceStt)) {
        sttService = await initializeLocalVoiceStt({
            localConfig,
            modelId: localModels.voiceLocalSttModel,
            logger,
            getLocalSttEngine,
        });
    }
    if (isLocalProviderEnabled(providers.dictationStt)) {
        dictationSttService = await initializeLocalDictationStt({
            localConfig,
            modelId: localModels.dictationLocalSttModel,
            logger,
            getLocalSttEngine,
        });
    }
    if (isLocalProviderEnabled(providers.voiceTts)) {
        localVoiceTtsProvider = await initializeLocalVoiceTts({
            localConfig,
            speechConfig,
            localModels,
            logger,
        });
        if (localVoiceTtsProvider) {
            ttsService = localVoiceTtsProvider;
        }
    }
    const cleanup = () => {
        const maybeFreeable = localVoiceTtsProvider;
        if (typeof maybeFreeable?.free === "function") {
            maybeFreeable.free();
        }
        for (const engine of localSttEngines.values()) {
            engine.free();
        }
    };
    return {
        turnDetectionService,
        sttService,
        ttsService,
        dictationSttService,
        localVoiceTtsProvider,
        localModelConfig: localConfig
            ? {
                modelsDir: localConfig.modelsDir,
                defaultModelIds: requiredLocalModelIds,
            }
            : null,
        availability: getLocalSpeechAvailability(speechConfig),
        cleanup,
    };
}
//# sourceMappingURL=runtime.js.map