<?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: Abhishek Mishra</title>
    <description>The latest articles on DEV Community by Abhishek Mishra (@stalwartcoder).</description>
    <link>https://dev.to/stalwartcoder</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%2F124434%2Fbb7cb710-068c-48da-822c-32f1adbeb871.jpeg</url>
      <title>DEV Community: Abhishek Mishra</title>
      <link>https://dev.to/stalwartcoder</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stalwartcoder"/>
    <language>en</language>
    <item>
      <title>Jev is Not a Small LLM: A Technical Guide to System One Models</title>
      <dc:creator>Abhishek Mishra</dc:creator>
      <pubDate>Tue, 22 Sep 2026 13:20:49 +0000</pubDate>
      <link>https://dev.to/stalwartcoder/jev-is-not-a-small-llm-a-technical-guide-to-system-one-models-25m2</link>
      <guid>https://dev.to/stalwartcoder/jev-is-not-a-small-llm-a-technical-guide-to-system-one-models-25m2</guid>
      <description>&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Model:&lt;/strong&gt; Jev, from TypeSafe AI. The first "System One" model, launched September 2026.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it is architecturally:&lt;/strong&gt; Not an autoregressive generator. You declare a constrained output space and it returns the probability mass over that space. There are no output tokens in the generative sense, which is why they're free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Output surface:&lt;/strong&gt; Three primitives. Noul (a probability), Score (a position on your rubric plus its distribution), Choice (one of up to 255 options plus its distribution). No text, no coordinates, no pixels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The property that changes your design:&lt;/strong&gt; Every question in a request is evaluated in parallel against one shared read of the state. Eight questions cost roughly what one costs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trained with:&lt;/strong&gt; RLCD (Reinforcement Learning for Calibrated Decisions), optimising against outcomes rather than human preference. This is why calibration is even a coherent claim here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I built:&lt;/strong&gt; Semantic Microscope. Labels every sentence of a document with five or six calibrated probabilities and renders the whole thing as a heatmap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My numbers (from Bengaluru):&lt;/strong&gt; five documents, roughly 68,000 judgments, &lt;strong&gt;31 cents&lt;/strong&gt;, zero errors. p50 356ms round trip, of which only &lt;strong&gt;98ms is the model&lt;/strong&gt; and 247ms is the Pacific.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measured calibration (n=59, hand-labelled):&lt;/strong&gt; discrimination is excellent and monotonic, but the probabilities sit below the diagonal in every bucket. The cause turned out to be a disagreement about what the question meant, which is the most useful thing I learned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/abhishekmishragithub/semantic-microscope" rel="noopener noreferrer"&gt;github.com/abhishekmishragithub/semantic-microscope&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqg1k8hl5yx7aibp08tpc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqg1k8hl5yx7aibp08tpc.png" alt="Frankenstein, 2,970 sentences, one cell each, coloured by dramatic tension. 56 × 56 cells, seven cents." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few days after Jev launched, a demo went round my timeline. Someone holds their hand up to a webcam, says "give me a ring", and a ring appears on their finger. Then sunglasses. Then a rainbow over their head. Credited to Jev. It did numbers.&lt;/p&gt;

&lt;p&gt;I got access that week and started building, and about an hour in I realised something: &lt;strong&gt;Jev could not have drawn any of that.&lt;/strong&gt; Not "it would be difficult". Structurally could not. There is no request you can make to Jev that produces a coordinate, an SVG path, or a pixel, because Jev's output space is something you declare in advance and it only ever returns a distribution over what you declared.&lt;/p&gt;

&lt;p&gt;Whatever produced that ring was almost certainly MediaPipe finding the finger joint and a pre-made sprite being dropped on it. Jev's largest possible role was picking the string &lt;code&gt;"ring"&lt;/code&gt; out of a list.&lt;/p&gt;

&lt;p&gt;I'm not writing this to dunk on anyone (the demo is fun, and launch week is chaos for everybody). I'm writing it because &lt;strong&gt;the misunderstanding in that demo is the same one that will make your first Jev project disappointing.&lt;/strong&gt; People are reaching for Jev as though it were a fast, cheap LLM. It's a different class of component, and once the architecture clicks you start seeing places for it that an LLM was never right for in the first place.&lt;/p&gt;

&lt;p&gt;This post covers what Jev actually is under the hood, why its economics are shaped the way they are, the five patterns that work, where it fails, and real latency and calibration numbers I measured myself from India.&lt;/p&gt;

&lt;h2&gt;
  
  
  What kind of model is this, actually
&lt;/h2&gt;

&lt;p&gt;Start here, because everything downstream follows from it.&lt;/p&gt;

&lt;p&gt;An LLM is an autoregressive next-token predictor. You give it a context, it produces a probability distribution over the vocabulary, samples one token, appends it, and repeats. If you want a decision out of that process you have to convince it to write the decision down as tokens, then parse those tokens back into a decision. Structured output modes (JSON schema, grammar-constrained decoding) make the parsing more reliable, but the machinery underneath is unchanged: it's still generating a sequence, and you're still paying per token generated.&lt;/p&gt;

&lt;p&gt;Jev inverts this. You declare the output space up front, as a Noul (binary), a Score (an ordered rubric of 2 to 10 levels), or a Choice (up to 255 options). The model does a forward pass over your state, and rather than sampling a sequence, it returns the &lt;strong&gt;probability mass over the space you declared.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;TypeSafe hasn't published the architecture, so some of this is inference rather than documented fact. But the evidence is strong. &lt;code&gt;openjev&lt;/code&gt; (166 stars) reproduces the primitive on a 4B open model by reading option logits directly, without generating anything, and gets something recognisably similar. That tells you the mechanism is a constrained read rather than a constrained generation.&lt;/p&gt;

&lt;p&gt;Three consequences follow immediately, and they explain most of the strange things about Jev's pricing and API:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Output tokens are free because there aren't any.&lt;/strong&gt; TypeSafe charges $0.042 per million input tokens and nothing for output. That's not a pricing promotion, it's a description of the architecture. Nothing is being generated, so there's nothing to meter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Questions can be parallel because they don't share a sequence.&lt;/strong&gt; Every question in a request is an independent read against the same forward pass over the same state. Question 4 cannot be influenced by question 2's answer, because there's no sequence for them to sit in. This is also why adding a question doesn't cause the context degradation you'd get from stuffing more into an LLM prompt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Schema violations are structurally impossible, not merely unlikely.&lt;/strong&gt; With an LLM in JSON mode you're constraining the sampler and hoping. With Jev the output space &lt;em&gt;is&lt;/em&gt; your schema, so there is no state the model can be in that produces an invalid value. This is a real guarantee and it is also narrower than the marketing suggests, which I'll come back to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why calibration is a coherent claim here
&lt;/h3&gt;

&lt;p&gt;The other half of the architecture story is the training objective. TypeSafe calls it &lt;strong&gt;RLCD, Reinforcement Learning for Calibrated Decisions&lt;/strong&gt;: probabilities are optimised against observed outcomes rather than against human preference.&lt;/p&gt;

&lt;p&gt;That distinction matters more than it sounds, and there's a well-known precedent. The GPT-4 technical report includes a pair of calibration plots showing the pre-trained base model was well calibrated on multiple-choice questions, and the post-RLHF model was substantially &lt;em&gt;less&lt;/em&gt; calibrated. Training on human preference teaches a model that confident-sounding answers are rewarded, which is precisely the pressure that destroys calibration.&lt;/p&gt;

&lt;p&gt;So when a chat model tells you it's "85% confident", that number is a linguistic artifact and means approximately nothing. When Jev returns &lt;code&gt;0.85&lt;/code&gt;, the training objective was at least pointed at making that number track reality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"At least pointed at" is doing real work in that sentence.&lt;/strong&gt; Calibration is a population-level property: if Jev says 0.8 across a thousand cases, roughly eight hundred should be true. It says nothing about whether &lt;em&gt;this particular&lt;/em&gt; 0.8 is correct. And TypeSafe publishes no reliability diagram and no ECE, so this remains a claim about their training objective rather than a measured guarantee. I show you how to check it yourself later in this post, and I show you what I found.&lt;/p&gt;

&lt;h2&gt;
  
  
  The API, concretely
&lt;/h2&gt;

&lt;p&gt;One endpoint. You send a &lt;code&gt;state&lt;/code&gt; (a string or JSON object describing the situation) and a set of &lt;code&gt;questions&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.typesafe.ai/v1/systemone&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;TYPESAFE_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jev-1.13.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;state&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sentence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Either party may terminate upon thirty days written notice.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document_kind&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;commercial contract&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;questions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;obligation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;noul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This sentence creates a binding obligation on one of the parties.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;risk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How legally load-bearing and unusual is this sentence?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;criteria&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pure boilerplate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Standard market terms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Materially binding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unusual or one-sided&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;clause_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;choice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Which category does this sentence belong to?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;criteria&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;termination&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ending, suspending or renewing the agreement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pricing, invoicing, fees or timing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;liability&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Indemnity, warranty, limitation of liability&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;other&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;None of the above&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the flat &lt;code&gt;"type"&lt;/code&gt; form. I tried the nested &lt;code&gt;{"noul": {...}}&lt;/code&gt; version first and got a 422.&lt;/p&gt;

&lt;p&gt;What comes back:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Noul&lt;/strong&gt; returns a single float, the probability the proposition is true. No confidence field, because the probability &lt;em&gt;is&lt;/em&gt; the belief.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Score&lt;/strong&gt; returns a continuous value that can land between levels (&lt;code&gt;2.14&lt;/code&gt;), the full per-level distribution, a confidence, and a legend mapping indices back to your level text. The continuous value is a probability-weighted mean over the rubric, which is why it isn't an integer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choice&lt;/strong&gt; returns the winning option, the full distribution across options, and a confidence derived from how peaked that distribution is.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Pin the model version (&lt;code&gt;jev-1.13.0&lt;/code&gt;) rather than using &lt;code&gt;jev-latest&lt;/code&gt;, and log the &lt;code&gt;model&lt;/code&gt; field that comes back in every response. If you're tuning thresholds you really do not want the model moving under you mid-project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A few operational limits worth knowing before you design anything: the state plus all questions share roughly a 64k token budget, Choice caps at 255 options, Score takes 2 to 10 levels, and the published rate limits are 250k tokens/sec and 1,200 requests/min. TypeSafe notes those limits are moving while capacity lands.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model: a sense, not a reasoner
&lt;/h2&gt;

&lt;p&gt;Kahneman's &lt;em&gt;Thinking, Fast and Slow&lt;/em&gt; splits cognition in two. System 2 is slow, deliberate, sequential, the thing you use to work through a proof. System 1 is fast, automatic, parallel, and it does not produce arguments. It produces &lt;em&gt;impressions&lt;/em&gt;. You walk into a room and know something is off before you could explain why.&lt;/p&gt;

&lt;p&gt;Every LLM you've used is System 2 cosplay. It produces a chain of words, and if you want a decision you have to ask it to write one down and then read the words back.&lt;/p&gt;

&lt;p&gt;Jev is shaped like System 1, and the architecture section above is why: parallel, non-sequential, no trace, output is an impression rather than an argument. There's no reasoning trace because there's no reasoning. That's the design, not a missing feature.&lt;/p&gt;

&lt;p&gt;The practical version:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Stop asking what Jev can replace. Start asking where your system currently has no instincts at all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Almost every LLM pipeline I've seen is a brain with no reflexes. It thinks carefully about everything, including things that should have been felt instantly. Those gaps are where Jev goes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The demos are (mostly) misattributed
&lt;/h2&gt;

&lt;p&gt;The ring isn't the only one. Once I started looking, a pattern showed up across the 180+ community projects that appeared in the first week. Almost all of them are real and clever. Almost all of them are credited to the wrong component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Jev drew captions and effects on my webcam."&lt;/strong&gt; There's a Japanese project, &lt;code&gt;jev-telop-live&lt;/code&gt;, that overlays variety-show captions and manga effects on a live camera feed. Its README is the most honest thing I've read about this model: it states outright that Jev does not write text, it answers typed questions with probabilities, and everything shown or played is picked from a closed set. The effects are hardcoded. Jev only selects which preset fires. That is exactly right, and exactly what the ring demo didn't say.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Jev plays Doom / Mario / StarCraft / Pac-Man."&lt;/strong&gt; Several of these exist and they do work. But Jev isn't seeing the screen. Something else serialises game state into text and Jev returns a Choice from a fixed action set each tick. Legitimate and interesting. The framing just makes people picture something that isn't happening.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Jev booked a flight in 7.1 seconds for $0.0039."&lt;/strong&gt; &lt;code&gt;browser-use/jev-ultrafast&lt;/code&gt;, 641 stars, genuinely impressive. But browser-use did the browsing. Jev picked which element to click. The record belongs to the pair.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Published latency numbers from code that was never run.&lt;/strong&gt; I found a Jev voice-agent repo quoting figures where the author notes, in the repo itself, that it had never been executed against the real API. Launch week produces a lot of this. Check whether numbers came from a real call before quoting them, including mine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And the one that cuts the other way:&lt;/strong&gt; &lt;code&gt;openjev&lt;/code&gt; reproducing the primitive off a 4B model's logits, which I mentioned above. Someone rebuilt the &lt;em&gt;shape&lt;/em&gt; of this in a weekend on open weights. That's genuinely useful information when you're deciding how much to build on the hosted version: the interface is copyable, and what TypeSafe is actually selling is the calibration training plus the hosting.&lt;/p&gt;

&lt;p&gt;None of this means Jev is overhyped. It means &lt;strong&gt;the thing it's actually good at is less flashy and more useful than the demos suggest.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Four properties, and what each one buys
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. The output is a calibrated float, not a token stream.&lt;/strong&gt; This is a category change, not a convenience. You get a number you can threshold, rank by, interpolate, animate, or send to a DAC. And you get &lt;em&gt;gradations&lt;/em&gt;: not "risky" but &lt;code&gt;0.73&lt;/code&gt;. You can sort four hundred clauses by how risky they are. You cannot sort by the word "risky".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Questions are parallel and output is free.&lt;/strong&gt; TypeSafe's cookbook reports batching 13 questions into one call was about 12× cheaper and 10× faster than asking them serially, with identical answers. My own runs match: going from 3 to 6 questions barely moved latency. &lt;strong&gt;So ask everything up front, including things you probably won't use.&lt;/strong&gt; The LLM instinct of asking the cheap question first and escalating is exactly backwards here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Under 100ms of model time.&lt;/strong&gt; Fast enough to sit inside a loop. A render frame, a game tick, a conversation turn. Classification stops being a batch job and becomes a primitive you call like a function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Effectively free.&lt;/strong&gt; Five documents including two full novels, the GDPR and an IETF specification: roughly 68,000 judgments for 31 cents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jev vs an LLM vs a fine-tuned classifier
&lt;/h2&gt;

&lt;p&gt;This is the comparison most posts dodge, because a fine-tuned BERT has been faster and cheaper than Jev at inference for years. The honest answer is that the difference isn't inference cost at all. It's &lt;strong&gt;what it costs to define a question.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A fine-tuned classifier needs labelled training data, hundreds to thousands of examples per class. You train, deploy, and have a model that answers exactly one question. Want a seventh dimension? Collect labels, retrain, redeploy. Reword a criterion? Retrain. Every question is a small project.&lt;/p&gt;

&lt;p&gt;With Jev a question is a sentence of prose, defined at call time. I reworded one of my criteria three times in an afternoon and re-ran the whole document after each change, for a few cents total.&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;Fine-tuned classifier&lt;/th&gt;
&lt;th&gt;Jev&lt;/th&gt;
&lt;th&gt;LLM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost to add a question&lt;/td&gt;
&lt;td&gt;Days&lt;/td&gt;
&lt;td&gt;Seconds&lt;/td&gt;
&lt;td&gt;Seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Needs training data&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;tr&gt;
&lt;td&gt;Inference latency&lt;/td&gt;
&lt;td&gt;~5-20ms&lt;/td&gt;
&lt;td&gt;~100ms server&lt;/td&gt;
&lt;td&gt;0.5-5s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Calibrated by design&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Claimed&lt;/td&gt;
&lt;td&gt;No (RLHF degrades it)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can generate text&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost at 10M/day&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Prohibitive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runs offline&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Use a fine-tune&lt;/strong&gt; when the taxonomy is frozen, volume is enormous, you need single-digit milliseconds, or you must run on-prem. And note the natural progression: if a Jev question of yours stabilises and volume explodes, distilling it into a small classifier is a perfectly good endgame. You'll already have the labelled dataset, because Jev generated it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Jev&lt;/strong&gt; when questions change often, you have many of them, you have no labelled data, or you want probabilities rather than labels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use an LLM&lt;/strong&gt; when you need words.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-line rule
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are writing a prompt that ends with &lt;em&gt;"respond only with one of: A, B, C"&lt;/em&gt;, that is a Jev call, and you should stop writing that prompt.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every JSON-mode enum. Every LLM-as-judge returning a 1 to 5. Every "is this safe, yes or no" guardrail. Every router picking a model. These are decisions wearing a text costume. You're paying generation prices and generation latency for something that was never text, then writing parsing code to undo it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five patterns that work
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The gate.&lt;/strong&gt; One Noul in front of an expensive or irreversible action. 100ms and a hundredth of a cent to avoid a bad outcome is trivially worth it, and unlike an LLM guardrail it cannot talk itself into a wrong answer through a long chain of reasoning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The router.&lt;/strong&gt; One Choice before an expensive model. The classic cascade, except the router is now three orders of magnitude cheaper than the thing it routes to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fan-out.&lt;/strong&gt; Twenty Nouls in one call covering every safety, intent and policy flag you care about. Because the marginal question is free, you can afford to check for things that almost never happen. Most under-used pattern right now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reflex.&lt;/strong&gt; Jev inside a real-time loop, running concurrently with something slow. In a voice agent that's the gap between STT finishing and TTS starting: your LLM drafts a reply while Jev simultaneously decides whether the user is frustrated, whether this is in scope, and whether a human should take over. The fast path lands before the slow path does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The dense labeller.&lt;/strong&gt; Nobody is building this one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern nobody is using: label everything
&lt;/h2&gt;

&lt;p&gt;Put the four properties together. Many questions, free. Per-item cost near zero. Fast. Calibrated floats instead of labels.&lt;/p&gt;

&lt;p&gt;That means you can afford to ask &lt;strong&gt;every question about every item in a corpus&lt;/strong&gt;, and then treat the resulting probabilities not as decisions but as a &lt;em&gt;field&lt;/em&gt; you can look at.&lt;/p&gt;

&lt;p&gt;I built Semantic Microscope to test this. It splits a document into sentences and asks Jev five or six questions about every single one, then renders the whole document as parallel vertical strips, one row per sentence, coloured by probability. You don't read the output. You look at it. A forty-page contract becomes a picture and the three clauses that matter glow. Point it at a novel with a different question set and the three-act structure shows up as bands.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1gnoqb0wrxhwnzdtda9c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1gnoqb0wrxhwnzdtda9c.png" alt="RFC 9110, six dimensions as parallel lanes. 3,001 sentences, all visible at once." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The core:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DIMENSIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;obligation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;noul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This sentence creates a binding obligation.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ambiguous&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;noul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A reasonable professional could read this two incompatible ways.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;financial&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;noul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This sentence has a direct financial consequence.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;liability&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;noul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This limits, excludes, caps or assigns liability.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sentence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nxt&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;previous&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sentence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sentence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;next&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nxt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document_kind&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;commercial contract&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;jev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;build_questions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DIMENSIONS&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;   &lt;span class="c1"&gt;# one call, all dimensions
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things here are easy to get wrong and both cost badly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One request per item, all questions inside it.&lt;/strong&gt; If you're looping over questions you've made the run 6× slower, 6× more likely to hit the rate limit, and thrown away the exact architectural property the approach depends on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Send the item, not the document.&lt;/strong&gt; One sentence plus one of context each side. Stuffing the whole document into state degrades accuracy as irrelevant material crowds it out, and burns input tokens (the ones you &lt;em&gt;do&lt;/em&gt; pay for) for nothing. Filtering context to what the question needs is your job, not the model's.&lt;/p&gt;

&lt;p&gt;Every existing Jev project I could find treats the output as a decision that triggers an action. Browser agents, trading bots, game players, routers, guardrails. Almost nobody treats the probability distribution as an artifact in its own right. That's open ground, and it's the thing this architecture makes possible that genuinely wasn't possible last month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two more worked examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The interrupt gate
&lt;/h3&gt;

&lt;p&gt;I run a daemon that speaks my coding agent's lifecycle events aloud. The failure mode of that whole genre is spam. One Noul fixes it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;questions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;worth_interrupting&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;noul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A developer in deep focus would want to be told this immediately.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;urgency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How urgently does this need attention?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;criteria&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ignore&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mention later&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Say now&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Stop everything&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Speak only above the bar, and pick voice and speed from the score. Turned a noisy toy into something I leave running.&lt;/p&gt;

&lt;h3&gt;
  
  
  Routing before the expensive model
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;questions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;skill&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;choice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Which specialist should handle this request?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;criteria&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Writing or debugging software&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;research&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Needs current external information&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Conversational, no tools needed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refuse&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Out of scope or unsafe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;needs_frontier_model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;noul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This request requires the most capable model rather than a fast one.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Route on &lt;code&gt;choice&lt;/code&gt;, and use &lt;code&gt;confidence&lt;/code&gt; to decide when to fall back to the expensive path rather than trusting the route. A flat distribution across four options is the model telling you it doesn't know, and that's actionable information you don't get from an LLM router.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No arithmetic, no counting, no date ordering.&lt;/strong&gt; Dates are text to it. Ask judgments, never computations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It reads literally, and that's mostly a feature.&lt;/strong&gt; Negations and scoping are taken at face value. On RFC 9110 it read "non-compliant" as a MUST question and separated MUST (median 0.75) from SHOULD (0.33) almost cleanly. The cost is that you own the question wording completely: there's no prose in the response to reveal that it interpreted you differently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State is not treated as hostile.&lt;/strong&gt; If user input goes into state, prompt injection is your threat model, not the model's.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context rot is real.&lt;/strong&gt; Accuracy degrades as state fills with irrelevant material. The parallelism protects questions from each other, not from a bloated state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Served from US West only.&lt;/strong&gt; Geography is a first-class latency cost if you're not in North America.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Cannot hallucinate" is narrower than it sounds.&lt;/strong&gt; The guarantee is structural: it cannot return a value outside your declared space. It can absolutely return the &lt;em&gt;wrong&lt;/em&gt; value from inside that space, with high confidence. TypeSafe's CEO said as much on Hacker News. Schema safety is not correctness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The headline benchmarks are vendor self-reported.&lt;/strong&gt; "20 to 200× faster, 40 to 400× cheaper" and the accuracy figures are TypeSafe's own and unreproduced. The one independent hands-on test I've seen (&lt;em&gt;Every&lt;/em&gt;) confirmed speed and cost, found accuracy "good but not perfect", and explicitly did not audit calibration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My numbers, measured from Bengaluru
&lt;/h2&gt;

&lt;p&gt;Vendor latency figures assume you're sitting near the inference pool. I'm 13,000km from it. Five documents, cold cache, 15 requests/s with 12 in flight, nothing rounded away:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;run&lt;/th&gt;
&lt;th&gt;preset&lt;/th&gt;
&lt;th&gt;sentences (live)&lt;/th&gt;
&lt;th&gt;wall&lt;/th&gt;
&lt;th&gt;p50&lt;/th&gt;
&lt;th&gt;p95&lt;/th&gt;
&lt;th&gt;p99&lt;/th&gt;
&lt;th&gt;errors&lt;/th&gt;
&lt;th&gt;cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;sample-contract (synthetic MSA)&lt;/td&gt;
&lt;td&gt;contract&lt;/td&gt;
&lt;td&gt;484 (482)&lt;/td&gt;
&lt;td&gt;33.2s&lt;/td&gt;
&lt;td&gt;385ms&lt;/td&gt;
&lt;td&gt;506ms&lt;/td&gt;
&lt;td&gt;617ms&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;$0.0141&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gdpr-contract (GDPR, EUR-Lex)&lt;/td&gt;
&lt;td&gt;contract&lt;/td&gt;
&lt;td&gt;1,977 (1,630)&lt;/td&gt;
&lt;td&gt;108.9s&lt;/td&gt;
&lt;td&gt;357ms&lt;/td&gt;
&lt;td&gt;454ms&lt;/td&gt;
&lt;td&gt;578ms&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;$0.0481&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pride-and-prejudice (Gutenberg #1342)&lt;/td&gt;
&lt;td&gt;prose&lt;/td&gt;
&lt;td&gt;4,533 (4,433)&lt;/td&gt;
&lt;td&gt;295.9s&lt;/td&gt;
&lt;td&gt;347ms&lt;/td&gt;
&lt;td&gt;439ms&lt;/td&gt;
&lt;td&gt;619ms&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;$0.1017&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rfc9110 (HTTP Semantics)&lt;/td&gt;
&lt;td&gt;rfc&lt;/td&gt;
&lt;td&gt;3,566 (3,001)&lt;/td&gt;
&lt;td&gt;200.6s&lt;/td&gt;
&lt;td&gt;356ms&lt;/td&gt;
&lt;td&gt;446ms&lt;/td&gt;
&lt;td&gt;570ms&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;$0.0826&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;frankenstein (Gutenberg #84)&lt;/td&gt;
&lt;td&gt;prose&lt;/td&gt;
&lt;td&gt;3,087 (2,970)&lt;/td&gt;
&lt;td&gt;198.8s&lt;/td&gt;
&lt;td&gt;410ms&lt;/td&gt;
&lt;td&gt;515ms&lt;/td&gt;
&lt;td&gt;636ms&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;$0.0669&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's &lt;strong&gt;roughly 68,000 judgments across five documents for 31 cents&lt;/strong&gt;, including two full novels, the GDPR, and an IETF specification. Zero errors and zero 429s across all of it.&lt;/p&gt;

&lt;p&gt;Doing the same with a frontier model would have been a budget conversation rather than a rounding error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where the time actually goes
&lt;/h3&gt;

&lt;p&gt;TypeSafe returns an &lt;code&gt;x-envoy-upstream-service-time&lt;/code&gt; header, so you can separate inference from network. On the RFC 9110 run:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;component&lt;/th&gt;
&lt;th&gt;p50&lt;/th&gt;
&lt;th&gt;p95&lt;/th&gt;
&lt;th&gt;p99&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;server (from the envoy header)&lt;/td&gt;
&lt;td&gt;98ms&lt;/td&gt;
&lt;td&gt;162ms&lt;/td&gt;
&lt;td&gt;209ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;network and TLS (client minus server)&lt;/td&gt;
&lt;td&gt;247ms&lt;/td&gt;
&lt;td&gt;322ms&lt;/td&gt;
&lt;td&gt;367ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Roughly two thirds of every request is the Pacific, not the model.&lt;/strong&gt; Jev itself answers in under 100ms. Two things follow:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reuse your connections.&lt;/strong&gt; A cold TLS handshake across that distance costs more than the inference. One persistent client for the whole run is not an optimisation, it's the difference between three minutes and most of an hour. I found this the annoying way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Geography decides which patterns work for you.&lt;/strong&gt; Dense labelling and gating are comfortable at 356ms. A reflex inside a live conversation turn, fighting for an 800ms end-to-end budget, is marginal from India and fine from Oregon. Measure before you design.&lt;/p&gt;

&lt;p&gt;One more detail worth reading off that table: every run sat pinned at my own 15 rps limiter for its entire duration, so wall time is just sentences ÷ 15. &lt;strong&gt;The bottleneck was my rate limiting, not Jev.&lt;/strong&gt; The documented ceiling is 1,200 requests/min and I was deliberately running under it.&lt;/p&gt;

&lt;p&gt;And the cache matters more than I expected. Re-running the GDPR document with a warm cache took &lt;strong&gt;2.9 seconds for 1,977 sentences and made zero requests.&lt;/strong&gt; That turns "iterate on the viewer while re-running the pipeline" from a cost decision into a non-decision, which changed how I worked on this more than any other single thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does the model actually track the question? A free check first
&lt;/h2&gt;

&lt;p&gt;Before hand-labelling anything, there's a cheap sanity check worth running, and I haven't seen anyone else do it.&lt;/p&gt;

&lt;p&gt;One of my six dimensions was deliberately &lt;strong&gt;lexical&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;normative_keyword&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;noul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This sentence contains an RFC 2119 keyword: MUST, MUST NOT, SHALL, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SHOULD, SHOULD NOT, REQUIRED, RECOMMENDED, MAY, OPTIONAL.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That question has objective ground truth. A regex answers it perfectly. So I ran the regex over all 3,001 sentences and compared.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recall 1.00. Precision 0.79.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Jev found every single one of the 413 keyword sentences, and flagged 107 more that contain no uppercase keyword.&lt;/p&gt;

&lt;p&gt;Look at what those 107 are, though. They're overwhelmingly sentences stating a requirement in &lt;strong&gt;lowercase&lt;/strong&gt; prose: "a server must", "clients should". Which means Jev is doing exactly what a careful human reader does before being told the rules, and getting it wrong for exactly the reason the IETF had to publish &lt;strong&gt;RFC 8174&lt;/strong&gt;, a whole RFC clarifying that only the &lt;em&gt;uppercase&lt;/em&gt; forms carry normative force, because everyone kept conflating them.&lt;/p&gt;

&lt;p&gt;Two things I'd take from that. First, a Noul does genuinely track its question rather than returning vibes. Second, "reads literally" is a real property and it cuts both ways: here it over-fires because the question said "contains a keyword" and Jev reasoned about meaning instead of characters.&lt;/p&gt;

&lt;p&gt;If you're building on Jev, find the one question in your set that has objective ground truth and check it this way. It costs nothing and it's the fastest signal you'll get.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measured calibration: the part nobody publishes
&lt;/h2&gt;

&lt;p&gt;TypeSafe says Jev's probabilities are calibrated. They publish no reliability diagram and no ECE. So I measured it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method
&lt;/h3&gt;

&lt;p&gt;The dimension:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;requirement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;noul&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ignoring this sentence would make an implementation non-compliant.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The labelling rule, written &lt;strong&gt;before&lt;/strong&gt; I saw any sentences and not revised during the run:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Work down the list, stop at the first match.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;contains MUST, MUST NOT, SHALL, SHALL NOT, REQUIRED → &lt;strong&gt;yes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;contains SHOULD, SHOULD NOT, RECOMMENDED → &lt;strong&gt;no&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;contains MAY, OPTIONAL → &lt;strong&gt;no&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;states an absolute requirement in plain prose, no keyword → &lt;strong&gt;yes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;only describes, defines or explains → &lt;strong&gt;no&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;points at another section instead of stating a rule → &lt;strong&gt;no&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;SHOULD is a "no" because RFC 2119 defines it as permitting valid reasons to deviate. An implementation that ignores a SHOULD with good cause is still compliant, and the question asks about compliance.&lt;/p&gt;

&lt;p&gt;Then: a stratified sample across the five probability buckets, &lt;strong&gt;with Jev's prediction hidden while labelling&lt;/strong&gt;, in two sittings of 30. That last detail is the one people skip, and skipping it invalidates the whole exercise. If you see the number first, you're measuring your own anchoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Result (n=59, single annotator)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgh9g46bq6edjchpflo1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgh9g46bq6edjchpflo1o.png" alt="Calibration of the requirement dimension on RFC 9110: predicted versus observed across five probability buckets, with a diagonal reference line. All five buckets fall below the diagonal." width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;bucket&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;predicted&lt;/th&gt;
&lt;th&gt;observed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.0–0.2&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;0.15&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.2–0.4&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;0.31&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.4–0.6&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;0.46&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.08&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.6–0.8&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;0.71&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.45&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.8–1.0&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;0.82&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.75&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Brier score: 0.165&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Three findings, in order of how much they'd change your design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Discrimination is excellent. Ranking is trustworthy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The observed column rises monotonically: 0.00, 0.00, 0.08, 0.45, 0.75. No inversions anywhere. If you sort by the score, the sort is meaningful. For most real uses (triage, review queues, "show me the 30 that matter") this is the property you actually depend on, and it holds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The probabilities sit below the diagonal in every bucket.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All five, same direction. Under a null of no bias that's about a 1-in-32 coincidence, and two buckets are individually significant: 0/12 against a predicted 0.31 has roughly a 1.2% binomial probability, and 1/12 against 0.46 about 0.8%.&lt;/p&gt;

&lt;p&gt;Concretely, &lt;strong&gt;0.71 meant about 0.45 here.&lt;/strong&gt; But be precise about what's established: with 11 to 12 items per bucket the intervals are wide, and the two end buckets are individually consistent with calibration. It's the middle that isn't. The sign test across all five plus the two significant mid-buckets is the evidence, not any single row.&lt;/p&gt;

&lt;p&gt;At n=29 after my first sitting I could see the shape but couldn't call it. The second sitting is what made it a finding rather than a hunch. If you run this yourself, do the second sitting.&lt;/p&gt;

&lt;p&gt;This has an identifiable cause rather than being diffuse noise. I dig into it two sections down: the mid-range is almost entirely SHOULD sentences, which Jev scores at a median of 0.33 while my labelling rule scored them as hard no's.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The triage number, which is the one I'd actually put in a pitch deck.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nothing below 0.4 was a real requirement. Zero out of 24 labelled items, across two buckets that together hold 2,059 of 3,001 sentences, or &lt;strong&gt;68.6% of RFC 9110.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So the honest operational claim is: this discards roughly two-thirds of the specification, with no false negatives observed at this sample size, and you read the rest. That's a much better claim than "AI reads your spec for you", and unlike that one, it has a number behind it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The rule this gives you
&lt;/h3&gt;

&lt;p&gt;For this question on this document: &lt;strong&gt;threshold at 0.6. Treat below 0.4 as safely discardable. Trust the ordering, discount the absolute values.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What I am not claiming
&lt;/h3&gt;

&lt;p&gt;One dimension, one document, one annotator, n=59, eleven to twelve items per bucket. The question's wording does real work, as the next section shows. I am not saying Jev is miscalibrated in general. I'm saying that on this task I measured a gap, that you should measure your own, and that the tooling to do it is in the repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run microscope validate &amp;lt;run-id&amp;gt; &lt;span class="nt"&gt;--dimension&lt;/span&gt; requirement
uv run microscope validate &amp;lt;run-id&amp;gt; &lt;span class="nt"&gt;--dimension&lt;/span&gt; requirement &lt;span class="nt"&gt;--add&lt;/span&gt; 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do it before you put a probability in front of anything consequential. And publish what you find either way. Right now almost nobody has, which is the only reason this section is interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the overconfidence actually was
&lt;/h2&gt;

&lt;p&gt;The calibration gap above has a mechanism, and finding it was the most useful thing in this whole exercise.&lt;/p&gt;

&lt;p&gt;RFC 2119 gives you three tiers of obligation. So I grouped every sentence by which uppercase keyword it contains and looked at what Jev gave them under the &lt;code&gt;requirement&lt;/code&gt; question:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;keyword&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;min&lt;/th&gt;
&lt;th&gt;p25&lt;/th&gt;
&lt;th&gt;median&lt;/th&gt;
&lt;th&gt;p75&lt;/th&gt;
&lt;th&gt;max&lt;/th&gt;
&lt;th&gt;share ≥ 0.5&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MUST / MUST NOT&lt;/td&gt;
&lt;td&gt;201&lt;/td&gt;
&lt;td&gt;0.23&lt;/td&gt;
&lt;td&gt;0.67&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.75&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.79&lt;/td&gt;
&lt;td&gt;0.90&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;96%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SHOULD / SHOULD NOT&lt;/td&gt;
&lt;td&gt;119&lt;/td&gt;
&lt;td&gt;0.13&lt;/td&gt;
&lt;td&gt;0.25&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.33&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.42&lt;/td&gt;
&lt;td&gt;0.65&lt;/td&gt;
&lt;td&gt;8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MAY&lt;/td&gt;
&lt;td&gt;104&lt;/td&gt;
&lt;td&gt;0.12&lt;/td&gt;
&lt;td&gt;0.21&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.27&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.36&lt;/td&gt;
&lt;td&gt;0.74&lt;/td&gt;
&lt;td&gt;6%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Only four sentences contain both a MUST and a SHOULD, so the separation isn't an artefact of mixed sentences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jev is reading the question correctly.&lt;/strong&gt; It asked itself whether ignoring this makes you non-compliant, concluded that's a MUST question, and separated the tiers almost cleanly: 96% of MUST sentences land above 0.5 against 8% of SHOULD. Threshold at 0.5 and you have, in effect, a MUST detector that also catches requirements stated in plain prose without any keyword at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But look at where SHOULD sits.&lt;/strong&gt; Median 0.33, not 0.05. Jev treats SHOULD as a &lt;em&gt;weak yes&lt;/em&gt; rather than a no. My labelling rule, written from RFC 2119, treated it as a hard no.&lt;/p&gt;

&lt;p&gt;That single disagreement explains most of the calibration gap. The 0.2 to 0.4 bucket, where I measured a predicted 0.31 against an observed 0.00, is the SHOULD population almost exactly. The model isn't badly calibrated there so much as it's holding a slightly different theory of the question than I am. A lawyer would side with me. Plenty of engineers would side with Jev, because in practice ignoring a SHOULD does often mean your implementation is wrong.&lt;/p&gt;

&lt;p&gt;I'd call that overconfidence, because under the question as I defined it those probabilities are too high. But it's overconfidence with a cause you can see and correct for, not noise.&lt;/p&gt;

&lt;p&gt;The general lesson, which is the thing I'd actually hand someone building on this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your question wording isn't prompt engineering. It's the schema.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With an LLM, a disagreement about what you meant surfaces in the prose. You read the answer and think, that's not what I asked. Jev returns a float. There is nowhere for the disagreement to appear, so it emerges downstream as a calibration gap and you blame the model.&lt;/p&gt;

&lt;p&gt;So before you trust a Noul: write down what a "yes" means precisely enough that a stranger could label from it, then group your results by some feature you already understand and check the distributions. If a class of items you expected near 0.1 is sitting at 0.33, that isn't noise. That's the model telling you it read the question differently, and it's the cheapest debugging signal you'll get.&lt;/p&gt;

&lt;p&gt;Worth noticing that both of my useful findings came from the same move: group the results by something you already have ground truth for, and look at the distribution. The regex check told me a Noul tracks its question. The keyword grouping told me &lt;em&gt;which&lt;/em&gt; question it thought it was answering. Neither needed a single hand-label.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I think this lands
&lt;/h2&gt;

&lt;p&gt;The obvious commercial fit is anywhere the work is "check N criteria against M documents", because that cost used to scale as N×M and now it basically doesn't. Compliance review, contract triage, policy audit, and increasingly, auditing AI agent transcripts against a policy, continuously, at volume.&lt;/p&gt;

&lt;p&gt;With one discipline attached: &lt;strong&gt;triage, not verdict.&lt;/strong&gt; The honest pitch is "this takes a reviewer from four hundred clauses to the thirty they must actually read". It is not "this decides compliance". Given calibration is an unverified claim, anyone selling the second version is selling something they can't back.&lt;/p&gt;

&lt;p&gt;The less obvious fit is the dense labelling section. Treating probabilities as a field rather than a trigger. Visualisation, instruments, art. Nobody's there yet, and I think that's where the interesting work is.&lt;/p&gt;

&lt;p&gt;Jev's real contribution isn't that it's cheap. It's that it makes &lt;em&gt;asking&lt;/em&gt; cheap, and when asking is free you ask about everything, and you find out that documents and conversations and codebases have shapes you were never able to see.&lt;/p&gt;

&lt;p&gt;Go build something and tell me about it :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources &amp;amp; References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.typesafe.ai" rel="noopener noreferrer"&gt;TypeSafe AI docs&lt;/a&gt;&lt;/strong&gt; - primitives, limits, and their own guidance on confidence thresholds. The confidence page is more careful than the marketing and worth reading first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/abhishekmishragithub/semantic-microscope" rel="noopener noreferrer"&gt;Semantic Microscope&lt;/a&gt;&lt;/strong&gt; - the tool from this post. Python pipeline, vanilla JS viewer, no framework, bring your own key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/TheoLeeCJ/openjev" rel="noopener noreferrer"&gt;openjev&lt;/a&gt;&lt;/strong&gt; - reproduces the primitive by reading option logits off a 4B open model. The best available evidence for how the mechanism actually works.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/ponyo877/jev-telop-live" rel="noopener noreferrer"&gt;jev-telop-live&lt;/a&gt;&lt;/strong&gt; - the most honest README in the ecosystem about what Jev does and doesn't do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/browser-use/jev-ultrafast" rel="noopener noreferrer"&gt;browser-use/jev-ultrafast&lt;/a&gt;&lt;/strong&gt; - the flight booking demo. Good example of Jev as one component rather than the whole system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/ChetasLua/jevmeter" rel="noopener noreferrer"&gt;jevmeter&lt;/a&gt;&lt;/strong&gt; - a live probability meter over a debate video, 1,191 calls for about 5 cents. Prior art if you're doing anything with probability as a visual.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc9110.html" rel="noopener noreferrer"&gt;RFC 9110&lt;/a&gt;&lt;/strong&gt; - HTTP Semantics. The document everything in the measurement sections was run against.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc2119.html" rel="noopener noreferrer"&gt;RFC 2119&lt;/a&gt;&lt;/strong&gt; - defines MUST, SHOULD, MAY and the rest. The reason SHOULD counts as "no" in my labelling rule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc8174.html" rel="noopener noreferrer"&gt;RFC 8174&lt;/a&gt;&lt;/strong&gt; - the clarification that only uppercase keywords are normative. Jev makes the same mistake this RFC exists to correct.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://arxiv.org/abs/2303.08774" rel="noopener noreferrer"&gt;GPT-4 Technical Report&lt;/a&gt;&lt;/strong&gt; - see the calibration plots showing RLHF degrading the base model's calibration. Useful background for why RLCD is a different bet.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>programming</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Build Voice AI in Python: Complete Speech-to-Text Developer Guide (2026)</title>
      <dc:creator>Abhishek Mishra</dc:creator>
      <pubDate>Tue, 10 Feb 2026 15:04:38 +0000</pubDate>
      <link>https://dev.to/stalwartcoder/build-voice-ai-in-python-complete-speech-to-text-developer-guide-2026-1oe2</link>
      <guid>https://dev.to/stalwartcoder/build-voice-ai-in-python-complete-speech-to-text-developer-guide-2026-1oe2</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR – Quick Integration Overview
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;API Platform:&lt;/strong&gt; Pulse STT by Smallest AI – a state-of-the-art speech-to-text API supporting real-time streaming and batch audio transcription.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transcribes in &lt;strong&gt;32+ languages&lt;/strong&gt; with automatic language detection&lt;/li&gt;
&lt;li&gt;Ultra-low latency: &lt;strong&gt;~64ms&lt;/strong&gt; time-to-first-transcript for streaming&lt;/li&gt;
&lt;li&gt;Rich metadata: word timestamps, speaker diarization, emotion detection, age/gender estimation, PII redaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Integration Methods:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pre-Recorded Audio:&lt;/strong&gt; &lt;code&gt;POST https://waves-api.smallest.ai/api/v1/pulse/get_text&lt;/code&gt; – upload files for batch processing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Streaming:&lt;/strong&gt; &lt;code&gt;wss://waves-api.smallest.ai/api/v1/pulse/get_text&lt;/code&gt; – WebSocket for live transcription&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Developer Experience:&lt;/strong&gt; Use any HTTP/WebSocket client or official SDKs (Python, Node.js). Authentication via a single API key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Pulse STT?&lt;/strong&gt; Compared to other providers, Pulse offers faster response (64ms vs 200-500ms for typical cloud STT) and all-in-one features (no need for separate services for speaker ID, sentiment, or PII masking).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://console.smallest.ai/apikeys" rel="noopener noreferrer"&gt;API Console&lt;/a&gt; – Get your API key&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://waves-docs.smallest.ai" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt; – Full API reference&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/smallest-inc/smallest-python-sdk" rel="noopener noreferrer"&gt;Python SDK&lt;/a&gt; – Official client&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Introduction: Why Voice Integration Matters
&lt;/h2&gt;

&lt;p&gt;Voice is becoming the next frontier for user interaction. From virtual assistants and voice bots to real-time transcription in meetings, speech interfaces are making software more accessible and user-friendly. Developers today have access to Automatic Speech Recognition (ASR) APIs that convert voice to text, opening up possibilities for hands-free control, live captions, voice search, and more.&lt;/p&gt;

&lt;p&gt;However, integrating voice AI is more than just getting raw text from audio. Modern use cases demand &lt;strong&gt;speed and accuracy&lt;/strong&gt; – a voice assistant needs to transcribe commands almost instantly, and a call center analytics tool might need not just the transcript but also who spoke when and how they said it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Latency is critical.&lt;/strong&gt; A delay of even a second feels laggy in conversation. Traditional cloud speech APIs often have 500–1200ms latency for live transcription, with better ones hovering around 200–250ms. This has pushed the industry toward ultra-low latency – under 300ms – to enable seamless real-time interactions.&lt;/p&gt;

&lt;p&gt;In this guide, we'll walk through how to integrate an AI voice &amp;amp; speech API that meets these modern demands using &lt;strong&gt;Smallest AI's Pulse STT&lt;/strong&gt;. By the end, you'll know how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Transcribe audio files (WAV/MP3) to text using a simple HTTP API&lt;/li&gt;
&lt;li&gt;Stream live audio for instantaneous transcripts via WebSockets&lt;/li&gt;
&lt;li&gt;Leverage advanced features like timestamps, speaker diarization, and emotion detection&lt;/li&gt;
&lt;li&gt;Use both Python and Node.js to integrate voice capabilities&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Understanding Pulse STT
&lt;/h2&gt;

&lt;p&gt;Pulse is the speech-to-text/ ASR(automatic speech recognition) model from Smallest AI's "Waves" platform. It's designed for fast, accurate, and rich transcription with &lt;strong&gt;industry-leading latency&lt;/strong&gt; – around &lt;strong&gt;64 milliseconds&lt;/strong&gt; to first transcribed word &lt;a href="https://waves-docs.smallest.ai/v4.0.0/content/speech-to-text/benchmarks/performance#ttft-comparison-analysis" rel="noopener noreferrer"&gt;TTFT&lt;/a&gt; for streaming audio. This is an order of magnitude faster than many alternatives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Highlight Features
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Real-Time &amp;amp; Batch Modes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stream live audio via WebSocket or upload files via HTTP POST&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;32+ Languages&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;English, Spanish, Hindi, French, German, Arabic, Japanese, and more with auto-detection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Word/Sentence Timestamps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Know exactly when each word was spoken (great for subtitles)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speaker Diarization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Differentiate speakers: "Speaker A said X, Speaker B said Y"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Emotion Detection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tag segments with emotions: happy, angry, neutral, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Age/Gender Estimation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Infer speaker demographics for analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PII/PCI Redaction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatically mask credit cards, SSNs, and personal info&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;64ms Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Time-to-first-transcript in streaming mode&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Getting Started: Authentication
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Get Your API Key
&lt;/h3&gt;

&lt;p&gt;Sign up on the &lt;a href="https://console.smallest.ai/apikeys?utm_source=blog" rel="noopener noreferrer"&gt;Smallest AI Console&lt;/a&gt; and generate an API key. This key authenticates all your requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Test Your Key
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$SMALLEST_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://waves-api.smallest.ai/api/v1/lightning-v3.1/get_voices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Authentication Header
&lt;/h3&gt;

&lt;p&gt;All requests require this header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authorization: Bearer &amp;lt;YOUR_API_KEY&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 1: Transcribing Audio Files (REST API)
&lt;/h2&gt;

&lt;p&gt;The Pre-Recorded API is perfect for batch processing voicemails, podcasts, meeting recordings, or any existing audio files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Endpoint
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST https://waves-api.smallest.ai/api/v1/pulse/get_text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Query Parameters
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;model&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Model identifier: &lt;code&gt;pulse&lt;/code&gt; (required)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;language&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;ISO code (&lt;code&gt;en&lt;/code&gt;, &lt;code&gt;es&lt;/code&gt;, &lt;code&gt;hi&lt;/code&gt;) or &lt;code&gt;multi&lt;/code&gt; for auto-detect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;word_timestamps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Include word-level timing data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;diarize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Enable speaker diarization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;emotion_detection&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Detect speaker emotions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;age_detection&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Estimate speaker age group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gender_detection&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Estimate speaker gender&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Supported Languages (32+)
&lt;/h3&gt;

&lt;p&gt;Italian, Spanish, English, Portuguese, Hindi, German, French, Ukrainian, Russian, Kannada, Malayalam, Polish, Marathi, Gujarati, Czech, Slovak, Telugu, Odia, Dutch, Bengali, Latvian, Estonian, Romanian, Punjabi, Finnish, Swedish, Bulgarian, Tamil, Hungarian, Danish, Lithuanian, Maltese, and auto-detection (&lt;code&gt;multi&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  cURL Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s2"&gt;"https://waves-api.smallest.ai/api/v1/pulse/get_text?model=pulse&amp;amp;language=en&amp;amp;diarize=true&amp;amp;word_timestamps=true&amp;amp;emotion_detection=true"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$SMALLEST_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: audio/wav"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-binary&lt;/span&gt; &lt;span class="s2"&gt;"@/path/to/audio.wav"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SMALLEST_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;audio_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meeting_recording.wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://waves-api.smallest.ai/api/v1/pulse/get_text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pulse&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;language&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;word_timestamps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;diarize&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;emotion_detection&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;API_KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio/wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;audio_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;audio_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Print transcription
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Transcription:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transcription&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# Print word-level details with speaker info
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;words&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt;
    &lt;span class="n"&gt;speaker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;speaker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;N/A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  [Speaker &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;speaker&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;] [&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s - &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;end&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s] &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;word&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Check emotions
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;emotions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Emotions detected:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;emotion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;emotions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;emotion&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&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;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxje3f9q0xzyczcmzzdi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxje3f9q0xzyczcmzzdi.gif" alt="smallest ai pulse stt python transcribe demo" width="719" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Node.js Example
&lt;/h3&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;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&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;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&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;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SMALLEST_API_KEY&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;audioFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meeting_recording.wav&lt;/span&gt;&lt;span class="dl"&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://waves-api.smallest.ai/api/v1/pulse/get_text&lt;/span&gt;&lt;span class="dl"&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pulse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;word_timestamps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;diarize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;emotion_detection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&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;audioData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;audioFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;audioData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&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;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;Content-Type&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;audio/wav&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transcription:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transcription&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Print words with speaker info&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&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="s2"&gt;`  [Speaker &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;s - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;s] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"transcription"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello, this is a test transcription."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"words"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.88&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello,"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.82&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker_confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.61&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.88&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.04&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"this"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker_confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.76&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.04&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"is"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker_confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.99&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker_confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.99&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.68&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker_confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.99&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.68&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"transcription."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker_confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.99&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"utterances"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello, this is a test transcription."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"adult"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"gender"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"female"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"emotions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"happiness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sadness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"anger"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fear"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"disgust"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.97&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fileSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;63236&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 2: Real-Time Streaming (WebSocket API)
&lt;/h2&gt;

&lt;p&gt;For live audio – voice assistants, live captioning, call center analytics – use the WebSocket API for sub-second latency with partial results as audio streams in.&lt;/p&gt;

&lt;h3&gt;
  
  
  WebSocket Endpoint
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wss://waves-api.smallest.ai/api/v1/pulse/get_text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Query Parameters
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;language&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;en&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Language code or &lt;code&gt;multi&lt;/code&gt; for auto-detect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;encoding&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;linear16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Audio format: &lt;code&gt;linear16&lt;/code&gt;, &lt;code&gt;linear32&lt;/code&gt;, &lt;code&gt;alaw&lt;/code&gt;, &lt;code&gt;mulaw&lt;/code&gt;, &lt;code&gt;opus&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sample_rate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;16000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sample rate: &lt;code&gt;8000&lt;/code&gt;, &lt;code&gt;16000&lt;/code&gt;, &lt;code&gt;22050&lt;/code&gt;, &lt;code&gt;24000&lt;/code&gt;, &lt;code&gt;44100&lt;/code&gt;, &lt;code&gt;48000&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;word_timestamps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Include word-level timestamps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;full_transcript&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Include cumulative transcript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sentence_timestamps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Include sentence-level timestamps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;redact_pii&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Redact personal information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;redact_pci&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Redact payment card information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;diarize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable speaker diarization&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Python Streaming Example
&lt;/h3&gt;

&lt;p&gt;From the &lt;a href="https://github.com/smallest-inc/cookbook/tree/main/speech-to-text/websocket" rel="noopener noreferrer"&gt;official cookbook&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;websockets&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;librosa&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlencode&lt;/span&gt;

&lt;span class="n"&gt;WS_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wss://waves-api.smallest.ai/api/v1/pulse/get_text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Configurable features
&lt;/span&gt;&lt;span class="n"&gt;LANGUAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;ENCODING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;linear16&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;SAMPLE_RATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16000&lt;/span&gt;
&lt;span class="n"&gt;WORD_TIMESTAMPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;FULL_TRANSCRIPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;SENTENCE_TIMESTAMPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;DIARIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;REDACT_PII&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;REDACT_PCI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transcribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;language&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LANGUAGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;encoding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ENCODING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sample_rate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_RATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;word_timestamps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WORD_TIMESTAMPS&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;full_transcript&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FULL_TRANSCRIPT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sentence_timestamps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SENTENCE_TIMESTAMPS&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;diarize&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DIARIZE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;redact_pii&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REDACT_PII&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;redact_pci&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REDACT_PCI&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;WS_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;urlencode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Load audio with librosa (handles any format)
&lt;/span&gt;    &lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;librosa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SAMPLE_RATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mono&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;chunk_duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;  &lt;span class="c1"&gt;# 100ms chunks
&lt;/span&gt;    &lt;span class="n"&gt;chunk_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_duration&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_RATE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;websockets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;additional_headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;✅ Connected to Pulse STT WebSocket&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_audio&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;pcm16&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;32768.0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int16&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;tobytes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&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="n"&gt;pcm16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&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="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;📤 Sent end signal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;receive_responses&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_final&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;✓ &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;transcript&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_last&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;full_transcript&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FULL TRANSCRIPT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;full_transcript&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                        &lt;span class="k"&gt;break&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;send_audio&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;receive_responses&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;# Usage
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SMALLEST_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;transcribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recording.wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Install dependencies:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;websockets librosa numpy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SMALLEST_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-api-key"&lt;/span&gt;
python transcribe.py recording.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Node.js Streaming Example
&lt;/h3&gt;

&lt;p&gt;From the &lt;a href="https://github.com/smallest-inc/cookbook/tree/main/speech-to-text/websocket" rel="noopener noreferrer"&gt;official cookbook&lt;/a&gt;:&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;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&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;WebSocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ws&lt;/span&gt;&lt;span class="dl"&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;wav&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wav&lt;/span&gt;&lt;span class="dl"&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;WS_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wss://waves-api.smallest.ai/api/v1/pulse/get_text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Configurable features&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LANGUAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&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;ENCODING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;linear16&lt;/span&gt;&lt;span class="dl"&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;SAMPLE_RATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16000&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;WORD_TIMESTAMPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;FULL_TRANSCRIPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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;DIARIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;REDACT_PII&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;REDACT_PCI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;audioFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;wav&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Reader&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;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;format&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;format&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="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunks&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;samples&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Int16Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;byteOffset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;samples&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createReadStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;audioFile&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;transcribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;audioFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LANGUAGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ENCODING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;sample_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SAMPLE_RATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;word_timestamps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WORD_TIMESTAMPS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;full_transcript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FULL_TRANSCRIPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;diarize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DIARIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;redact_pii&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;REDACT_PII&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;redact_pci&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;REDACT_PCI&lt;/span&gt;&lt;span class="p"&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;WS_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;audio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;audioFile&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;chunkDuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 100ms&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chunkSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunkDuration&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;SAMPLE_RATE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&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;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;✅ Connected to Pulse STT WebSocket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunkSize&lt;/span&gt;&lt;span class="p"&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;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;chunkSize&lt;/span&gt;&lt;span class="p"&gt;);&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;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;byteOffset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;byteLength&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunkDuration&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&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;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}));&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;📤 Sent end signal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&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;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;result&lt;/span&gt; &lt;span class="o"&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;is_final&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&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="s2"&gt;`✓ &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;is_last&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;full_transcript&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&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="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&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="s2"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;));&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FULL TRANSCRIPT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;));&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;full_transcript&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&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;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&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;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;);&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;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SMALLEST_API_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;transcribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;recording.wav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Done!&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;strong&gt;Install dependencies:&lt;/strong&gt;&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;ws wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SMALLEST_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-api-key"&lt;/span&gt;
node transcribe.js recording.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  WebSocket Response Format
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"session_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sess_12345abcde"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"transcript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello, how are you?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"full_transcript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello, how are you?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_final"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_last"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"words"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello,"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.98&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"how"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"are"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.97&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"you?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Response Fields
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;is_final&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;false&lt;/code&gt; = partial/interim transcript; &lt;code&gt;true&lt;/code&gt; = finalized segment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;is_last&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;true&lt;/code&gt; when the entire session is complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;transcript&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Current segment text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;full_transcript&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Accumulated text from entire session (if enabled)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;words&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Word-level timestamps (if enabled)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fgithub.com%2Fsmallest-inc%2Fcookbook%2Fblob%2Fmain%2Fblog-code-samples%2Fpulse-stt-developer-guide%2Fscreenshots%2Fblog_pulse_stt_guide_node_js_websocket.gif%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fgithub.com%2Fsmallest-inc%2Fcookbook%2Fblob%2Fmain%2Fblog-code-samples%2Fpulse-stt-developer-guide%2Fscreenshots%2Fblog_pulse_stt_guide_node_js_websocket.gif%3Fraw%3Dtrue" alt="smallest ai pulse stt node streaming websocket demo" width="760" height="478"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 3: Advanced Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Speaker Diarization
&lt;/h3&gt;

&lt;p&gt;Enable &lt;code&gt;diarize=true&lt;/code&gt; to identify different speakers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pulse&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;language&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;diarize&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Response includes speaker labels:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"words"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker_confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.95&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker_confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.92&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"utterances"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello, how can I help?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"I have a question."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"speaker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Emotion Detection
&lt;/h3&gt;

&lt;p&gt;Enable &lt;code&gt;emotion_detection=true&lt;/code&gt; to analyze speaker sentiment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"emotions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"happiness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sadness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"anger"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fear"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"disgust"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  PII/PCI Redaction
&lt;/h3&gt;

&lt;p&gt;For compliance (HIPAA, PCI-DSS), enable &lt;code&gt;redact_pii=true&lt;/code&gt; or &lt;code&gt;redact_pci=true&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"transcript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My credit card is [CREDITCARD_1] and SSN is [SSN_1]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"redacted_entities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"[CREDITCARD_1]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[SSN_1]"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Age and Gender Detection
&lt;/h3&gt;

&lt;p&gt;Enable &lt;code&gt;age_detection=true&lt;/code&gt; and &lt;code&gt;gender_detection=true&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"adult"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"gender"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"female"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Comparing STT Providers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Latency&lt;/th&gt;
&lt;th&gt;Languages&lt;/th&gt;
&lt;th&gt;Diarization&lt;/th&gt;
&lt;th&gt;Emotion&lt;/th&gt;
&lt;th&gt;PII Redaction&lt;/th&gt;
&lt;th&gt;Price (per 1000 min)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pulse STT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~64ms&lt;/td&gt;
&lt;td&gt;32+&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Competitive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Cloud STT&lt;/td&gt;
&lt;td&gt;200-300ms&lt;/td&gt;
&lt;td&gt;125+&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;~$16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deepgram&lt;/td&gt;
&lt;td&gt;100-200ms&lt;/td&gt;
&lt;td&gt;36+&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;~$4-5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AssemblyAI&lt;/td&gt;
&lt;td&gt;200-400ms&lt;/td&gt;
&lt;td&gt;30+&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;~$3.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI Whisper&lt;/td&gt;
&lt;td&gt;Batch only&lt;/td&gt;
&lt;td&gt;99+&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;~$6&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Why Pulse STT stands out:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fastest time-to-first-transcript (64ms)&lt;/li&gt;
&lt;li&gt;All-in-one features (no separate services needed)&lt;/li&gt;
&lt;li&gt;Competitive accuracy across diverse accents&lt;/li&gt;
&lt;li&gt;Built for real-time voice AI applications&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Audio Quality
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;16kHz, mono, 16-bit PCM&lt;/strong&gt; for best results&lt;/li&gt;
&lt;li&gt;WAV or FLAC formats are ideal&lt;/li&gt;
&lt;li&gt;Minimize background noise when possible&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Error Handling
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;audio_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exceptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Rate limited - implement exponential backoff
&lt;/span&gt;        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;retry_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Invalid API key
&lt;/span&gt;        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid API key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rate Limiting
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add 500ms+ delay between batch requests&lt;/li&gt;
&lt;li&gt;Use webhooks for long audio files&lt;/li&gt;
&lt;li&gt;Implement exponential backoff for 429 errors&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Bonus: Full Demo Application
&lt;/h2&gt;

&lt;p&gt;Want to see everything working together? Check out the &lt;strong&gt;demo app&lt;/strong&gt; in the &lt;a href="https://github.com/smallest-inc/cookbook/tree/main/blog-code-samples/pulse-stt-developer-guide/demo-app" rel="noopener noreferrer"&gt;code samples repository&lt;/a&gt; — a complete Next.js web application featuring:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fgithub.com%2Fsmallest-inc%2Fcookbook%2Fraw%2Fmain%2Fblog-code-samples%2Fpulse-stt-developer-guide%2Fdemo-app%2Fscreenshots%2Fblog_pulse_stt_guide_next_js_demo_app.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fgithub.com%2Fsmallest-inc%2Fcookbook%2Fraw%2Fmain%2Fblog-code-samples%2Fpulse-stt-developer-guide%2Fdemo-app%2Fscreenshots%2Fblog_pulse_stt_guide_next_js_demo_app.gif" alt="smallest ai pulse stt demo" width="559" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;File upload transcription&lt;/strong&gt; with word-level timestamps (hover to see timing)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time microphone streaming&lt;/strong&gt; with live transcript display&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure WebSocket proxy&lt;/strong&gt; that keeps your API key server-side&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern UI&lt;/strong&gt; with Smallest AI brand colors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language selection&lt;/strong&gt; (English, Hindi, Spanish, French, German, Portuguese, Auto-detect)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emotion detection&lt;/strong&gt; and speaker diarization display&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quick Start
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;.env.local&lt;/code&gt; file with your API key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'SMALLEST_API_KEY=your-api-key'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .env.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start both servers (Next.js + WebSocket proxy):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev:all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open &lt;strong&gt;&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/strong&gt; in Chrome or Safari (for microphone access).&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;The demo runs two servers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Next.js&lt;/strong&gt; (port 3000) — Serves the React UI and handles file upload via &lt;code&gt;/api/transcribe&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WebSocket Proxy&lt;/strong&gt; (port 3001) — Securely proxies audio from browser to Pulse STT WebSocket API&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser → WebSocket Proxy (3001) → Pulse STT (wss://waves-api.smallest.ai)
Browser → Next.js API (3000) → Pulse STT (REST API)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This architecture keeps your API key secure on the server while enabling real-time streaming.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;demo-app/
├── src/
│   └── app/
│       ├── api/
│       │   └── transcribe/
│       │       └── route.ts    # REST API for file upload
│       ├── page.tsx            # Main UI
│       └── layout.tsx
├── ws-server.js                # WebSocket proxy server
├── .env.local                  # Your API key (create this)
└── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scripts
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start Next.js only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run dev:ws&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start WebSocket proxy only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run dev:all&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start both (recommended)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This architecture pattern is recommended for production apps — API keys stay server-side while the React frontend provides a smooth user experience with both file upload and real-time microphone transcription.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Integrating voice and speech capabilities into your workflow and apps can greatly enhance user experience. With Pulse STT, developers can achieve high-accuracy, low-latency transcription with just a few API calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use REST API:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Podcast transcription&lt;/li&gt;
&lt;li&gt;Meeting recordings&lt;/li&gt;
&lt;li&gt;Voicemail processing&lt;/li&gt;
&lt;li&gt;Batch analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to use WebSocket API:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live captioning&lt;/li&gt;
&lt;li&gt;Voice assistants&lt;/li&gt;
&lt;li&gt;Call center real-time analytics&lt;/li&gt;
&lt;li&gt;Interactive voice applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code patterns in this guide translate directly to production. Start with the REST API for prototyping, then add WebSocket streaming when real-time interaction becomes a requirement.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://console.smallest.ai" rel="noopener noreferrer"&gt;Smallest AI Console&lt;/a&gt;&lt;/strong&gt; — API key management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://waves-docs.smallest.ai" rel="noopener noreferrer"&gt;Waves Documentation&lt;/a&gt;&lt;/strong&gt; — Full API reference
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://discord.gg/5evETqguJs" rel="noopener noreferrer"&gt;Discord Community&lt;/a&gt;&lt;/strong&gt; — Developer support&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>voice</category>
      <category>ai</category>
      <category>python</category>
      <category>smallestai</category>
    </item>
    <item>
      <title>How to do efficient fine-Tuning for LLMs using SLoRA</title>
      <dc:creator>Abhishek Mishra</dc:creator>
      <pubDate>Wed, 07 Aug 2024 08:23:17 +0000</pubDate>
      <link>https://dev.to/tunehqai/how-to-do-efficient-fine-tuning-for-llms-using-slora-1a27</link>
      <guid>https://dev.to/tunehqai/how-to-do-efficient-fine-tuning-for-llms-using-slora-1a27</guid>
      <description>&lt;p&gt;You're a passionate AI developer, eager to try to utilize the power of large language models (LLMs) for your latest project. You've got brilliant ideas, but there's a catch – fine-tuning these massive models feels like trying to parallel park a cruise ship in a crowded marina. It's resource-intensive, time-consuming, and frankly, a bit overwhelming.&lt;br&gt;
Sound familiar? You're not alone in this boat.&lt;/p&gt;

&lt;p&gt;Before we dive deeper, let's clarify what we mean by fine-tuning:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fine-tuning is the process of further training a pre-trained model on a specific task or dataset to adapt its knowledge for a particular application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The world of AI has been grappling with a significant challenge: how to efficiently fine-tune LLMs without breaking the bank or melting your hardware – we all are GPU poor except NVIDIA. &lt;br&gt;
Traditional fine-tuning methods are like using a sledgehammer to crack a nut, – they get the job done, but at what cost?&lt;br&gt;
Enter &lt;strong&gt;SLoRA – Sparse Low-Rank Adaptation&lt;/strong&gt;, – the unsung hero for efficient model fine-tuning.&lt;/p&gt;

&lt;p&gt;Fine-tuning large language models (LLMs) has become a crucial step in achieving state-of-the-art results in various natural language processing (NLP) tasks. However, this process often comes with significant computational costs, memory requirements, and time constraints. In this article, we'll explore SLoRA, a novel approach to efficient model fine-tuning that promises to revolutionize the way we work with LLMs. By leveraging sparse low-rank adaptation, SLoRA offers a faster, more cost-effective, and more sustainable way to fine-tune LLMs without sacrificing performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is SLoRA?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxznk7b7h7xiys96eug5d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxznk7b7h7xiys96eug5d.png" alt="image alt" width="799" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To understand SLoRA, it's essential to first grasp the concept of &lt;a href="https://arxiv.org/pdf/2106.09685" rel="noopener noreferrer"&gt;Low-Rank Adaptation (LoRA)&lt;/a&gt;. LoRA is a parameter-efficient fine-tuning method that updates only a small subset of model parameters while keeping the rest frozen. This approach has shown remarkable success in reducing computational costs and memory requirements for model fine-tuning.&lt;/p&gt;

&lt;p&gt;However, LoRA still updates a relatively large number of parameters, which can be computationally expensive and memory-intensive. This is where SLoRA comes in – by introducing sparsity into the LoRA framework, SLoRA further reduces the number of updated parameters to approximately 1% of the original model's parameters. This drastic reduction in updated parameters leads to significant computational savings and faster convergence rates&lt;br&gt;
SLoRA stands for Sparse Low-Rank Adaptation, a method designed to enhance the efficiency of fine-tuning LLMs. It builds on the concept of LoRA, which constrains the update of pre-trained weights using low-rank decomposition. SLoRA introduces sparsity into this approach, focusing only on a subset of parameters that significantly impact the model's performance.&lt;/p&gt;

&lt;p&gt;Here's a simple analogy -- Imagine you have a giant jigsaw puzzle. LoRA would focus on updating a specific section of the puzzle, while SLoRA would pinpoint only the most important pieces within that section.&lt;/p&gt;

&lt;h2&gt;
  
  
  How SLoRA Works?
&lt;/h2&gt;

&lt;p&gt;SLoRA employs a sparse matrix approach where the weight updates are constrained to a low-rank format and further sparsified. This involves decomposing the weight matrix into a product of two smaller matrices and applying updates only to a sparse subset of the original parameters. This method reduces the density of updates to about 1%, significantly cutting down on the resources needed for training.&lt;/p&gt;

&lt;p&gt;Think of a weight matrix in an LLM as a giant grid of numbers. These numbers represent the connections between different parts of the model. SLoRA uses a technique called sparse matrix decomposition to break down this grid into smaller, more manageable pieces.&lt;/p&gt;

&lt;p&gt;Imagine slicing a pizza into smaller triangles. SLoRA only updates the toppings on a select few of those triangles, leaving the rest untouched. This dramatically reduces the amount of data we need to process and store.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FwJ9uLUf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FwJ9uLUf.png" alt="image alt" width="800" height="1899"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparison with Traditional Fine-Tuning Methods
&lt;/h3&gt;

&lt;p&gt;Traditional fine-tuning involves updating all model parameters, which is resource-intensive and time-consuming. In contrast, SLoRA updates only a small, significant subset of parameters, achieving similar performance with much lower computational overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SLoRA in the nutshell:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SLoRA builds on the foundation of LoRA (Low-Rank Adaptation), which already constrains updates to a small subset of parameters.&lt;/li&gt;
&lt;li&gt;It takes this a step further by introducing sparsity – focusing on an even smaller, more crucial set of parameters.&lt;/li&gt;
&lt;li&gt;The result? You're updating only about 1% of the model's parameters, dramatically reducing computational load and memory requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://arxiv.org/pdf/2308.06522v1" rel="noopener noreferrer"&gt;&lt;strong&gt;You can read more here&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Computational Requirements&lt;/strong&gt;: By updating only a sparse subset of parameters, SLoRA dramatically lowers the computational load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Fine-Tuning Process&lt;/strong&gt;: The sparse updates enable quicker convergence, speeding up the fine-tuning process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lower Memory Usage&lt;/strong&gt;: The reduced number of updates translates to lower memory requirements, making it feasible to deploy models on devices with limited memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Potential for Improved Model Performance&lt;/strong&gt;: Efficient parameter updates can lead to models that are not only faster but also potentially more robust and adaptable to specific tasks.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to use SLoRA in Your Projects?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initialize the Sparse Matrix&lt;/strong&gt;: Begin by setting up the sparse matrix with low-rank decomposition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply Sparse Updates&lt;/strong&gt;: Update only the critical parameters as identified by the sparsity constraints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Train the Model&lt;/strong&gt;: Proceed with the fine-tuning process, leveraging the computational efficiency of SLoRA.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;For more detailed guide checkout this paper: &lt;a href="https://arxiv.org/pdf/2308.06522" rel="noopener noreferrer"&gt;https://arxiv.org/pdf/2308.06522&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  SLoRA's Secret Sauce:
&lt;/h3&gt;

&lt;p&gt;Here's where SLoRA really flexes its muscles. By dramatically reducing the number of parameters updated during fine-tuning, SLoRA processes fewer tokens. It's like having a car that can drive the same distance using only a fraction of the fuel.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fewer tokens processed = Lower costs&lt;/li&gt;
&lt;li&gt;Efficient updates = More bang for your buck&lt;/li&gt;
&lt;li&gt;Optimized token usage = Stretch your budget further&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's say you're fine-tuning a model on a specific task. Traditional methods might process millions of tokens, updating every parameter. With SLoRA, you're looking at a fraction of that - potentially cutting your token usage (and thus, your costs)!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;SLoRA represents a significant leap forward in efficient model fine-tuning. It empowers developers to unlock the full potential of LLMs while being mindful of resources and costs.&lt;/p&gt;

&lt;p&gt;Ready to give SLoRA a try? At &lt;a href="https://tunehq.ai/developers" rel="noopener noreferrer"&gt;Tune AI&lt;/a&gt;, we implemented this approach to, make models mode accessible and provide an efficient way to fine-tune and serve LLMs.&lt;br&gt;
Head over to &lt;a href="https://studio.tune.app/" rel="noopener noreferrer"&gt;Tune Studio&lt;/a&gt; and start exploring! Share your experiences and let's build a more accessible and sustainable future for AI together.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>machinelearning</category>
      <category>finetune</category>
      <category>genai</category>
    </item>
    <item>
      <title>Don't Be That Dev: Avoiding the XY Problem Trap</title>
      <dc:creator>Abhishek Mishra</dc:creator>
      <pubDate>Tue, 20 Feb 2024 19:55:52 +0000</pubDate>
      <link>https://dev.to/stalwartcoder/dont-be-that-dev-avoiding-the-xy-problem-trap-bho</link>
      <guid>https://dev.to/stalwartcoder/dont-be-that-dev-avoiding-the-xy-problem-trap-bho</guid>
      <description>&lt;p&gt;Have you ever found yourself in a situation where you're trying to solve a problem, but you're so focused on your &lt;strong&gt;attempted solution&lt;/strong&gt; that you're not even sure what the &lt;strong&gt;actual problem&lt;/strong&gt; is? This is a common pitfall known as the &lt;strong&gt;XY problem&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the XY Problem?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The XY problem is a communication issue that often arises in software development. It occurs when someone seeking help focuses on their &lt;strong&gt;attempted solution (X)&lt;/strong&gt; rather than the &lt;strong&gt;actual problem they're trying to solve (Y)&lt;/strong&gt;. This can lead to misunderstandings, wasted time, and ineffective solutions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fam4p9hrxx9l8rampy516.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fam4p9hrxx9l8rampy516.png" alt="dont be that dev meme on bill murray" width="500" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's a classic example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine a developer named Abhishek is working on a web application that displays product information. He encounters an issue where product images take a long time to load, impacting the user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The XY Problem Approach:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of clearly stating the problem of slow image loading, Abhishek asks a question focusing on his chosen solution:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How can I implement caching for product images in my application?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Why it's a problem:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While caching might seem like a logical solution, focusing on it without explaining the context can lead to issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Misdiagnosis:&lt;/strong&gt; The person providing help might suggest specific caching techniques without understanding the root cause of slow loading. This could be inefficient if the issue lies elsewhere, like slow image optimization or network problems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Limited solutions:&lt;/strong&gt; Exploring only caching might overlook alternative solutions like image compression or a Content Delivery Network (CDN) that could be more effective.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Wasted time:&lt;/strong&gt; Both Abhishek and the other dev spend time discussing caching, which might not be the real solution.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Better approach:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Abhishek should rephrase his question to focus on the actual problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I'm experiencing slow loading times for product images in my web application. This is affecting the user experience. Can you suggest ways to improve the loading speed?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clearer communication:&lt;/strong&gt; The helper understands the desired outcome (faster image loading) and can suggest various solutions, including caching, optimization, or CDN, depending on the root cause.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Effective solutions:&lt;/strong&gt; Exploring a wider range of options increases the chances of finding the most efficient and suitable solution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Saved time:&lt;/strong&gt; Focusing on the actual problem avoids unnecessary discussions about potentially irrelevant solutions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Avoiding the XY Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here are some tips to avoid falling into the XY problem trap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clearly define the problem you're facing:&lt;/strong&gt; What are you trying to achieve? What specific issue are you encountering?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Provide context and relevant details:&lt;/strong&gt; What have you tried so far? What is the expected outcome?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Be open to exploring different solutions:&lt;/strong&gt; Don't get fixated on your initial idea.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these tips, you can ensure effective communication and collaboration when seeking help with software development problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remember:&lt;/strong&gt; It's always better to focus on the &lt;strong&gt;Y&lt;/strong&gt; (the actual problem) before jumping to the &lt;strong&gt;X&lt;/strong&gt; (solutions).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reference:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For more information on the XY problem, you can refer to the Wikipedia page: &lt;a href="https://en.wikipedia.org/wiki/XY_problem" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/XY_problem&lt;/a&gt;&lt;/p&gt;

</description>
      <category>developer</category>
      <category>softwareengineering</category>
      <category>productivity</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Understanding Strings in Rust: String vs str</title>
      <dc:creator>Abhishek Mishra</dc:creator>
      <pubDate>Mon, 10 Jul 2023 18:01:05 +0000</pubDate>
      <link>https://dev.to/stalwartcoder/understanding-strings-in-rust-string-vs-str-412i</link>
      <guid>https://dev.to/stalwartcoder/understanding-strings-in-rust-string-vs-str-412i</guid>
      <description>&lt;p&gt;If you're a Python developer exploring the Rust language, you'll find that working with strings in Rust is quite different from Python. Rust has two main types to represent strings: &lt;code&gt;String&lt;/code&gt; and &lt;code&gt;str&lt;/code&gt;.   &lt;/p&gt;

&lt;p&gt;Let's dive into what they are and how they differ.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are &lt;code&gt;String&lt;/code&gt; and &lt;code&gt;str&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;String&lt;/code&gt; is a growable, heap-allocated data structure that allows you to store a sequence of UTF-8 characters. This is similar to Python's &lt;code&gt;str&lt;/code&gt; type, but with one key difference - &lt;code&gt;String&lt;/code&gt; in Rust is mutable and can be modified (&lt;a href="https://doc.rust-lang.org/std/string/struct.String.html" rel="noopener noreferrer"&gt;Rust Doc: String&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;On the other hand, &lt;code&gt;str&lt;/code&gt; (pronounced 'string slice') is an immutable reference or 'view' into a string. It can point to the entire string or a subsection of it (&lt;a href="https://doc.rust-lang.org/std/primitive.str.html" rel="noopener noreferrer"&gt;Rust Doc: str&lt;/a&gt;).&lt;br&gt;
You will most commonly encounter &lt;code&gt;str&lt;/code&gt; in its borrowed form, represented as &lt;code&gt;&amp;amp;str&lt;/code&gt;.&lt;br&gt;
Also, &lt;code&gt;&amp;amp;mut str&lt;/code&gt; is a mutable reference to a str. You can use it to perform in-place modifications to the string, as long as those modifications maintain valid UTF-8.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In Rust, &lt;code&gt;str&lt;/code&gt; itself is a type that represents a sequence of valid UTF-8 characters, while &lt;code&gt;&amp;amp;str&lt;/code&gt; and &lt;code&gt;&amp;amp;mut str&lt;/code&gt; are references to such a sequence. The difference is that &lt;code&gt;&amp;amp;str&lt;/code&gt; is an immutable reference (meaning you can't use it to change the underlying string), while &lt;code&gt;&amp;amp;mut str&lt;/code&gt; is a mutable reference (so you can use it to change the underlying string, as long as you maintain valid UTF-8).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Why does Rust have two string types?
&lt;/h2&gt;

&lt;p&gt;The two string types in Rust cater to different use cases. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;String&lt;/code&gt; is used when you need to own a string and change its contents, like appending characters or changing a character at a certain position.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;str&lt;/code&gt; is used for more 'read-only' operations. Since it's an immutable reference, it does not own the underlying memory and cannot alter it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;amp;mut str&lt;/code&gt; allows you to perform some in-place modifications to a string, as long as you maintain valid UTF-8. However, its use is less common and usually requires more care.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;However, the mutable operations that you can do on &lt;code&gt;&amp;amp;mut str&lt;/code&gt; are limited. For example, as the user mentioned, you can use the &lt;code&gt;make_ascii_lowercase&lt;/code&gt; method to change all ASCII alphabetic characters to lowercase in place, but you can't use it to append to the string or change its length, because that could invalidate the UTF-8.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a different from Python, where you're used to working with just one main string type (&lt;code&gt;str&lt;/code&gt;), which is always immutable. &lt;/p&gt;
&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Let's look at an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", world"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// This works fine&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this Rust program, we create a &lt;code&gt;String&lt;/code&gt; and then append to it using the &lt;code&gt;push_str&lt;/code&gt; method, something Python developers might be surprised to see, given that strings in Python are immutable.&lt;/p&gt;

&lt;p&gt;Now, let's see what happens when we try to modify (change a specific character) a &lt;code&gt;str&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;s&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="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'H'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// This will cause an error&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this Rust program, we're trying to replace the first character of the &lt;code&gt;str&lt;/code&gt; s with 'H'. If &lt;code&gt;s&lt;/code&gt; were a mutable &lt;code&gt;String&lt;/code&gt;, we could do this with the &lt;code&gt;replace_range&lt;/code&gt; method. But because &lt;code&gt;s&lt;/code&gt; is a &lt;code&gt;str&lt;/code&gt;, we cannot change its contents, and this program will not compile because &lt;code&gt;str&lt;/code&gt; is immutable.&lt;/p&gt;

&lt;p&gt;If we want to append a character to the string, we first have to convert it to a String with &lt;code&gt;s.to_string()&lt;/code&gt;. Then, we can use the &lt;code&gt;push&lt;/code&gt; method to append a character to the &lt;code&gt;String&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Convert to String to allow changes&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'!'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Append a character to the string&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This program will compile and print "hello!".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example of using &lt;code&gt;&amp;amp;mut str&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HELLO"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;s_slice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;  &lt;span class="c1"&gt;// Obtain a &amp;amp;mut str from the String&lt;/span&gt;
    &lt;span class="n"&gt;s_slice&lt;/span&gt;&lt;span class="nf"&gt;.make_ascii_lowercase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// This works fine&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this program, we create a &lt;code&gt;String&lt;/code&gt; and then obtain a &lt;code&gt;&amp;amp;mut str&lt;/code&gt; slice from it using &lt;code&gt;&amp;amp;mut s[..]&lt;/code&gt;. We then call the &lt;code&gt;make_ascii_lowercase&lt;/code&gt; method on the &lt;code&gt;&amp;amp;mut str&lt;/code&gt; to change all ASCII alphabetic characters to lowercase. The program will print "hello".&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;String&lt;/code&gt; and &lt;code&gt;str&lt;/code&gt; serve different purposes. Use &lt;code&gt;String&lt;/code&gt; when you need to own and modify string data, and use &lt;code&gt;str&lt;/code&gt; when you need a temporary, read-only view into a string.&lt;/p&gt;

&lt;p&gt;Rust string types give you more control over memory allocation and can help prevent bugs related to memory access. This design choice aligns with Rust's core goals of performance and safety. It's one of the ways Rust differs significantly from Python and many other languages, and it's something you'll get used to as you write more Rust code.&lt;/p&gt;

&lt;p&gt;For more detailed information, refer to the official Rust documentation for &lt;a href="https://doc.rust-lang.org/std/string/struct.String.html" rel="noopener noreferrer"&gt;&lt;code&gt;String&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://doc.rust-lang.org/std/primitive.str.html" rel="noopener noreferrer"&gt;&lt;code&gt;str&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>programming</category>
      <category>python</category>
      <category>learning</category>
    </item>
    <item>
      <title>Creating a Low-Latency Cache with Dozer and PostgreSQL</title>
      <dc:creator>Abhishek Mishra</dc:creator>
      <pubDate>Tue, 30 May 2023 05:56:29 +0000</pubDate>
      <link>https://dev.to/getdozer/creating-a-low-latency-cache-with-dozer-and-postgresql-i18</link>
      <guid>https://dev.to/getdozer/creating-a-low-latency-cache-with-dozer-and-postgresql-i18</guid>
      <description>&lt;p&gt;In the realm of software development and data management, the efficiency of data retrieval plays a crucial role in the overall performance of an application. One effective way to enhance this efficiency is by implementing a cache. A cache is a high-speed data storage layer that stores a subset of data, typically transient in nature so that future requests for that data are served up faster than is possible by accessing the data’s primary storage location.&lt;/p&gt;

&lt;p&gt;This blog post explores how to enhance these aspects by implementing a low-latency cache using &lt;a href="https://github.com/getdozer/dozer" rel="noopener noreferrer"&gt;Dozer&lt;/a&gt; and &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt;. We delve into the importance of caching in data management, the limitations of not having a cache, and the unique advantages of using Dozer as a cache layer. We also provide a guide on how to use Dozer for real-time data ingestion from PostgreSQL. This post is a must-read for developers seeking to improve their application's performance and responsiveness, and for those looking to simplify their data infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Do We Need a Cache on Top of PostgreSQL?
&lt;/h2&gt;

&lt;p&gt;PostgreSQL is a powerful, open-source object-relational database system. It is highly extensible and enables high performance on complex queries and heavy loads. However, like any other database, it has its limitations.&lt;/p&gt;

&lt;p&gt;When a database grows in size and complexity, the time taken to retrieve data can increase significantly. This is especially true for complex queries that involve multiple joins and aggregations. In such scenarios, every millisecond counts, and the latency can add up quickly, leading to a slow and unresponsive application.&lt;/p&gt;

&lt;p&gt;This is where a cache comes into play. A cache is a high-speed data storage layer that stores a subset of data so that future requests for that data are served up faster than is possible by accessing the data’s primary storage location. By storing frequently accessed data in a cache, we can significantly reduce the time taken to access this data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the Problem with Not Having a Cache?
&lt;/h2&gt;

&lt;p&gt;Without a cache, every time a client requests data, the application has to query the database. This can be a time-consuming operation, especially if the database is large or the query is complex. This can lead to increased latency and a poor user experience.&lt;/p&gt;

&lt;p&gt;Moreover, without a cache, the database can become a bottleneck, especially under heavy load. Every read and write operation involves a significant amount of work, and as the number of operations increases, the time taken to complete these operations also increases. This can lead to increased CPU and memory usage, and in extreme cases, it can even lead to database crashes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not PostgreSQL Read Replica?
&lt;/h2&gt;

&lt;p&gt;While a PostgreSQL read replica can certainly help offload some of the read operations from your primary database, it's not without its limitations. The process of querying a read replica still involves a network round trip and the overhead of a database query. These factors can contribute to latency, especially when dealing with large volumes of data or complex queries. A cache like the one provided by Dozer, on the other hand, can serve data much faster than a read replica.&lt;/p&gt;

&lt;p&gt;In terms of using a read replica instead of a cache layer like Dozer, it depends on your specific use case and requirements. A read replica can help improve read performance by distributing read traffic across multiple instances, but it may not provide the same level of performance improvement as a cache layer like Dozer.&lt;/p&gt;

&lt;p&gt;Moreover, Dozer doesn't make a distinction between types of data sources. Developers can get a seamless experience building products with application databases such as Postgres and MySQL, data warehouses such as SnowFlake and cloud storage such as S3 and Deltalake. Dozer can also consume real-time events and Ethereum data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Dozer?
&lt;/h2&gt;

&lt;p&gt;In the context of database management, most OLTP workloads involve random disk I/O usage. Given that disks, including SSDs, are slower in performance than RAM, database systems use caching to increase performance. Caching is all about storing data in memory (RAM) for faster access at a later point in time.&lt;/p&gt;

&lt;p&gt;One approach to database caching involves replicating data using Change Data Capture (CDC) to an alternative database optimized for your queries. This method is increasingly being adopted for operations that require extensive data reading. However, it comes with its own set of challenges such as ensuring real-time data, managing indexing, guaranteeing availability, handling schema changes, and considering costs. Dozer addresses these pain points by providing an end-to-end system that takes care of the complexity of caching logic, allowing developers to focus on building their applications.&lt;/p&gt;

&lt;p&gt;Dozer, an open-source data API backend, provides a solution to this. It connects to any of your data sources, transforms and stores the data in an embedded cache powered by LMDB, automatically creates secondary indexes, and instantly generates low-latency REST and gRPC APIs. Dozer is implemented fully in Rust for fast processing of data and is less resource intensive.&lt;/p&gt;

&lt;p&gt;Without a cache layer, data retrieval would rely solely on the performance of the PostgreSQL database and its internal caching mechanisms. This can result in slower response times and increased load on the database server. By using a cache layer like Dozer, you can improve the performance of data retrieval and reduce the load on the database server.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Use Dozer as a Cache
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Architecture Diagram
&lt;/h3&gt;

&lt;p&gt;Here's a simple architecture diagram showing how Dozer can be used as a cache layer for a PostgreSQL database:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpar4c66qu63vqwunymjy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpar4c66qu63vqwunymjy.png" alt="architecture diagram of using Dozer as a cache layer for a PostgreSQL database" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a nutshell:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dozer begins by ingesting data in real-time from the PostgreSQL database using the PostgreSQL connector and stores this data in its cache.&lt;/li&gt;
&lt;li&gt;When a client sends a request for data, Dozer processes the request using the low-latency APIs it has generated, and retrieves the required data from its cache to serve the client.&lt;/li&gt;
&lt;li&gt;For write requests, these are facilitated through the backend API, which directly communicates with the PostgreSQL database. Once the write operation is confirmed, the PostgreSQL database sends a write confirmation back to the backend API.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key point here is that data ingestion into Dozer's cache and the serving of data to the client through Dozer's APIs occur in parallel. This setup ensures quick and efficient access to data, enhancing the performance of your application."&lt;/p&gt;

&lt;p&gt;Dozer provides a &lt;a href="https://getdozer.io/docs/configuration/connectors/#postgresql" rel="noopener noreferrer"&gt;PostgreSQL connector&lt;/a&gt; that allows it to ingest data in real-time from your PostgreSQL database. The configuration can be as simple as the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;app_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;movie-booking&lt;/span&gt;
&lt;span class="na"&gt;connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Postgres&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5438&lt;/span&gt;
      &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;database_name&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;connection_name&lt;/span&gt;

&lt;span class="na"&gt;sql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;-- transformation and&lt;/span&gt;
  &lt;span class="s"&gt;-- analytical queries here.&lt;/span&gt;

&lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;source_name_1&lt;/span&gt;
    &lt;span class="na"&gt;table_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;table_name&lt;/span&gt;
    &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;connection_name&lt;/span&gt;

  &lt;span class="s"&gt;...&lt;/span&gt;

&lt;span class="na"&gt;endpoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;endpoint_name&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/endpoint_path&lt;/span&gt;
    &lt;span class="na"&gt;table_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;table_name&lt;/span&gt;
    &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;primary_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;primary_key_column_name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration allows Dozer to ingest data in real-time from your PostgreSQL database and store it in a high-performance cache. This cache can then be used to serve low-latency data APIs to your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Implementing Dozer with its ability to ingest data in real-time from PostgreSQL can significantly improve the performance of your application by reducing the time taken to access frequently used data. This approach can significantly enhance your application's performance, making it more efficient and responsive in today's demanding tech scenario. By leveraging Dozer's real-time SQL engine, automatic secondary indexing, and instant API generation, developers can drastically lower the cost, complexity, and effort involved in putting together the data infrastructure necessary to build data applications.&lt;/p&gt;

&lt;p&gt;Happy coding, Happy Data APIng! 🚀👩‍💻👨‍💻&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>cache</category>
      <category>api</category>
      <category>systems</category>
    </item>
    <item>
      <title>Secure Your Data APIs with Dozer: Adding Authorization to APIs</title>
      <dc:creator>Abhishek Mishra</dc:creator>
      <pubDate>Thu, 25 May 2023 14:35:50 +0000</pubDate>
      <link>https://dev.to/getdozer/secure-your-data-apis-with-dozer-adding-authorization-to-apis-3pn5</link>
      <guid>https://dev.to/getdozer/secure-your-data-apis-with-dozer-adding-authorization-to-apis-3pn5</guid>
      <description>&lt;p&gt;In today's world of API-driven applications, securing access to data is very important. As the amount of data generated and consumed continues to grow, the need for reliable, and efficient data access management becomes increasingly critical. One essential aspect of data security is ensuring proper authorization for API calls, allowing only the right people, applications, and services to access the required data. Managing access control for your APIs is crucial to guarantee that only authorized users can access and perform specific actions. With the increasing complexity of API ecosystems, secure and efficient authentication and authorization mechanisms are necessary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/getdozer/dozer" rel="noopener noreferrer"&gt;Dozer&lt;/a&gt; addresses this challenge by adding authorization layer to your data APIs in an efficient way. One of the ways Dozer provides authorization is through the use of &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;JSON Web Tokens (JWT)&lt;/a&gt;. JWT is a widely used industry-standard method for representing claims securely between two parties. You can learn more about JWT &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Using JWT tokens simplifies the process of adding authorization to your data APIs.&lt;/p&gt;

&lt;p&gt;To demonstrate this, we'll build a simple movie ticket booking app that has two roles - user (public) and admin. The user can only book tickets and view their bookings, whereas the admin has full access to all the APIs. We will use &lt;a href="https://github.com/getdozer/dozer-js" rel="noopener noreferrer"&gt;&lt;code&gt;@dozerjs/dozer&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/getdozer/dozer-react" rel="noopener noreferrer"&gt;&lt;code&gt;dozer-react&lt;/code&gt;&lt;/a&gt; to enhance the functionality of our app. &lt;code&gt;@dozerjs/dozer&lt;/code&gt; is a TypeScript wrapper over gRPC APIs generated by Dozer, facilitating seamless communication with Dozer, while &lt;code&gt;dozer-react&lt;/code&gt; provides a set of React helpers for using Dozer as a data provider. The sample application's repository can be found &lt;a href="https://github.com/getdozer/dozer-samples/tree/main/usecases/api-auth" rel="noopener noreferrer"&gt;here&lt;/a&gt;, you can aslo find the instructions to run the application directly.&lt;/p&gt;

&lt;p&gt;By following the step-by-step guide we've provided, you can safeguard your application from unauthorized access, ensuring data integrity and user trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Clone the repo and change to the project directory:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:getdozer/dozer-samples.git &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;dozer-samples/usecases/api-auth/
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start the PostgreSQL database:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;database &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate and export a master token for auth:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dozer api generate-token
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MASTER_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_token_here
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start the Dozer app:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dozer
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In a new terminal, install server dependencies and run the server app:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;server &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; node index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In a new terminal, navigate to the &lt;code&gt;client&lt;/code&gt; directory, install client dependencies and start the app:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="nb"&gt;cd&lt;/span&gt; ../client &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;a&gt;localhost:3000&lt;/a&gt; to use the app. For the admin dashboard, go to &lt;a&gt;localhost:3000/admin/dashboard&lt;/a&gt; with "admin" as username and password.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User Page&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5j83id5l2pnbt8np03hb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5j83id5l2pnbt8np03hb.png" alt="user page with list of movies to book" width="730" height="856"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Admin dashboard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkq5kgf37c44s99u0jdsy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkq5kgf37c44s99u0jdsy.png" alt="admin dashboard showing realtime bookings" width="731" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbku1ofpkd7x3sa1sr36a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbku1ofpkd7x3sa1sr36a.png" alt="architecture of movie ticket booking app with dozer and postgresql for adding Authorization to dozer APIs " width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this blog, we'll guide you through the process of constructing a movie ticket booking application using Dozer, React, and PostgreSQL. The PostgreSQL database is utilized directly in our server-side application to manage user creation and ticket bookings.&lt;/p&gt;

&lt;p&gt;To elaborate, the server app is specifically designed to handle user login, create new user entries, and register ticket bookings. It interacts directly with the PostgreSQL database to handle these tasks. The information required for booking tickets, such as booking details, is sent from the React frontend application to the Node.js server app, which then inserts these details into the PostgreSQL database.&lt;/p&gt;

&lt;p&gt;However, when it comes to consuming real-time data like the movie list, dashboard updates, or ongoing bookings, we use Dozer, which fetches the data from PostgreSQL using the PostgreSQL connector. This strategy allows us to get the most recent booking updates and display them on the dashboard in real-time.&lt;/p&gt;

&lt;p&gt;The PostgreSQL connector in Dozer bridges our database with the Dozer server and enables the seamless transfer of data in real-time. You can learn more about this connector at Dozer's documentation page here: &lt;a href="https://getdozer.io/docs/configuration/connectors#postgres" rel="noopener noreferrer"&gt;PostgreSQL Connector&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the client side, we're using a React app to display the movie data and booking interface, pulling data from Dozer. We employ the &lt;code&gt;@dozerjs/dozer&lt;/code&gt; and &lt;code&gt;dozer-react&lt;/code&gt; libraries to simplify interactions with Dozer and access real-time data without having to hardcode API endpoints in the code.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@dozerjs/dozer&lt;/code&gt; library manages gRPC requests between the frontend and the Dozer server, allowing effective communication between the two. In contrast, the &lt;code&gt;dozer-react&lt;/code&gt; library provides a set of React helpers, making it simpler to use Dozer as a data provider in our React app. Find more about these libraries at their respective GitHub repositories: &lt;a href="https://github.com/getdozer/dozer-js" rel="noopener noreferrer"&gt;@dozerjs/dozer&lt;/a&gt; and &lt;a href="https://github.com/getdozer/dozer-react" rel="noopener noreferrer"&gt;dozer-react&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's dive into the process of building this application, demonstrating how you can leverage Dozer to amplify your app development experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server-Side Setup (Express.js)
&lt;/h2&gt;

&lt;p&gt;First, let's set up the server-side code using Express.js. The code is available in &lt;code&gt;server/index.js&lt;/code&gt;:&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ApiClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AuthClient&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@dozerjs/dozer&lt;/span&gt;&lt;span class="dl"&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;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&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;cors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;faker&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@faker-js/faker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//... Rest of the code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We import the required libraries, including &lt;code&gt;express&lt;/code&gt;, &lt;code&gt;@dozerjs/dozer&lt;/code&gt;, &lt;code&gt;axios&lt;/code&gt;, &lt;code&gt;cors&lt;/code&gt;, and &lt;code&gt;@faker-js/faker&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database Connection for Server-Side
&lt;/h3&gt;

&lt;p&gt;Setting up a connection with a PostgreSQL database is crucial to perform operations like user creation and booking entries. We accomplish this using the &lt;code&gt;pg&lt;/code&gt; client.&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pg&lt;/span&gt;&lt;span class="dl"&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;127.0.0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;omdb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postgres&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postgres&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In the configuration object, we specify the parameters like host, port, database name, user, and password. With the successful connection established via &lt;code&gt;client.connect()&lt;/code&gt;, we can execute queries to our database in our Express.js routes.&lt;/p&gt;

&lt;p&gt;This setup enables two primary functionalities in our application:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User creation:&lt;/strong&gt; With the database connection ready, we can insert new user details into the &lt;code&gt;users&lt;/code&gt; table. This is used in the &lt;code&gt;/public/new_user&lt;/code&gt; endpoint, where a new user is created with a unique UUID and a randomly generated name.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Booking entries:&lt;/strong&gt; The connection also allows us to create new entries in the &lt;code&gt;bookings&lt;/code&gt; table. This functionality is used in the &lt;code&gt;/public/book_movie&lt;/code&gt; endpoint, where a user can book a movie, resulting in a new booking record in the database with the user's id and the provided movie id.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Admin Login Endpoint
&lt;/h3&gt;

&lt;p&gt;This endpoint validates the provided username and password. If valid, a post request is made to the authentication server to get a token. The token is then sent back to the client. Error handling is also set up to send a 500 status code in case of a server error and a 400 status code for incorrect credentials.&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/admin/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// Check if the provided credentials are valid&lt;/span&gt;
    &lt;span class="c1"&gt;// Generate JWT token with full access to all API endpoints&lt;/span&gt;
    &lt;span class="c1"&gt;// Send the JWT token to the client&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Public New User Endpoint
&lt;/h3&gt;

&lt;p&gt;The new user endpoint generates a random username and UUID using the &lt;code&gt;faker&lt;/code&gt; library. It then inserts this new user into the database. After successful insertion, a JWT token is generated for the new user with limited access. Error handling is set up in case the server encounters an error while processing the request.&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/public/new_user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// Generate random username and UUID&lt;/span&gt;
    &lt;span class="c1"&gt;// Insert new user into the database&lt;/span&gt;
    &lt;span class="c1"&gt;// Generate JWT token with limited access for the new user&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle server errors&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Public Book Movie Endpoint
&lt;/h3&gt;

&lt;p&gt;The book movie endpoint allows users to book a movie by sending their JWT token in the headers. The server first validates the user's token. If valid, it inserts a new record in the bookings table in the database with the user's id and the provided movie id. The response includes error handling as well.&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/public/book_movie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// Validate the user's token&lt;/span&gt;
    &lt;span class="c1"&gt;// Insert a new record in the bookings table&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle server errors&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Error Handling Middleware
&lt;/h3&gt;

&lt;p&gt;Lastly, we also add a middleware function to handle any errors that may slip through our route handlers. This middleware logs the error and sends a generic error message to the client.&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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="c1"&gt;// log the error, for now just console.log&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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something broke!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After setting up these routes, the Express.js application is ready to listen for requests on port 4000.&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our error handling middleware ensures that any errors that occur during these database operations are effectively captured and appropriately communicated to the user.&lt;br&gt;
In this way, our server is set up to handle the creation of new users, allow users to book movies, and allow an admin to log in, all while ensuring errors are handled appropriately. .&lt;/p&gt;
&lt;h2&gt;
  
  
  Database Setup For Movie data (PostgreSQL)
&lt;/h2&gt;

&lt;p&gt;We use PostgreSQL as our database, and the configuration is available in the &lt;code&gt;docker-compose.yml&lt;/code&gt; file. The file defines a &lt;code&gt;postgres&lt;/code&gt; service, which includes the container name, image, volumes, and environment variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;omdb-postgres&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;debezium/postgres:13&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./pg_hba.conf:/var/lib/foo/pg_hba.conf&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data/init.sql:/docker-entrypoint-initdb.d/init.sql&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/data&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres -c hba_file=/var/lib/foo/pg_hba.conf&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;omdb&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;ALLOW_IP_RANGE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;5438:5432'&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;postgres&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;omdb"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The database is populated with the Open Movie Database (OMDB) dataset, which provides a comprehensive list of movie-related data. For further details about this dataset, you can visit the official OMDB repository here: &lt;a href="https://github.com/credativ/omdb-postgresql" rel="noopener noreferrer"&gt;OMDB on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Front-End Setup (React)
&lt;/h2&gt;

&lt;p&gt;The frontend of our application is designed with React, a popular JavaScript library used for building interactive UIs. The frontend setup for our movie booking application involves a series of React components that interact with our backend server using HTTP requests. These components handle user authentication, data fetching, and real-time updates to ensure users have an interactive and up-to-date interface.&lt;/p&gt;

&lt;p&gt;Let's take a look at the structure of our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── README.md
├── package.json
├── src
│&amp;nbsp;&amp;nbsp; ├── App.css
│&amp;nbsp;&amp;nbsp; ├── App.js
│&amp;nbsp;&amp;nbsp; ├── App.test.js
│&amp;nbsp;&amp;nbsp; ├── components
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; ├── admin
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; └── dashboard.js
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; ├── login.js
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; └── public
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp;     ├── movies.js
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp;     └── moviesList.js
│&amp;nbsp;&amp;nbsp; ├── index.css
│&amp;nbsp;&amp;nbsp; ├── index.js
│&amp;nbsp;&amp;nbsp; ...
└── yarn.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our React components are placed in the &lt;code&gt;src/components&lt;/code&gt; directory, separated by user type (public users and admins).&lt;/p&gt;

&lt;h3&gt;
  
  
  Login Component
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;login.js&lt;/code&gt; component facilitates the login functionality for the admin users. It includes text fields for the admin to enter their username and password, and a login button to submit the login details.&lt;/p&gt;

&lt;p&gt;On submission, a &lt;code&gt;POST&lt;/code&gt; request is made to the &lt;code&gt;http://localhost:4000/admin/login&lt;/code&gt; endpoint with the username and password as the body of the request. If the credentials are valid, the response will contain a token, which is stored in the browser's local storage and used to authenticate future requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Admin Dashboard Component
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;dashboard.js&lt;/code&gt; component acts as the main interface for admin users. On load, it checks if a token exists in local storage. If not, it redirects the user to the login page.&lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;movies_with_bookings&lt;/code&gt; query, it fetches the list of movies with their booking counts and displays them in a table. This component uses real-time updates to ensure the admin always has the most current booking data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Movie List Component
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;moviesList.js&lt;/code&gt; component displays the list of movies and their current booking counts to public users. It allows users to "buy" a ticket for a movie, which is simulated by making a &lt;code&gt;POST&lt;/code&gt; request to the &lt;code&gt;http://localhost:4000/public/book_movie&lt;/code&gt; endpoint with the selected movie's id. The state of this component is updated in real-time as bookings are made.&lt;/p&gt;

&lt;h3&gt;
  
  
  Movies Component
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;movies.js&lt;/code&gt; component acts as a wrapper for the &lt;code&gt;moviesList.js&lt;/code&gt; component. On load, it checks for a token in local storage. If a token doesn't exist, it makes a &lt;code&gt;GET&lt;/code&gt; request to the &lt;code&gt;http://localhost:4000/public/new_user&lt;/code&gt; endpoint to generate a new token. Once a token is obtained, it passes the token as a prop to the &lt;code&gt;MoviesList&lt;/code&gt; component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Dozer JWT in the Application
&lt;/h2&gt;

&lt;p&gt;Having established the foundation of our application in the previous sections, it's time to delve into the secure integration of JWT authentication and Role-Based Access Control (RBAC) using Dozer. Our focus will be on illustrating how this can be applied in our movie ticket booking application.&lt;/p&gt;

&lt;p&gt;Outlined below are the key steps to enable secure API authorization in your application:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate a master token using Dozer's API server.&lt;/li&gt;
&lt;li&gt;Using the master token, generate custom access tokens for each set of APIs to establish granular-level access.&lt;/li&gt;
&lt;li&gt;Incorporate the generated custom access tokens in subsequent client-side API calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Master JWT Token Generation
&lt;/h3&gt;

&lt;p&gt;Kick off the process by running the following command to generate a master JWT token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dozer api generate-token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command triggers the generation of the master token, which is outputted to stdout. The master token has the privilege of accessing all API endpoints specified in the config file. To access the APIs, include the token in your request header as demonstrated below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MASTER_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;your_master_token_here&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Custom Access Token Generation
&lt;/h3&gt;

&lt;p&gt;For a more granular access control, Dozer allows for the creation of custom access tokens for specific API calls. These tokens can be generated through a POST request to the &lt;code&gt;/auth/token&lt;/code&gt; endpoint, providing an access filter and the previously generated &lt;code&gt;MASTER_TOKEN&lt;/code&gt; in the request header.&lt;/p&gt;

&lt;p&gt;This affords you the opportunity to designate specific access controls for different users or roles within your application. For a more detailed guide on this, you may refer to the Dozer documentation page on &lt;a href="https://getdozer.io/docs/configuration/security" rel="noopener noreferrer"&gt;Authentication &amp;amp; Authorization&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the context of our movie ticket booking app, we generate a JWT token comprising the necessary access controls whenever an admin logs in or a new user is registered. This token is then dispatched to the client and utilized in future API calls.&lt;/p&gt;

&lt;p&gt;Here is an illustration of the token generation process in the &lt;code&gt;index.js&lt;/code&gt; file located in the &lt;code&gt;server&lt;/code&gt; directory:&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;//...other code&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MASTER_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MASTER_TOKEN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/admin/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;//...other code&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;All&lt;/span&gt;&lt;span class="dl"&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;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://127.0.0.1:8080/auth/token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&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;Authorization&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;Bearer &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;MASTER_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="c1"&gt;//...other code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Furthermore, we can customize the access token to limit access based on the user's role:&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;//...other code&lt;/span&gt;
&lt;span class="c1"&gt;// Generate token with limited access based on user role&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&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="c1"&gt;//...other code&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;//...other code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code snippet above, the custom access token restricts access to only the &lt;code&gt;need_to_Add_endpoint_name&lt;/code&gt; API endpoint. The access filter can be tweaked to include other endpoints and set specific permissions anchored on user roles.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Incorporating Tokens in Client-Side API Calls
&lt;/h3&gt;

&lt;p&gt;Once the JWT tokens are generated, they can be utilized client-side for secure API access. This can be seen in the &lt;code&gt;movies.js&lt;/code&gt; file and other components housed in the &lt;code&gt;public&lt;/code&gt; directory.&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;//...other code&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Movies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setToken&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;useEffect&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public_jwt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public_jwt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;//...other code&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;span class="c1"&gt;//...other code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever the client makes an API call, the server validates the JWT token and checks if the user has the necessary permissions to access the requested endpoint. If the token is valid and the user will get the valid response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up:
&lt;/h2&gt;

&lt;p&gt;Using Dozer's powerful security capabilities, you can easily add authorization to your data APIs, ensuring that your application remains secure and accessible only to authorized users. Whether you're building a movie ticket app or any other application, Dozer provides a flexible and straightforward way to manage access control for your APIs.&lt;/p&gt;

&lt;p&gt;The beauty of Dozer lies in its flexibility—it moulds itself according to your needs, allowing you to craft custom access controls for different user roles, thereby ensuring the right balance between functionality and security.&lt;/p&gt;

&lt;p&gt;Through our movie ticket booking application, we've demonstrated just a fragment of the potential that Dozer holds. Regardless of your application's domain—be it e-commerce, social media, healthcare, or any other field—you can leverage the power of Dozer to secure your data APIs.&lt;/p&gt;

&lt;p&gt;In conclusion, Dozer presents a robust, scalable, and straightforward solution to facilitate API security and data management. It's a testament to the flexibility of modern software tools and their ability to adapt to a wide range of application needs. We hope this guide has clarified the process of secure API management and inspired you to integrate Dozer into your next project.&lt;/p&gt;

&lt;p&gt;Happy coding, Happy Data APIng! 🚀👩‍💻👨‍💻&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>react</category>
      <category>api</category>
      <category>security</category>
    </item>
    <item>
      <title>ES Modules or CommonJS: What's the Deal and Why Should I Care ?</title>
      <dc:creator>Abhishek Mishra</dc:creator>
      <pubDate>Wed, 10 May 2023 10:53:12 +0000</pubDate>
      <link>https://dev.to/stalwartcoder/es-modules-or-commonjs-whats-the-deal-and-why-should-i-care--3hem</link>
      <guid>https://dev.to/stalwartcoder/es-modules-or-commonjs-whats-the-deal-and-why-should-i-care--3hem</guid>
      <description>&lt;p&gt;Today, I'm on a quest to untangle a little confusion that's been bothering me (as a JS noob 👶)- and maybe you, too. &lt;/p&gt;

&lt;p&gt;It's all about JavaScript module systems: &lt;a href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/" rel="noopener noreferrer"&gt;ES Modules&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/CommonJS" rel="noopener noreferrer"&gt;CommonJS&lt;/a&gt;. Funny enough, I stumbled upon this while trying out a library, &lt;a href="https://github.com/getdozer/dozer-js" rel="noopener noreferrer"&gt;@dozerjs/dozer&lt;/a&gt;, a JavaScript library to interact with &lt;a href="https://github.com/getdozer/dozer" rel="noopener noreferrer"&gt;Dozer&lt;/a&gt;, a data API backend.&lt;/p&gt;

&lt;p&gt;Alright, here's the deal. Back in the day, JavaScript didn't have a built-in module system. So, dev's couldn't easily separate their code into different files or manage dependencies. It was kind of a mess. But then, Node.js stepped up with its own module system, CommonJS. And later, &lt;a href="https://262.ecma-international.org/6.0/" rel="noopener noreferrer"&gt;ES6 (ES2015)&lt;/a&gt; introduced ES Modules.&lt;/p&gt;

&lt;p&gt;Now, you might be thinking, &lt;strong&gt;"Why should I, as a web dev, even care about this? 🤔"&lt;/strong&gt; Well, it's simple. The module system you choose can affect your code's structure, how fast it runs, and even its compatibility. Trust me, I learned this the hard way when I faced some import issues while running a node app with &lt;a href="https://github.com/getdozer/dozer-js" rel="noopener noreferrer"&gt;@dozerjs/dozer&lt;/a&gt;. Let's dive in!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CommonJS&lt;/strong&gt;: This is like the godfather of JavaScript module systems. It uses the &lt;code&gt;require()&lt;/code&gt; function to import modules and &lt;code&gt;module.exports&lt;/code&gt; to export them. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;The cool part?&lt;/em&gt;&lt;/strong&gt; You can use &lt;code&gt;require&lt;/code&gt; pretty much anywhere - inside functions, loops, or based on some conditions. &lt;br&gt;
&lt;strong&gt;&lt;em&gt;The not-so-cool part?&lt;/em&gt;&lt;/strong&gt; Imports are synchronous, meaning they could slow things down a bit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's a little example:&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;// Importing a module&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Exporting a module&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;someFunction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ES Modules&lt;/strong&gt;: These are the new kids on the block, coming in with ES6. Instead of &lt;code&gt;require()&lt;/code&gt; and &lt;code&gt;module.exports&lt;/code&gt;, they use &lt;code&gt;import&lt;/code&gt; and &lt;code&gt;export&lt;/code&gt;. These modules are statically analyzed, which means the imports and exports are determined before the code runs. This can make your code run faster and gives you some extra tooling perks.&lt;/p&gt;

&lt;p&gt;Here's how it looks:&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;// Importing a module&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&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;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Exporting a module&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;someFunction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  So, which one do you choose? 🤹‍♀️**
&lt;/h2&gt;

&lt;p&gt;If you're writing code for the browser, ES Modules are a great choice because modern browsers support them natively. For Node.js, it does support ES Modules, but you might still find yourself using CommonJS for compatibility reasons. &lt;/p&gt;

&lt;p&gt;Got some older browsers or Node.js versions to support? They might not be fans of ES Modules. In that case, you could stick with CommonJS or use a tool like &lt;a href="https://babeljs.io/" rel="noopener noreferrer"&gt;Babel&lt;/a&gt; to compile your ES Modules to CommonJS. &lt;/p&gt;

&lt;p&gt;The trend is definitely leaning towards ES Modules, but there's still a ton of CommonJS code out there. So, it's a good idea to know your way around both. &lt;/p&gt;

&lt;p&gt;Remember, the choice is yours. Pick the module system that fits your project and team the best.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Quick Example: Switching to CommonJS in Node.js
&lt;/h2&gt;

&lt;p&gt;I thought it might be handy to wrap this up with a little example. So, let's say you're working on a Node.js app and you've been using ES Modules. And if want to switch back to CommonJS. &lt;strong&gt;How do you do it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Well, first, you'll need to change your import and export statements. Here's an example:&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;// ES Module import&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&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;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Change to CommonJS require&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&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;But wait, there's another step! You also need to update the type in your &lt;code&gt;package.json&lt;/code&gt; file. If you have &lt;code&gt;"type": "module"&lt;/code&gt;, which allows you to use ES Modules, you'll want to remove it to switch back to CommonJS.&lt;/p&gt;

&lt;p&gt;Here is the &lt;code&gt;package.json&lt;/code&gt; example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dozer_lib_js_test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"commonjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@dozerjs/dozer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^0.0.6"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope this helps!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>node</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Announcing the Dozer Appathon!</title>
      <dc:creator>Abhishek Mishra</dc:creator>
      <pubDate>Wed, 03 May 2023 05:59:55 +0000</pubDate>
      <link>https://dev.to/getdozer/announcing-the-dozer-appathon-2oo7</link>
      <guid>https://dev.to/getdozer/announcing-the-dozer-appathon-2oo7</guid>
      <description>&lt;p&gt;👋🏼 Are you looking for a platform that simplifies the process of building and deploying data-driven applications? Look no further than &lt;a href="https://getdozer.io/" rel="noopener noreferrer"&gt;Dozer&lt;/a&gt; ! 💻 is a &lt;strong&gt;powerful Data API backend&lt;/strong&gt; that simplifies the process of building and deploying data-driven applications &amp;amp; APIs for real-time data processing and analysis, predictive analytics, data caching, and much more.&lt;/p&gt;

&lt;p&gt;And now, you have the chance to showcase your coding skills and creativity by participating in the Dozer Appathon! 🚀 This exciting event is open to everyone who is interested in building applications with Dozer. The submission period runs from &lt;strong&gt;May 3 to May 9, 2023&lt;/strong&gt;; so you still have time to get your app ready! ⏰&lt;/p&gt;

&lt;h2&gt;
  
  
  Dozer Appathon Hacker Guide 👩‍💻👨‍💻
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5y5e7r7n16hyeur5p6kn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5y5e7r7n16hyeur5p6kn.gif" alt="Hero" width="498" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction 🚀
&lt;/h2&gt;

&lt;p&gt;Welcome to the Dozer Appathon! This is your chance to showcase your coding skills and creativity by building amazing applications using our platform. &lt;a href="https://getdozer.io/" rel="noopener noreferrer"&gt;Dozer&lt;/a&gt; is a &lt;strong&gt;powerful Data API backend&lt;/strong&gt; that simplifies the process of building and deploying data-driven applications &amp;amp; APIs. &lt;/p&gt;

&lt;h2&gt;
  
  
  Sample use cases📝
&lt;/h2&gt;

&lt;p&gt;To help you get started, we have prepared a list of sample use cases and ideas for your app. You can use these as inspiration for your project, or come up with your own unique ideas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some sample use cases are
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Real-time data processing and analysis
- Data aggregation and consolidation from multiple sources
- Machine learning and predictive analytics
- Data caching and optimization for faster performance
- IoT data processing and analysis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Some wonderful project ideas💡
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Real-time Eth layer 2 crypto dashboard📈&lt;/li&gt;
&lt;li&gt;NodeJS-based Twilio notifications with real-time alerts using Dozer📲&lt;/li&gt;
&lt;li&gt;Real-time ML predictions using ONNX model🧠&lt;/li&gt;
&lt;li&gt;React Native push notifications📱&lt;/li&gt;
&lt;li&gt;Klarna clone with user profiles and transactions in React Native💳&lt;/li&gt;
&lt;li&gt;Real-time vehicle tracking on Google Maps with traffic density alerts (Web or React Native)🚗&lt;/li&gt;
&lt;li&gt;Real-time inventory dashboard for a retail chain with multiple warehouses🛍️&lt;/li&gt;
&lt;li&gt;Fraud detection for credit card transactions using ML models on Python Lambda💳🕵️‍♂️&lt;/li&gt;
&lt;li&gt;Model training and scoring with data injection through Python Lambda 🧑‍💻📈&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prizes 🎁
&lt;/h2&gt;

&lt;p&gt;We have some exciting prizes up for grabs!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The top 5 submissions will win an amazing Mechanical Keyboard and a Dozer branded Swagpack 🏆&lt;/li&gt;
&lt;li&gt;The next 10 successful submissions win Dozer Branded swagpack which includes an awesome tee and stickers. 🎉&lt;/li&gt;
&lt;li&gt;Additionally, all participants will receive a certificate of participation.📜&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources 📚
&lt;/h2&gt;

&lt;p&gt;To help you build your app, we have some resources for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://getdozer.io/" rel="noopener noreferrer"&gt;https://getdozer.io/&lt;/a&gt; 🌐&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://getdozer.io/docs/dozer" rel="noopener noreferrer"&gt;https://getdozer.io/docs/dozer&lt;/a&gt; 📖&lt;/li&gt;
&lt;li&gt;Blogs: &lt;a href="https://getdozer.io/blog" rel="noopener noreferrer"&gt;https://getdozer.io/blog&lt;/a&gt; 📰&lt;/li&gt;
&lt;li&gt;Blog Tutorial: &lt;a href="https://getdozer.io/blog/building-real-time-data-app-using-dozer-react-postgresql/" rel="noopener noreferrer"&gt;https://getdozer.io/blog/building-real-time-data-app-using-dozer-react-postgresql/&lt;/a&gt; 📚&lt;/li&gt;
&lt;li&gt;Video Tutorial: &lt;a href="https://youtu.be/pVfyMfNrlD4" rel="noopener noreferrer"&gt;https://youtu.be/pVfyMfNrlD4&lt;/a&gt; 📹&lt;/li&gt;
&lt;li&gt;Discord Community support: If you have any questions or need help with your project, you can reach out to &lt;code&gt;#dozer-appathon&lt;/code&gt; channel of the &lt;a href="https://discord.gg/9TeAVfF34S" rel="noopener noreferrer"&gt;Dozer Discord&lt;/a&gt; for support. 💬&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Judging Criteria 🧐
&lt;/h2&gt;

&lt;p&gt;We will rate as per optimal utilisation of Dozer in your app on a scale of 0-10, based on factors like &lt;code&gt;real-time data, multiple data sources, and caching requirements&lt;/code&gt;. We'll also consider the problem you're solving and the code quality of your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Submission Method 📩
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Submit a PR following the &lt;a href="https://github.com/getdozer/dozer-samples/tree/main/community-samples" rel="noopener noreferrer"&gt;Contribution Guidelines&lt;/a&gt; with  your project detail.&lt;/li&gt;
&lt;li&gt;Fill out &lt;a href="https://forms.gle/hoqPqS4qLJAnBpaWA" rel="noopener noreferrer"&gt;this form&lt;/a&gt; post PR submission.&lt;/li&gt;
&lt;li&gt;Winners will be announced in the &lt;a href="https://discord.gg/9TeAVfF34S" rel="noopener noreferrer"&gt;Discord Server&lt;/a&gt;.💪🏆&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Stargazers’ Raffle✨
&lt;/h2&gt;

&lt;p&gt;Star our &lt;a href="https://github.com/getdozer/dozer" rel="noopener noreferrer"&gt;repository&lt;/a&gt; and get a chance to win an amazing Swagpack!!🎁🎉&lt;br&gt;
We will announce the winners in our Discord server. So, don’t forget to &lt;a href="https://discord.gg/9TeAVfF34S" rel="noopener noreferrer"&gt;join&lt;/a&gt;.🤗&lt;/p&gt;

&lt;p&gt;We're excited to see what you can create with Dozer!&lt;br&gt;
Good luck and Happy Hacking!, Happy Data APIng 🚀 👩‍💻👨‍💻&lt;/p&gt;

&lt;p&gt;For more details, checkout: &lt;a href="https://getdozer.io/blog/dozer-appathon" rel="noopener noreferrer"&gt;https://getdozer.io/blog/dozer-appathon&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>hackathon</category>
      <category>api</category>
      <category>developer</category>
    </item>
    <item>
      <title>Unleashing the Power of Dozer Lambda Runtime for Real-time and Event-driven Data Apps</title>
      <dc:creator>Abhishek Mishra</dc:creator>
      <pubDate>Tue, 02 May 2023 14:21:50 +0000</pubDate>
      <link>https://dev.to/getdozer/unleashing-the-power-of-dozer-lambda-runtime-for-real-time-and-event-driven-data-apps-cn3</link>
      <guid>https://dev.to/getdozer/unleashing-the-power-of-dozer-lambda-runtime-for-real-time-and-event-driven-data-apps-cn3</guid>
      <description>&lt;p&gt;Real-time data processing is essential for modern applications, as it ensures that insights are timely and accurate. The open-source project Dozer now provides a runtime environment that allows developers to execute lambda functions or custom user-defined functions based on specific data conditions.&lt;br&gt;
This new functionality allows for more dynamic and event-driven applications, as Lambda functions can be triggered based on specific data change conditions. Just imagine triggering a Twilio notification based on a SQL statement (data change condition)!&lt;/p&gt;

&lt;p&gt;In this blog post, we will discuss how you can use Dozer to respond to real-time data changes by triggering functions based on data conditions.&lt;br&gt;
In this &lt;a href="https://github.com/getdozer/dozer-samples/tree/main/usecases/lambda" rel="noopener noreferrer"&gt;example&lt;/a&gt;, we will create a React app that generates a real-time graph based on room temperature data (room temperature monitoring). We will use the &lt;a href="https://github.com/getdozer/dozer/tree/main/dozer-log-python" rel="noopener noreferrer"&gt;&lt;code&gt;pydozer_log&lt;/code&gt;&lt;/a&gt; module to react to data change conditions and trigger a Twilio message if the room temperature goes above 22.9°C.&lt;/p&gt;
&lt;h2&gt;
  
  
  Dozer Lambda Runtime: A Glimpse
&lt;/h2&gt;

&lt;p&gt;The Dozer Lambda runtime is a major enhancement to the Dozer project, enabling developers to write Lambda functions in JavaScript and Python that react to Dozer events.&lt;/p&gt;

&lt;p&gt;To help you better understand the Dozer Lambda runtime, we will examine the following state diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jh34ullovt53iun1pnx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jh34ullovt53iun1pnx.png" alt="dozer lambda runtime" width="778" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DCC: Data Change Condition&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data Source: Your application's data source, such as a database, sends data to the Dozer pipeline.&lt;/li&gt;
&lt;li&gt;Dozer Pipeline: The data is processed through the Dozer pipeline, which can apply various transformations and aggregations based on the configuration you provide.&lt;/li&gt;
&lt;li&gt;Lambda Runtime: The Dozer Lambda runtime monitors the pipeline for specific data change conditions that you define. If a data change condition is met, the corresponding Lambda function is triggered.&lt;/li&gt;
&lt;li&gt;Action/Trigger: The triggered Lambda function performs the desired action, such as sending a Twilio notification or updating a database record.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reponse of trigger can be used to write back top dozer, for example using gRPC service.&lt;/p&gt;
&lt;h3&gt;
  
  
  JavaScript and Python Bindings for Reading Dozer Logs
&lt;/h3&gt;

&lt;p&gt;Dozer now provides bindings for both JavaScript and Python to read logs, making it easier for developers to work with the languages they are most comfortable with. These bindings are essential components of the Dozer Lambda runtime, as they enable developers to create Lambda functions that respond to&lt;br&gt;
events.&lt;/p&gt;
&lt;h2&gt;
  
  
  React App Example: Room Temperature Monitoring
&lt;/h2&gt;

&lt;p&gt;In this example, we will create a React app that generates a real-time graph based on room temperature data. We will use the pydozer_log module to react to data change conditions and trigger a Twilio message if the room temperature goes above 22.9°C.&lt;/p&gt;

&lt;p&gt;Here are the steps to run the app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the &lt;a href="https://github.com/getdozer/dozer-samples" rel="noopener noreferrer"&gt;Dozer Samples repository&lt;/a&gt; and install dependencies:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/getdozer/dozer-samples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;dozer-samples/usecases/lambda/
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Remove any existing Dozer configuration and start the Dozer:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ./.dozer &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; dozer &lt;span class="nt"&gt;-c&lt;/span&gt; config/dozer-config.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Run the Python scripts to read data from the pipeline:&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: make sure to replace the Twilio configuration in &lt;code&gt;reader.py&lt;/code&gt;, with your account id and auth token. To learn more about Twilio SMS setup checkout this &lt;a href="https://www.twilio.com/docs/sms/quickstart/python" rel="noopener noreferrer"&gt;getting started guide.&lt;/a&gt;&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python reader.py
python main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Navigate to the React app folder, install the necessary packages, and start the development server:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;react
yarn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zkrnl7k0iisbpxp2z8u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zkrnl7k0iisbpxp2z8u.png" alt="reach app showing a graph of room temperature monitoring" width="799" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the app is running, you should see a real-time graph of the room temperature data. If the temperature exceeds 22.9°C, a Twilio message will be triggered, notifying the relevant parties of the situation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh55yk011z1db3w7f6qgi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh55yk011z1db3w7f6qgi.png" alt="twilio message after temperature exceeds 22.9°C" width="800" height="995"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion 🎯
&lt;/h2&gt;

&lt;p&gt;By using the Dozer Lambda runtime, you can create event-driven applications that automatically respond to changes in your data, making your applications more efficient, scalable, and responsive to user needs. By leveraging the Python and JavaScript libraries provided by Dozer, developers can easily build applications that respond to real-time data changes, making it an invaluable resource for modern applications.&lt;/p&gt;

&lt;p&gt;Happy coding, Happy Data APIng! 🚀👩‍💻👨‍💻&lt;/p&gt;

</description>
      <category>lambda</category>
      <category>eventdriven</category>
      <category>react</category>
      <category>twilio</category>
    </item>
    <item>
      <title>🚀 Getting Started with Dozer with Docker: A Step-by-Step Tutorial</title>
      <dc:creator>Abhishek Mishra</dc:creator>
      <pubDate>Mon, 24 Apr 2023 14:00:00 +0000</pubDate>
      <link>https://dev.to/getdozer/getting-started-with-dozer-with-docker-a-step-by-step-tutorial-5ge2</link>
      <guid>https://dev.to/getdozer/getting-started-with-dozer-with-docker-a-step-by-step-tutorial-5ge2</guid>
      <description>&lt;p&gt;In the world of data-driven applications, accessing and manipulating data in real-time is crucial. Dozer is a powerful tool that helps you create low-latency data APIs (gRPC and REST) from any data source, enabling seamless integration with frontend applications. In this tutorial, we'll walk you through setting up Dozer with Docker and connecting it to PostgreSQL using Docker.&lt;/p&gt;

&lt;h3&gt;
  
  
  🌟 Why Dozer?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="[https](https://github.com/getdozer/dozer)"&gt;Dozer&lt;/a&gt; addresses the challenges of accessing and manipulating data in real-time by providing an easy-to-use solution to create efficient data APIs. With Dozer, you can quickly set up APIs that can be easily integrated with your frontend applications. Furthermore, using Docker allows you to containerize your application, making it portable and easy to manage.&lt;/p&gt;

&lt;p&gt;In this step-by-step tutorial, we'll guide you through connecting PostgreSQL with Dozer using Docker. Let's get started!&lt;/p&gt;

&lt;h3&gt;
  
  
  🔧 Prerequisites:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Docker/Docker desktop installed on your machine&lt;/li&gt;
&lt;li&gt;Basic knowledge of Docker and PostgreSQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;📝 Overall steps involved:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;docker-compose&lt;/code&gt; file for PostgreSQL&lt;/li&gt;
&lt;li&gt;Create a Dozer config with PostgreSQL connector and API configuration&lt;/li&gt;
&lt;li&gt;Run PostgreSQL (via Docker)&lt;/li&gt;
&lt;li&gt;Run Dozer (via Docker)&lt;/li&gt;
&lt;li&gt;Query your API&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔹 Step 1: Create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file
&lt;/h3&gt;

&lt;p&gt;First, create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file and copy the following configuration to it or download the file here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.9'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linux/amd64&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;quick-start-postgres&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;public.ecr.aws/getdozer/dozer-samples-pg-stocks:latest&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres -c hba_file=/var/lib/stock-sample/pg_hba.conf&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stocks&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;ALLOW_IP_RANGE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;5434:5432'&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;postgres&lt;/span&gt;&lt;span class="nv"&gt;  &lt;/span&gt;&lt;span class="s"&gt;-h&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;stocks"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sample-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔹 Step 2: Create a Dozer config file
&lt;/h3&gt;

&lt;p&gt;Next, create a &lt;code&gt;dozer-config.yaml&lt;/code&gt; file with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;app_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1-hypercharge-postgres-sample&lt;/span&gt;
&lt;span class="na"&gt;connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Postgres&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;host.docker.internal&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5434&lt;/span&gt;
      &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stocks&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stocks&lt;/span&gt;
&lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stocks&lt;/span&gt;
    &lt;span class="na"&gt;table_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stocks&lt;/span&gt;
    &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ticker&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;date&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;open&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;low&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;close&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;adj_close&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;volume&lt;/span&gt;
    &lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;stocks&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stocks_meta&lt;/span&gt;
    &lt;span class="na"&gt;table_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stocks_meta&lt;/span&gt;
    &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;symbol&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;security_name&lt;/span&gt;
    &lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;stocks&lt;/span&gt;
&lt;span class="na"&gt;endpoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stocks&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/stocks&lt;/span&gt;
    &lt;span class="na"&gt;table_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stocks&lt;/span&gt;
    &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;primary_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stocks_meta&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/stocks-meta&lt;/span&gt;
    &lt;span class="na"&gt;table_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stocks_meta&lt;/span&gt;
    &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;primary_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;symbol&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔹 Step 3: Run PostgreSQL with sample stock data
&lt;/h3&gt;

&lt;p&gt;Open a terminal or command prompt and navigate to the directory containing the &lt;code&gt;docker-compose.yml&lt;/code&gt; file. Run the following command to start PostgreSQL with sample stock data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔹 Step 4: Run Dozer with PostgreSQL connector (via Docker)
&lt;/h3&gt;

&lt;p&gt;Open another terminal or command prompt and navigate to the directory containing the &lt;code&gt;dozer-config.yaml&lt;/code&gt; file. To run Dozer as a Docker container, execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;:/usr/dozer &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-p&lt;/span&gt; 50051:50051 &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/amd64 &lt;span class="se"&gt;\&lt;/span&gt;
       public.ecr.aws/k7k6x1d4/dozer &lt;span class="se"&gt;\&lt;/span&gt;
       dozer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations 🥳 , you should see Dozer up and running!&lt;/p&gt;

&lt;h3&gt;
  
  
  🎉 Query your API
&lt;/h3&gt;

&lt;p&gt;Dozer automatically generates APIs in both REST and gRPC formats, along with documentation, &lt;a href="https://swagger.io/specification/" rel="noopener noreferrer"&gt;OpenAPI&lt;/a&gt;, and proto files. In the following sections, we'll showcase some possible queries. Refer to the APIs section for more details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔸 Query Using gRPC:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can use &lt;a href="https://github.com/fullstorydev/grpcurl" rel="noopener noreferrer"&gt;gRPCurl&lt;/a&gt; or &lt;a href="https://www.postman.com//download" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; to interact with gRPC APIs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;gRPC query example:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;grpcurl &lt;span class="nt"&gt;-plaintext&lt;/span&gt; localhost:50051 dozer.generated.stocks_meta.StocksMetas/query
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;🔸 Query Using REST:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can use curl or Postman to interact with REST APIs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;REST query example:&lt;/em&gt;&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;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="s1"&gt;'localhost:8080/stocks-meta'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! You've successfully set up Dozer with Docker and connected it to PostgreSQL. Now you can easily create APIs for your data and integrate them into your frontend applications.&lt;/p&gt;

&lt;p&gt;If you're interested in learning more about how to use Dozer with applications, we recommend reading our previous blog post: &lt;a href="https://dev.to/getdozer/building-a-real-time-data-app-with-dozer-react-and-postgresql-391n"&gt;"Building a Real-Time Data App with Dozer, React, and PostgreSQL"&lt;/a&gt;. In this blog, you'll find a detailed tutorial that demonstrates how to integrate Dozer with a React frontend application and PostgreSQL as a data source. This comprehensive guide will give you a better understanding of how to build powerful, real-time data-driven applications using Dozer.&lt;/p&gt;

&lt;p&gt;Happy coding, Happy Data APIng! 🚀👩‍💻👨‍💻&lt;/p&gt;

</description>
      <category>docker</category>
      <category>postgres</category>
      <category>dozer</category>
      <category>api</category>
    </item>
    <item>
      <title>Dozer Goes Open Source: Empowering the Community to Build Real-time Data Apps</title>
      <dc:creator>Abhishek Mishra</dc:creator>
      <pubDate>Fri, 21 Apr 2023 15:56:07 +0000</pubDate>
      <link>https://dev.to/getdozer/dozer-goes-open-source-empowering-the-community-to-build-real-time-data-apps-5dd6</link>
      <guid>https://dev.to/getdozer/dozer-goes-open-source-empowering-the-community-to-build-real-time-data-apps-5dd6</guid>
      <description>&lt;p&gt;We are excited to announce that Dozer, a powerful platform for building low-latency data APIs (gRPC and REST) from any data source, is now open source! &lt;a href="https://www.apache.org/licenses/LICENSE-2.0.html" rel="noopener noreferrer"&gt;The Apache 2.0 license&lt;/a&gt; 🎉. With this move, we aim to empower the community to build and scale &lt;a href="https://www.splunk.com/en_us/data-insider/what-is-real-time-data.html" rel="noopener noreferrer"&gt;real-time data&lt;/a&gt; applications more effectively.&lt;/p&gt;

&lt;p&gt;Dozer simplifies the process of connecting applications to various data sources, such as PostgreSQL, Kafka, or other databases &amp;amp; sources, enabling developers to easily create and manage real-time data APIs. By making Dozer open source, we are inviting developers to contribute to its growth and help shape the future of real-time data applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Dozer?
&lt;/h2&gt;

&lt;p&gt;Dozer is a platform that enables developers to build low-latency data APIs (gRPC and REST) from any data source. It simplifies the process of connecting applications to data sources like databases, APIs, or other services, and automatically manages data streaming and synchronization. This allows developers to focus on building powerful applications that utilize real-time data without worrying about the complexities of managing data connections and APIs.&lt;br&gt;
With a few lines of SQL and a simple YAML configuration, you can build, deploy and maintain full data backends. It also has support for client libraries in JS and React to easily integrate with front-end applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Open Source?
&lt;/h2&gt;

&lt;p&gt;There are several reasons why we decided to make Dozer open source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Community-driven innovation:&lt;/strong&gt; We want developers from all over the world to contribute their ideas,and provide valuable insights, improvements, and fixes, leading to a more innovative and robust platform, and faster development cycles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Transparency and trust:&lt;/strong&gt; We want to enable users to view and understand the underlying code, fostering trust in the platform and ensuring that it meets their needs and expectations. Especially how data is being stored and processed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Collaboration and learning:&lt;/strong&gt; We encourage developers to collaborate, share ideas, and learn from one another. We want to foster a strong community that helps developers grow their skills and expertise in the real-time data space.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started with Dozer
&lt;/h2&gt;

&lt;p&gt;To help you get started with Dozer, we've created  &lt;a href="https://getdozer.io/docs/dozer/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; and &lt;a href="https://getdozer.io/blogs/" rel="noopener noreferrer"&gt;tutorial blogs&lt;/a&gt; that guide you through the process of setting up, configuring, and using Dozer for your data applications. You can find these resources on our official documentation site and can also follow &lt;a href="https://dev.to/getdozer"&gt;Dozer on dev.to&lt;/a&gt; or additional resources on getting to know &amp;amp; use Dozer better!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Contribute?
&lt;/h2&gt;

&lt;p&gt;We welcome contributions from the community! If you're interested in contributing to Dozer, please check out our GitHub &lt;a href="https://github.com/getdozer/dozer" rel="noopener noreferrer"&gt;repository&lt;/a&gt; for the guidelines. Whether you want to submit a bug report, suggest a new feature, or contribute code, we appreciate your help in making Dozer even better.&lt;/p&gt;

&lt;p&gt;We also encourage you to check out the following resources to know other ways of contributions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Show and tell GitHub discussion forum&lt;/strong&gt;: We have setup a &lt;a href="https://github.com/getdozer/dozer/discussions/categories/show-and-tell" rel="noopener noreferrer"&gt;GitHub discussion forum&lt;/a&gt;, where you can share your Dozer projects, and experience, ask questions, do a feature request, and connect with fellow Dozer community members. Feel free to join the conversation and share your own projects &amp;amp; ideas!
Additionally, we have also created a discord channel to give developers an opportunity to showcase and talk about their projects. Join our &lt;a href="https://discord.gg/64rQR4d3Z8" rel="noopener noreferrer"&gt;discord channel&lt;/a&gt;, If you’ve built something using Dozer, we’d love to see it!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dozer Samples Repository&lt;/strong&gt;: We have created a &lt;a href="https://github.com/getdozer/dozer-samples" rel="noopener noreferrer"&gt;Dozer Samples repository&lt;/a&gt; on GitHub, which contains sample applications built using Dozer. This repository can be a good resource for learning how to use Dozer and getting inspiration for your projects. You can also contribute to the dozer-sample repository by submitting a pull request with your projects. This not only helps showcase your work but also provides good examples for other developers to learn from and take inspiration to build their own projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also join our community &lt;a href="https://discord.com/invite/3eWXBgJaEQ" rel="noopener noreferrer"&gt;discord&lt;/a&gt; to see what we are cooking at Dozer :female-cook: :male-cook:&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We believe that by making Dozer open source, we are empowering the developer community to build amazing real-time data applications. We look forward to seeing the project and ideas that arise from this collaborative effort, and we're excited to work together to shape the future of real-time data!&lt;br&gt;
Together, we can shape the future of real-time data and contribute to the ongoing success of open source software. 🚀&lt;/p&gt;

&lt;p&gt;Happy coding, Happy Data APIng! 🚀👩‍💻👨‍💻&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>community</category>
      <category>database</category>
      <category>sql</category>
    </item>
  </channel>
</rss>
