<?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: Sheikh Aminul</title>
    <description>The latest articles on DEV Community by Sheikh Aminul (@sheikaminul).</description>
    <link>https://dev.to/sheikaminul</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%2F1051773%2F6ca4cf47-4e9b-428e-94e0-a0427d43cef6.jpg</url>
      <title>DEV Community: Sheikh Aminul</title>
      <link>https://dev.to/sheikaminul</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sheikaminul"/>
    <language>en</language>
    <item>
      <title>How to fix punctuation in speech-to-text and LLM output without calling a model</title>
      <dc:creator>Sheikh Aminul</dc:creator>
      <pubDate>Sat, 22 Aug 2026 07:49:25 +0000</pubDate>
      <link>https://dev.to/sheikaminul/how-to-fix-punctuation-in-speech-to-text-and-llm-output-without-calling-a-model-3ofl</link>
      <guid>https://dev.to/sheikaminul/how-to-fix-punctuation-in-speech-to-text-and-llm-output-without-calling-a-model-3ofl</guid>
      <description>&lt;p&gt;If you've ever wired up the Web Speech API and rendered the result straight to the page, you've seen this:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recognition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SpeechRecognition&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webkitSpeechRecognition&lt;/span&gt;&lt;span class="p"&gt;)()&lt;/span&gt;
&lt;span class="nx"&gt;recognition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;recognition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onresult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transcript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;transcript&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// 'can you send me the report'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;recognition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The transcription is correct. The formatting isn't. No leading capital, no question mark. The same thing happens with streamed LLM tokens that get cut off before the final punctuation lands, and with any form field where users type fast and don't bother.&lt;/p&gt;

&lt;p&gt;The instinctive fix is to send it back through a model. "Clean up this text." It works, and it's a strange amount of machinery for the problem: a network round trip, tokens billed, latency you can feel, and a nondeterministic result for a task that is almost entirely mechanical.&lt;/p&gt;

&lt;p&gt;Capitalizing the first letter is trivial. The actual question is &lt;strong&gt;which mark goes at the end&lt;/strong&gt; — and that turns out to be the only interesting part.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real problem is classification, not punctuation
&lt;/h2&gt;

&lt;p&gt;To punctuate a sentence you first have to know what kind of sentence it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;can you send me the report&lt;/code&gt; → interrogative → &lt;code&gt;?&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;this is amazing&lt;/code&gt; → exclamatory → &lt;code&gt;!&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;the meeting is at three&lt;/code&gt; → declarative → &lt;code&gt;.&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's a three-way classification problem. And for unpunctuated English it's a problem with a lot of surface structure to exploit — interrogatives overwhelmingly start with an auxiliary or a wh-word, exclamatives have their own recognizable openers. You don't need a language model to notice &lt;code&gt;can you&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Which is what I ended up building. &lt;code&gt;sentencify&lt;/code&gt; is a small library that does the classification with ordered regular expressions, then applies the punctuation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;sentencify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;correctSentence&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sentencify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;correctSentence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;can you send me the report&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// 'Can you send me the report?'&lt;/span&gt;
&lt;span class="nf"&gt;correctSentence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;this is amazing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;             &lt;span class="c1"&gt;// 'This is amazing!'&lt;/span&gt;
&lt;span class="nf"&gt;correctSentence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;the meeting is at three&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;// 'The meeting is at three.'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No await. No model. No dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Punctuation is not universal, and this is where it gets interesting
&lt;/h2&gt;

&lt;p&gt;If you're only shipping English, you could write the naive version yourself in an afternoon. The moment you add a second language, the assumptions break.&lt;/p&gt;

&lt;p&gt;Spanish opens a question &lt;em&gt;and&lt;/em&gt; closes it — &lt;code&gt;¿Cuál es tu nombre?&lt;/code&gt; — so you can't just append to the end, you have to prepend too. French typography puts a space before &lt;code&gt;?&lt;/code&gt;, &lt;code&gt;!&lt;/code&gt;, and &lt;code&gt;:&lt;/code&gt; — &lt;code&gt;Comment vas-tu ?&lt;/code&gt; — and text that omits it looks wrong to a French reader in the way &lt;code&gt;Hello ,world&lt;/code&gt; looks wrong to an English one. Japanese uses &lt;code&gt;。&lt;/code&gt; and &lt;code&gt;？&lt;/code&gt;, not the ASCII marks.&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="nf"&gt;correctSentence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cuál es tu nombre&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;es&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;// '¿Cuál es tu nombre?'&lt;/span&gt;
&lt;span class="nf"&gt;correctSentence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comment vas-tu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;// 'Comment vas-tu ?'&lt;/span&gt;
&lt;span class="nf"&gt;correctSentence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kannst du mir helfen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// 'Kannst du mir helfen?'&lt;/span&gt;
&lt;span class="nf"&gt;correctSentence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;すごい&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ja&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                  &lt;span class="c1"&gt;// 'すごい！'&lt;/span&gt;
&lt;span class="nf"&gt;correctSentence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;qual é o seu nome&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;// 'Qual é o seu nome?'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six languages currently: English, Japanese, German, Spanish, French, Portuguese.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works, and why the ordering is load-bearing
&lt;/h2&gt;

&lt;p&gt;Each language is an ordered array of rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SentenceTypeDetectExpressionSets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;RegExp&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="s1"&gt;exclamatory&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;interrogative&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;declarative&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;detectSentenceType&lt;/code&gt; walks the array top to bottom and returns the type of the &lt;strong&gt;first&lt;/strong&gt; rule that matches. Nothing matches, it falls through to declarative.&lt;/p&gt;

&lt;p&gt;This is worth being explicit about, because it's the main thing that makes the library easy to reason about and also the main thing that makes it fragile. First-match means a broad interrogative pattern placed above a narrow exclamatory one will silently swallow it. The bug is invisible until someone reports one specific sentence coming out wrong.&lt;/p&gt;

&lt;p&gt;The alternative design is to score every match and take the highest confidence. More robust, considerably harder to debug when it misfires. I chose debuggable, and I'm not certain that was the right call.&lt;/p&gt;

&lt;p&gt;Because it's debuggable, the rule sets are a public export rather than a hidden internal:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;expressionsByLanguage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sentencify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Read the actual ordered rules for a language and see which one fires&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expressionsByLanguage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;en&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a sentence classifies wrong, you can find the exact rule responsible instead of filing an issue against a black box.&lt;/p&gt;

&lt;h2&gt;
  
  
  The properties that come from not using a model
&lt;/h2&gt;

&lt;p&gt;This is the part that actually matters for production use:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deterministic.&lt;/strong&gt; Same input, same output, forever. You can write assertions against it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Synchronous.&lt;/strong&gt; No promise, no warm-up, no cold start. Cheap enough to run on every keystroke in a controlled input, or on every token in a stream.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Idempotent.&lt;/strong&gt; Already-punctuated text passes through untouched. You will not get &lt;code&gt;Hello world..&lt;/code&gt; by calling it twice, which matters when the call sits somewhere in a pipeline you don't fully control.&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="nf"&gt;correctSentence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Already punctuated.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// 'Already punctuated.' — unchanged&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Offline.&lt;/strong&gt; No network call means no failure mode where your text formatting goes down because a provider had an incident.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small.&lt;/strong&gt; Zero runtime dependencies, ESM-only, &lt;code&gt;sideEffects: false&lt;/code&gt;, under 40 KB unpacked.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it deliberately doesn't do
&lt;/h2&gt;

&lt;p&gt;It is not a grammar checker. It won't fix spelling, agreement, or word choice. It won't split a run-on into sentences. It classifies and punctuates, and that's the whole scope.&lt;/p&gt;

&lt;p&gt;And regex rules will get sentences wrong that a model would get right. Indirect questions are the obvious failure class — &lt;code&gt;I wonder if you could send the report&lt;/code&gt; is declarative but reads interrogative to a naive pattern. That's the trade. You give up ceiling accuracy and you get determinism, speed, inspectability, and no bill.&lt;/p&gt;

&lt;p&gt;For a lot of pipelines that's the right trade, because the text was going to be displayed unpunctuated otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it fits
&lt;/h2&gt;

&lt;p&gt;The pattern I'd suggest is treating this as a &lt;strong&gt;finishing pass&lt;/strong&gt;, not a replacement for anything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After a speech-to-text transcript, before display or storage&lt;/li&gt;
&lt;li&gt;After an LLM completion, as the last step before rendering&lt;/li&gt;
&lt;li&gt;On chat and support-ticket input, to normalize formatting&lt;/li&gt;
&lt;li&gt;On short-answer form fields, comments, reviews&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It runs after the expensive thing has already happened, and it costs nothing.&lt;/p&gt;

&lt;p&gt;Which makes the fix to the example this article opened with a one-line change:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;correctSentence&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sentencify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;recognition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onresult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transcript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;transcript&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;correctSentence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;recognition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// 'Can you send me the report?'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that &lt;code&gt;recognition.lang&lt;/code&gt; is a full locale — &lt;code&gt;'en-US'&lt;/code&gt;, &lt;code&gt;'fr-FR'&lt;/code&gt;, &lt;code&gt;'ja-JP'&lt;/code&gt; — and gets passed straight through. Both &lt;code&gt;correctSentence&lt;/code&gt; and &lt;code&gt;isPunctuationAvailable&lt;/code&gt; match on the first two characters, so locale variants resolve to the base language and you don't have to slice it yourself. Unsupported languages still get capitalized, they just skip punctuation.&lt;/p&gt;

&lt;p&gt;In TypeScript the &lt;code&gt;language&lt;/code&gt; parameter is typed as a narrow union of the six supported codes, so a raw locale string needs a guard or a cast — &lt;code&gt;isPunctuationAvailable(recognition.lang)&lt;/code&gt; is there for exactly that check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it and tell me where it's wrong
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;sentencify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;npm: &lt;a href="https://www.npmjs.com/package/sentencify" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/sentencify&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/SheikhAminul/sentencify" rel="noopener noreferrer"&gt;https://github.com/SheikhAminul/sentencify&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's new, and the English rules have had the most attention. If you throw a sentence at it that classifies wrong, &lt;a href="https://github.com/SheikhAminul/sentencify/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt; — misclassified sentences are the single most useful thing anyone can send me right now.&lt;/p&gt;

&lt;p&gt;Adding a language is one file: the ordered rule array plus that language's punctuation conventions, no core changes. Arabic (&lt;code&gt;؟&lt;/code&gt;), Hindi (&lt;code&gt;।&lt;/code&gt;), and Greek (&lt;code&gt;;&lt;/code&gt;) would all be interesting, since in each of them the question mark isn't &lt;code&gt;?&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>node</category>
      <category>nlp</category>
    </item>
    <item>
      <title>ChatGPT Chrome Extension: Talk to ChatGPT in over 140 languages!</title>
      <dc:creator>Sheikh Aminul</dc:creator>
      <pubDate>Fri, 24 Mar 2023 19:46:31 +0000</pubDate>
      <link>https://dev.to/sheikaminul/chatgpt-chrome-extension-talk-to-chatgpt-in-over-140-languages-25hf</link>
      <guid>https://dev.to/sheikaminul/chatgpt-chrome-extension-talk-to-chatgpt-in-over-140-languages-25hf</guid>
      <description>&lt;p&gt;Are you tired of typing out your queries and responses to ChatGPT? Say hello to "&lt;a href="https://chrome.google.com/webstore/detail/voice-control-for-openai/baahncfnjojaofhdmdfkpeadigoemkif"&gt;Voice Control for OpenAI ChatGPT&lt;/a&gt;" Chrome Extension, which allows you to talk to ChatGPT using your microphone in over 140 languages!&lt;/p&gt;

&lt;p&gt;With this extension, you can ask questions and hear responses from ChatGPT with a natural voice. No more struggling with typing out your questions or trying to decipher the responses. The natural voice feature ensures that the conversation is easy to understand and follow.&lt;/p&gt;

&lt;p&gt;But that's not all, the ChatGPT Chrome Extension also gives you the ability to change the read aloud (text to speech) voice, language, and speed. You can customize the extension to suit your preferences and make the conversation even more comfortable for you.&lt;/p&gt;

&lt;p&gt;Using &lt;a href="https://chrome.google.com/webstore/detail/voice-control-for-openai/baahncfnjojaofhdmdfkpeadigoemkif"&gt;Voice Control for OpenAI ChatGPT&lt;/a&gt; is easy. Just install the extension from &lt;a href="https://chrome.google.com/webstore/detail/voice-control-for-openai/baahncfnjojaofhdmdfkpeadigoemkif"&gt;this (Chrome Web Store) link&lt;/a&gt;, give it permission to access your microphone, and start speaking to ChatGPT.&lt;/p&gt;

&lt;p&gt;This extension is perfect for anyone who wants to have a natural and effortless conversation with ChatGPT. Whether you're a student trying to learn a new language or just someone looking for an easier way to communicate, the ChatGPT Chrome Extension is the perfect tool for you.&lt;/p&gt;

&lt;p&gt;In summary, the ChatGPT Chrome Extension is a game-changer for anyone who wants to have an effortless conversation with ChatGPT. With the ability to talk to ChatGPT using your microphone in over 140 languages and the customization options, this extension is a must-have for anyone looking for an easier way to communicate.&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>openai</category>
    </item>
  </channel>
</rss>
