Skip to content

ASR plugin development

External speech-to-text plugins under storage/plugins/asr/*
Repo: https://github.com/vastsa/BokeBox · License: LGPL-3.0 · apiVersion = 1

Overview: ASR / TTS plugins.
Example: asr-plugin-echo.
TTS: TTS plugins.

Chinese full guide (same content family): /development/asr-plugin


Principles

  1. Only audio → text — no Job writes, no SQLite, no cron
  2. Input is a local pathinput.audioPath prepared by the host
  3. Strict activation — runtime uses Settings asrProvider; fail loud on misconfig
  4. Default off / least privilege — prefer defaultEnabled: false
  5. Hot reload — drop into storage/plugins/asr/<dir>/ then rescan

Layout

text
storage/plugins/asr/<dir>/
  plugin.json
  index.js
bash
cp -R examples/asr-plugin-echo storage/plugins/asr/echo
curl -s -X POST http://localhost:8787/api/asr-plugins/rescan
curl -s -X PATCH http://localhost:8787/api/asr-plugins/asr.echo \
  -H 'Content-Type: application/json' \
  -d '{"enabled":true}'

Set as current under Settings → Plugins or set asrProvider in AI services.


plugin.json

FieldRequiredNotes
idyese.g. asr.myprovider
name / version / entryyesESM entry relative to dir
apiVersionyes1
riskLevelrecommendedlow | medium | high
defaultEnabledrecommendedusually false
permissionsnoe.g. config, network
suggestedModelnoUI hint
configSchemanoSettings form fields

Export contract

Loader requires:

  • name, version, riskLevel, defaultEnabled
  • isAvailable(): boolean
  • async transcribe(input, ctx)

Input

FieldNotes
audioPathrequired local file
formatoptional mp3 / wav / …
modeloptional override
languageoptional hint

Output

FieldNotes
textrequired transcript
providerusually plugin id
modeloptional
demooptional

Context

storageDir, config, getConfig(key), optional signal (AbortSignal).

Minimal plugin

js
import fs from 'node:fs/promises';

export default {
  id: 'asr.myprovider',
  name: 'My ASR',
  version: '0.1.0',
  riskLevel: 'medium',
  defaultEnabled: false,
  isAvailable() {
    return true;
  },
  async transcribe(input, ctx) {
    const audioPath = String(input?.audioPath || '');
    if (!audioPath) throw new Error('audioPath required');
    await fs.access(audioPath);
    const apiKey = String(ctx?.getConfig?.('apiKey') || '').trim();
    if (!apiKey) throw new Error('Configure apiKey in plugin settings');
    // call your API with the file at audioPath …
    return {
      text: '…',
      provider: 'asr.myprovider',
      model: 'my-model',
    };
  },
};

API

MethodPath
GET/api/asr-plugins
POST/api/asr-plugins/rescan
PATCH/api/asr-plugins/:id
PUT/api/asr-plugins/:id/config

Checklist

  1. Manifest + ESM export valid
  2. Rescan lists plugin without loadError
  3. Enable + set asrProvider
  4. Run a video/audio job through transcribe
  5. Missing credentials produce a clear error