<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gerhard Engel</title>
    <description>The latest articles on DEV Community by Gerhard Engel (@gerhard_engel_4dcf99a2924).</description>
    <link>https://dev.to/gerhard_engel_4dcf99a2924</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4233133%2Fdfa7bd1e-214c-4da1-aa35-3e02996a8118.jpg</url>
      <title>DEV Community: Gerhard Engel</title>
      <link>https://dev.to/gerhard_engel_4dcf99a2924</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gerhard_engel_4dcf99a2924"/>
    <language>en</language>
    <item>
      <title>Self-Hosted Indian Language STT Server – VEXYL-STT Open Source</title>
      <dc:creator>Gerhard Engel</dc:creator>
      <pubDate>Sun, 08 Nov 2026 05:06:53 +0000</pubDate>
      <link>https://dev.to/gerhard_engel_4dcf99a2924/self-hosted-indian-language-stt-server-vexyl-stt-open-source-6id</link>
      <guid>https://dev.to/gerhard_engel_4dcf99a2924/self-hosted-indian-language-stt-server-vexyl-stt-open-source-6id</guid>
      <description>&lt;p&gt;If you’ve ever tried to add &lt;strong&gt;self-hosted Indian language speech to text&lt;/strong&gt; to a production system, you know the problem. Cloud STT APIs either don’t support Indian languages well, charge per-minute fees that kill your margins, or send audio to servers in the US — which is a non-starter for healthcare and government use cases. We built &lt;strong&gt;VEXYL-STT&lt;/strong&gt; to fix this, and today we’re releasing it as open source.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/vexyl-ai/vexyl-stt" rel="noopener noreferrer"&gt;VEXYL-STT&lt;/a&gt; is a free, self-hosted speech-to-text server wrapping AI4Bharat’s &lt;strong&gt;IndicConformer 600M multilingual model&lt;/strong&gt;. It supports 14 Indian languages, runs on CPU (no GPU required for typical workloads), and exposes both a WebSocket streaming API and a REST batch API on a single port. Apache 2.0 licensed. No API keys. No per-minute billing. Your audio never leaves your server.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is VEXYL-STT and Why Did We Build It?
&lt;/h2&gt;

&lt;p&gt;VEXYL-STT started as an internal component of the &lt;a href="https://vexyl.ai/" rel="noopener noreferrer"&gt;VEXYL AI Voice Gateway&lt;/a&gt; — our enterprise platform that bridges Asterisk/FreePBX telephony infrastructure with modern AI services. We needed a self-hosted STT option for deployments where cloud APIs are not viable: hospitals with patient audio data, government agencies with data sovereignty requirements, and enterprises that simply can’t afford ₹1–3 per minute of STT billing at scale.&lt;/p&gt;

&lt;p&gt;We chose AI4Bharat’s IndicConformer 600M multilingual model as the backbone because, frankly, nothing else comes close for Indian languages. It’s the most capable open-source Indian ASR model available, trained on thousands of hours of Indic language audio across 22 official languages. We extracted the STT component, wrapped it in a production-ready server, and are now releasing it so the community can use it independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Indian Languages Does VEXYL-STT Support?
&lt;/h2&gt;

&lt;p&gt;The current release supports &lt;strong&gt;14 Indian languages&lt;/strong&gt; out of the box:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language Code&lt;/th&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Language Code&lt;/th&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ml-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Malayalam&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mr-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Marathi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hi-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hindi&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pa-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Punjabi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ta-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tamil&lt;/td&gt;
&lt;td&gt;&lt;code&gt;or-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Odia&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;te-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Telugu&lt;/td&gt;
&lt;td&gt;&lt;code&gt;as-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Assamese&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kn-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Kannada&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ur-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Urdu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bn-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bengali&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sa-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sanskrit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gu-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gujarati&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ne-IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nepali&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Switch between languages at the session level — no server restart needed. Just pass the language code in your WebSocket start message or batch API request. If you pass an unknown code, it defaults to Malayalam (&lt;code&gt;ml&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does the API Work?
&lt;/h2&gt;

&lt;p&gt;VEXYL-STT runs two modes on a single port — you don’t need to run separate services for streaming vs. batch use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-Time WebSocket Streaming
&lt;/h3&gt;

&lt;p&gt;Connect over WebSocket, send raw 16kHz 16-bit mono PCM audio as binary frames, and receive JSON transcripts in real time. The server uses energy-based VAD to detect speech boundaries and fires a &lt;code&gt;final&lt;/code&gt; message when an utterance completes. This is the right mode for telephony integrations, browser mic capture, and any scenario where you’re streaming live audio.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Connect and start a Malayalam session&lt;/span&gt;
&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ml-IN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;abc123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Stream raw PCM audio as binary frames&lt;/span&gt;
&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pcmBuffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Receive transcript&lt;/span&gt;
&lt;span class="c1"&gt;// {"type":"final","text":"ഡോക്ടറെ കാണണം","lang":"ml-IN","latency_ms":280}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Batch REST API
&lt;/h3&gt;

&lt;p&gt;For file-based transcription or systems with their own VAD (including our own VEXYL Voice Gateway which uses Silero VAD v5), the batch API accepts WAV, MP3, FLAC, OGG, and M4A files up to 25MB / 5 minutes. Submit a file, poll for status, retrieve the transcript. Supported formats cover almost everything you’ll encounter in the field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8091/batch/transcribe &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-API-Key: your-secret"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"file=@patient-recording.wav"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"language_code=ml-IN"&lt;/span&gt;

&lt;span class="c"&gt;# Response: {"job_id":"batch_a1b2c3","status":"queued","audio_duration":4.52}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How Do I Get It Running in 5 Minutes?
&lt;/h2&gt;

&lt;p&gt;The quickest path is the automated setup script. You’ll need Python 3.10+, a HuggingFace account with access approved for the &lt;a href="https://huggingface.co/ai4bharat/indic-conformer-600m-multilingual" rel="noopener noreferrer"&gt;gated IndicConformer model&lt;/a&gt;, and about 3GB of free disk space for the model weights.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Request access to the model at &lt;code&gt;huggingface.co/ai4bharat/indic-conformer-600m-multilingual&lt;/code&gt; (approval is typically quick)&lt;/li&gt;
&lt;li&gt;Clone the repo: &lt;code&gt;git clone https://github.com/vexyl-ai/vexyl-stt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;./setup.sh&lt;/code&gt; — it handles venv creation, dependency installation, HuggingFace authentication, and model download&lt;/li&gt;
&lt;li&gt;Start the server: &lt;code&gt;./run.sh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Open &lt;code&gt;test.html&lt;/code&gt; in your browser to test live transcription from your microphone&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For Docker deployments, pass your HuggingFace token as a build arg and the model gets baked into the image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;HF_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HF_TOKEN&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; vexyl-stt &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;VEXYL_STT_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mysecret vexyl-stt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One thing worth knowing before you start: the HuggingFace gated model approval is required. If you hit a 401 or 403, run &lt;code&gt;huggingface-cli whoami&lt;/code&gt; and verify your token has read access and that your access request has been approved. This catches most people out.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does VEXYL-STT Compare to Cloud STT for Indian Languages?
&lt;/h2&gt;

&lt;p&gt;I’ll be direct: if you’re doing low-volume transcription with no data sovereignty concerns, Sarvam AI’s API is excellent and I’d use it. But if you’re running at scale, building in healthcare, or deploying for government — the economics and compliance picture shifts dramatically in favour of self-hosting.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;VEXYL-STT (Self-Hosted)&lt;/th&gt;
&lt;th&gt;Sarvam AI API&lt;/th&gt;
&lt;th&gt;Google STT (Indian)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost per minute&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;₹0 (infrastructure only)&lt;/td&gt;
&lt;td&gt;Paid per minute&lt;/td&gt;
&lt;td&gt;Paid per minute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Indian languages&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;14 languages&lt;/td&gt;
&lt;td&gt;10+ languages&lt;/td&gt;
&lt;td&gt;Limited coverage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data sovereignty&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Audio stays on your server&lt;/td&gt;
&lt;td&gt;❌ Sent to cloud&lt;/td&gt;
&lt;td&gt;❌ Sent to Google&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HIPAA / healthcare&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Viable&lt;/td&gt;
&lt;td&gt;Requires DPA&lt;/td&gt;
&lt;td&gt;Requires DPA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Latency (India)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;280–400ms (same machine)&lt;/td&gt;
&lt;td&gt;300–800ms (network)&lt;/td&gt;
&lt;td&gt;400–1000ms (network)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Offline capable&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The latency numbers above are from our production deployment at a tertiary care hospital in Kerala processing Malayalam patient interactions. On the same VPS, local WebSocket transcription consistently returns under 350ms. Cloud providers add network round-trip time on top of model inference — which matters a lot when you’re building a real-time voice assistant.&lt;/p&gt;

&lt;h2&gt;
  
  
  CTC vs RNNT: Which Decoding Mode Should I Use?
&lt;/h2&gt;

&lt;p&gt;The IndicConformer model supports both CTC and RNNT decoding. VEXYL-STT defaults to CTC because it’s faster — typically 30–50% lower latency on CPU. RNNT is more accurate, especially for longer utterances and noisy telephony audio, but adds latency.&lt;/p&gt;

&lt;p&gt;My recommendation: start with CTC (&lt;code&gt;VEXYL_STT_DECODE=ctc&lt;/code&gt;), measure your accuracy on real audio, and switch to RNNT (&lt;code&gt;VEXYL_STT_DECODE=rnnt&lt;/code&gt;) if accuracy is the limiting factor rather than latency. For most patient interaction use cases we’ve tested, CTC accuracy is sufficient and the latency advantage is worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production Deployment Tips
&lt;/h2&gt;

&lt;p&gt;A few things we learned running this in production that aren’t obvious from the docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use PM2 to manage the process.&lt;/strong&gt; The repo includes PM2 setup instructions. Set &lt;code&gt;--restart-delay=3000&lt;/code&gt; so a crash doesn’t hammer the model reload loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The VAD silence threshold (0.015) may need tuning for telephony audio.&lt;/strong&gt; PSTN audio often has different gain characteristics than microphone audio. If you’re getting premature cut-offs or missed utterances, adjust the &lt;code&gt;SILENCE_THRESHOLD&lt;/code&gt; constant in &lt;code&gt;vexyl_stt_server.py&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CPU is fine up to ~10 concurrent streams.&lt;/strong&gt; At that point, look at GPU acceleration. Swap to the CUDA PyTorch build and set &lt;code&gt;VEXYL_STT_DEVICE=auto&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For Asterisk use cases, bring your own VAD.&lt;/strong&gt; The VEXYL Voice Gateway uses Silero VAD v5 which is far more accurate than energy-threshold VAD. Use the batch REST API with pre-segmented speech rather than relying on the built-in WebSocket VAD for telephony.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get Involved
&lt;/h2&gt;

&lt;p&gt;VEXYL-STT is actively maintained and we welcome contributions — new language support, performance improvements, integration examples, and documentation. Star the repo if it’s useful, open an issue if you find a bug, and submit a PR if you’ve built something on top of it.&lt;/p&gt;

&lt;p&gt;If you’re looking to go further — full telephony AI with Asterisk, multi-language IVR, voice bots for healthcare or enterprise — that’s what the &lt;a href="https://vexyl.ai/" rel="noopener noreferrer"&gt;VEXYL AI Voice Gateway&lt;/a&gt; is built for. It’s a self-hosted platform where you bring your own provider keys, with support for Indian languages over PSTN and SIP.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://vexyl.ai/self-hosted-indian-language-stt-server-vexyl-stt-open-source/" rel="noopener noreferrer"&gt;vexyl.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>ai</category>
      <category>speechrecognition</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
