<?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: Nathan Roll</title>
    <description>The latest articles on DEV Community by Nathan Roll (@nathanroll).</description>
    <link>https://dev.to/nathanroll</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%2F4114712%2F0fa832f5-db68-48fc-a850-2990a8d2deb5.png</url>
      <title>DEV Community: Nathan Roll</title>
      <link>https://dev.to/nathanroll</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nathanroll"/>
    <language>en</language>
    <item>
      <title>We taught a fruit fly to hear human emotion</title>
      <dc:creator>Nathan Roll</dc:creator>
      <pubDate>Tue, 08 Sep 2026 13:58:57 +0000</pubDate>
      <link>https://dev.to/oruk/we-taught-a-fruit-fly-to-hear-human-emotion-4hem</link>
      <guid>https://dev.to/oruk/we-taught-a-fruit-fly-to-hear-human-emotion-4hem</guid>
      <description>&lt;p&gt;We copied the connections between 499 reconstructed fruit-fly neurons into software and fed the resulting network human voices. A small output layer learned to predict labels listeners had assigned to those recordings. The fly circuit stayed fixed throughout training.&lt;/p&gt;

&lt;p&gt;This was a computational experiment with an artificial input pathway and simplified neuron dynamics. No living fly learned to recognize human feelings.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I'm a cofounder of Oruk, where this experiment was conducted. This adaptation was prepared by an AI agent from our published research article and checked against its reported methods and results. The experiment has not been peer reviewed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://male-cns.janelia.org/download/" rel="noopener noreferrer"&gt;MaleCNS reconstruction&lt;/a&gt; supplies neuron shapes and connection tables. We selected a strongly connected group: every neuron can reach every other through some directed path. It contains 15,865 connections supported by 867,344 synaptic contacts.&lt;/p&gt;

&lt;p&gt;More contacts produce stronger model weights. Neurotransmitter annotations supply positive or negative signs, followed by global spectral scaling. These are modeling assumptions; the wiring diagram alone cannot recreate each cell's physiology.&lt;/p&gt;

&lt;p&gt;That recurrent wiring gives the network a short memory. Every 10 milliseconds, a new frame of audio enters through a fixed random projection. Each neuron combines its neighbors' previous activity with the incoming sound and retains some of its previous state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x[t] = (1 - alpha) * x[t-1]
       + alpha * tanh(W @ x[t-1] + W_in @ u[t])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;u[t]&lt;/code&gt; contains 32 log-mel audio bands, &lt;code&gt;x[t]&lt;/code&gt; contains 499 neuron states, and both weight matrices stay fixed. The interactive model uses &lt;code&gt;alpha = 0.15&lt;/code&gt; and a target recurrent spectral radius of &lt;code&gt;0.9&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is reservoir computing. &lt;a href="https://www.nature.com/articles/s41467-024-44900-4" rel="noopener noreferrer"&gt;Suárez and colleagues&lt;/a&gt; developed conn2res to explore biological connectomes this way; &lt;a href="https://www.mdpi.com/2313-7673/10/5/341" rel="noopener noreferrer"&gt;Costi and colleagues&lt;/a&gt; have used fly connectivity for time-series prediction. We applied the approach to listener judgments of speech.&lt;/p&gt;

&lt;p&gt;We resample audio to 8 kHz, use 25 ms analysis windows, and normalize features using training frames. Four successive temporal averages turn the circuit's activity into 1,996 features. Another 128 features summarize the audio directly. Both branches enter the learned ridge readout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;features = concatenate(pooled_neuron_states, pooled_audio)
scores = features @ beta + bias
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only &lt;code&gt;beta&lt;/code&gt; and &lt;code&gt;bias&lt;/code&gt; are learned. The output has 15 emotion labels and 16 speaking styles. &lt;strong&gt;The direct audio branch matters:&lt;/strong&gt; useful predictions can come from acoustic features without passing through the fly circuit.&lt;/p&gt;

&lt;p&gt;Training used 16,995 clips, validation 2,239, and testing 2,022. Known speakers stay within one split; when speaker identity is unreliable, the entire source corpus stays together. Exact duplicate audio does not cross splits. Most recordings have one listener rating, which limits what their labels can establish.&lt;/p&gt;

&lt;p&gt;The decisive comparison was scrambled wiring. We shuffled connection destinations while preserving each source neuron's outgoing count, signs and weight values before rescaling, then selected settings and trained a separate readout. We also tested audio-only and disconnected-circuit controls.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Test mean average precision&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fly wiring&lt;/td&gt;
&lt;td&gt;16.84%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scrambled wiring&lt;/td&gt;
&lt;td&gt;16.88%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Constant scores&lt;/td&gt;
&lt;td&gt;9.71%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Mean average precision measures ranking across the 31 labels; it is not classification accuracy. The fly-minus-scrambled difference was −0.04 percentage points, with a 95% interval of −0.16 to +0.07. The comparison averages three seeds; intervals use paired bootstrap resamples of 45 held-out speaker/corpus groups. These results provide no evidence that the fly's particular wiring helped on this split.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://oruk.ai/research/we-taught-a-fruit-fly-to-read-human-emotion" rel="noopener noreferrer"&gt;interactive article&lt;/a&gt; also lets you silence neurons while holding the fitted readout fixed. Removing the 50 highest-ranked neurons drops that model's test mAP from 16.91% to 10.83%. Its starting score differs from the table because this intervention uses one model, rather than the three-seed mean.&lt;/p&gt;

&lt;p&gt;That readout depends on its circuit's features. Destroying those features after training can hurt even when a different circuit, trained separately, works equally well. The intervention and scrambled control therefore answer different questions.&lt;/p&gt;

&lt;p&gt;You can rotate the reconstructed neurons, compare six licensed demonstration recordings and rerun the intervention in the original article. The clips differ in speakers and words as well as listener labels; colored activity is not evidence of biological “emotion cells.” Those interactive figures cannot run inside this DEV post.&lt;/p&gt;

&lt;p&gt;The fitted demonstration model and six excerpts are public. The full speech-labeling dataset and listener records remain private, so this is not a fully reproducible public benchmark. The fly circuit is an exploratory model, separate from Oruk's production speech API.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>neuroscience</category>
      <category>research</category>
    </item>
    <item>
      <title>Build a local call-review panel with Python</title>
      <dc:creator>Nathan Roll</dc:creator>
      <pubDate>Tue, 08 Sep 2026 01:31:19 +0000</pubDate>
      <link>https://dev.to/nathanroll/build-a-local-call-review-panel-with-python-2dgh</link>
      <guid>https://dev.to/nathanroll/build-a-local-call-review-panel-with-python-2dgh</guid>
      <description>&lt;p&gt;An audio analysis response is easier to inspect when you can hear the passage beside its transcript. This tutorial builds a local review page that lets you replay a speaker turn, search the words or annotations, and read vocal-expression scores separately from what was said.&lt;/p&gt;

&lt;p&gt;We will start with an actual saved response and a licensed public recording. That path needs Python and a browser, but no API key, model download, or inference request. Then we will connect the same page to the Oruk Python SDK for your own recordings.&lt;/p&gt;

&lt;p&gt;Disclosure: this example is maintained by Oruk, the API provider. The article and implementation were prepared with an AI coding agent and checked with automated tests and browser playback tests. The sample demonstrates an integration; it is not an accuracy evaluation or a customer case study.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the saved example
&lt;/h2&gt;

&lt;p&gt;You need Python 3.10 or later, curl, and a current browser. The complete renderer uses Python's standard library. It generates an HTML file with a native audio player, plain JavaScript controls, and no third-party scripts or fonts.&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;mkdir &lt;/span&gt;oruk-call-review
&lt;span class="nb"&gt;cd &lt;/span&gt;oruk-call-review
curl &lt;span class="nt"&gt;--fail&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; call-review.py https://oruk.ai/examples/call-review.py
curl &lt;span class="nt"&gt;--fail&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; response.json https://oruk.ai/samples/conversations/02-grocery-prices.oruk.json
curl &lt;span class="nt"&gt;--fail&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; recording.wav https://oruk.ai/samples/conversations/02-grocery-prices.wav
curl &lt;span class="nt"&gt;--fail&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; attribution.txt https://oruk.ai/examples/call-review-attribution.txt
python3 call-review.py &lt;span class="nt"&gt;--response&lt;/span&gt; response.json &lt;span class="nt"&gt;--audio&lt;/span&gt; recording.wav &lt;span class="nt"&gt;--output&lt;/span&gt; review.html &lt;span class="nt"&gt;--attribution-file&lt;/span&gt; attribution.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;review.html&lt;/code&gt; in your browser. Keep &lt;code&gt;recording.wav&lt;/code&gt; next to it. On Windows, use your Python launcher if &lt;code&gt;python3&lt;/code&gt; is not available.&lt;/p&gt;

&lt;p&gt;The 14.45-second grocery conversation comes from &lt;a href="https://huggingface.co/datasets/TheAgenticDataCompany/open-yap-1k" rel="noopener noreferrer"&gt;The Agentic Data Company's Open Yap 1K public sample&lt;/a&gt;, licensed under CC BY 4.0. Oruk excerpted and downmixed it. The attribution file is included in the generated report; preserve it when sharing the sample. Other demo recordings can have different permissions.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://oruk.ai/examples/call-review.py" rel="noopener noreferrer"&gt;complete program&lt;/a&gt; is available under the &lt;a href="https://oruk.ai/examples/call-review.LICENSE.txt" rel="noopener noreferrer"&gt;MIT license&lt;/a&gt;. The &lt;a href="https://oruk.ai/samples/conversations/02-grocery-prices.oruk.json" rel="noopener noreferrer"&gt;saved JSON&lt;/a&gt; contains the model's original output, not substitute scores written for this tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the result before adding an API call
&lt;/h2&gt;

&lt;p&gt;The page has four passages. The first runs from 0.185 to 4.325 seconds and has the local label &lt;code&gt;speaker_0&lt;/code&gt;. Its transcript begins:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm sorry. The price of food has gone up so much.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The returned emotion annotation is &lt;code&gt;disappointed&lt;/code&gt;, with a score of 0.868 when rounded. The speaking-style annotation is &lt;code&gt;casual&lt;/code&gt;, with a rounded score of 0.869. The report displays them in separate lists below the words.&lt;/p&gt;

&lt;p&gt;Press &lt;strong&gt;Play passage 1&lt;/strong&gt; to replay that interval. Playback pauses near the returned end time. Choose &lt;strong&gt;Play from here without stopping&lt;/strong&gt; when you want to hear the surrounding context. Searching &lt;code&gt;frustrated&lt;/code&gt; should leave two passages visible; clearing the search restores all four. Filtering reads the existing response and does not call the model.&lt;/p&gt;

&lt;p&gt;There is a useful limitation in this example: its &lt;code&gt;words&lt;/code&gt; arrays are empty. The response provides speaker-turn boundaries, not individual word timing. The page says that explicitly. If another response includes word timestamps, a details control exposes those returned values and lets you replay a word. It never assigns timestamps by dividing a passage's duration by its word count.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyze your own recording
&lt;/h2&gt;

&lt;p&gt;For a fresh analysis, use an English recording you have permission to process, up to 30 MB and 60 minutes. Create a key through your Oruk account and set &lt;code&gt;ORUK_API_KEY&lt;/code&gt; in your environment. The live API uses the &lt;a href="https://oruk.ai/pricing" rel="noopener noreferrer"&gt;current subscription terms&lt;/a&gt;; the saved-data example above does not require a subscription.&lt;/p&gt;

&lt;p&gt;This command reuses the SDK's existing complete file example rather than introducing another upload implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="c"&gt;# macOS / Linux; on Windows use .venv\Scripts\activate&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install &lt;/span&gt;&lt;span class="nv"&gt;oruk&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;0.2.6
curl &lt;span class="nt"&gt;--fail&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; analyze-file.py https://oruk.ai/examples/analyze-file.py

&lt;span class="c"&gt;# Set ORUK_API_KEY in the environment before this command.&lt;/span&gt;
python analyze-file.py my-recording.wav &lt;span class="nt"&gt;--diarize&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; my-response.json &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  python call-review.py &lt;span class="nt"&gt;--response&lt;/span&gt; my-response.json &lt;span class="nt"&gt;--audio&lt;/span&gt; my-recording.wav &lt;span class="nt"&gt;--output&lt;/span&gt; my-review.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The renderer runs only if analysis succeeds. It reads the saved file; it does not upload or analyze the recording again. Do not attach the grocery sample's attribution to your own audio. You can supply your own source note with &lt;code&gt;--attribution-file&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you already have a Python application, use this request-and-save step instead of the &lt;code&gt;analyze-file.py&lt;/code&gt; command:&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;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;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;oruk&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Oruk&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;Oruk&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ORUK_API_KEY&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;client&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-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;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;oruk-resonance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-response.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;write_text&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="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ensure_ascii&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&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="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;utf-8&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;Choose the CLI or this snippet. Running both makes two logical requests. Unified analysis returns the transcript, emotion, and speaking style together; separate transcription and affect calls would process the audio separately.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;diarize=True&lt;/code&gt; makes the segments speaker turns. Leave &lt;code&gt;num_speakers&lt;/code&gt; unset unless you know the number of speakers. The labels belong to that recording; &lt;code&gt;speaker_0&lt;/code&gt; does not mean “customer,” “agent,” or a persistent identity. These SDK calls use the recorded-file API, not the separate realtime WebSocket preview.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the fields separate
&lt;/h2&gt;

&lt;p&gt;The report is built around a small data model:&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;segment&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;segments&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;segment&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="n"&gt;segment&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="n"&gt;segment&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="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;Words:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;segment&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;text&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;Emotion scores:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;segment&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;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;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;Style scores:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;segment&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;styles&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;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;segment&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="ow"&gt;or&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;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="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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;text&lt;/code&gt; is a model transcript and can contain transcription errors. &lt;code&gt;emotions&lt;/code&gt; and &lt;code&gt;styles&lt;/code&gt; contain selected acoustic model scores. They describe model support for how speech sounds; they do not reveal a person's private feelings or intent.&lt;/p&gt;

&lt;p&gt;Several labels can coexist. Their scores need not sum to one, and the numbers are not automatically calibrated probabilities. Emotion output includes the highest-scoring label when none meets its selection threshold. An empty style list means no style was returned, which does not establish absence. See the &lt;a href="https://oruk.ai/docs#labels" rel="noopener noreferrer"&gt;score interpretation reference&lt;/a&gt; before designing application thresholds.&lt;/p&gt;

&lt;p&gt;The report keeps the returned order and values, displays three decimal places, and preserves the full score in the meter value and numeric tooltip. It does not turn a high score into a customer-risk verdict or rank a speaker's performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replay from the browser's media clock
&lt;/h2&gt;

&lt;p&gt;The essential interaction is a seek followed by playback:&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;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;await&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;play&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complete program also tracks the chosen end time, checks that boundary while playback is running, and pauses near it. It stops that animation-frame check when paused. Native seeking outside the selected interval releases the stop boundary. Highlighting uses &lt;code&gt;audio.currentTime&lt;/code&gt;, so it follows the recording rather than a separate elapsed-time timer. Overlapping intervals can both be active.&lt;/p&gt;

&lt;p&gt;These boundaries are useful for reviewing a passage. They are not sample-accurate editing cuts. Browser media clocks and seek precision impose limits.&lt;/p&gt;

&lt;p&gt;The renderer escapes transcript text, labels, titles, and source notes before inserting them into HTML. It does not inject a tagged transcript as executable markup. Its Content Security Policy permits the generated script and style by hash, allows local media, and blocks network connections. The generated report has no analytics or API calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle the failures a reviewer will encounter
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Invalid credentials or a rejected request:&lt;/strong&gt; the SDK CLI exits unsuccessfully, with the HTTP status, code, and request ID on stderr. An empty stdout file is not a successful response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Temporary service errors:&lt;/strong&gt; SDK 0.2.6 retries HTTP 429, 500, 502, 503, and 504 up to twice. It reuses a request ID for tracing, which does not establish exactly-once processing. Python network and timeout errors propagate. Do not add an unbounded retry loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Malformed saved data:&lt;/strong&gt; the renderer rejects API error objects, unsupported tasks, invalid intervals, and non-finite or out-of-range scores before writing the report. It refuses to overwrite its input files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empty segments or missing scores:&lt;/strong&gt; the page says what was not provided. The full transcript remains available even when there are no timed passages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The wrong or missing recording:&lt;/strong&gt; the page reports loading/playback errors and warns if the audio duration differs from the response. Equal durations cannot prove two files belong together; use the exact recording that produced the response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep the report's relative audio path intact when moving files. The HTML contains the transcript, even though it never contains the API key. Treat the report and recording under the same permissions and access controls.&lt;/p&gt;

&lt;p&gt;This is a local review tool, not an authenticated multi-user application. A team version needs recording permissions, reviewer access, storage and retention rules, and representative evaluation before introducing any automatic triage threshold. The small example provides a place to inspect those decisions against the original audio.&lt;/p&gt;

&lt;p&gt;Further reference: &lt;a href="https://oruk.ai/guides/speaker-diarization-python" rel="noopener noreferrer"&gt;speaker diarization&lt;/a&gt;, &lt;a href="https://oruk.ai/docs/sdks" rel="noopener noreferrer"&gt;SDK setup and errors&lt;/a&gt;, and &lt;a href="https://oruk.ai/docs#reference-analysis" rel="noopener noreferrer"&gt;analysis response fields&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
