<?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: Sonam</title>
    <description>The latest articles on DEV Community by Sonam (@sonam_50a41a4ced7e6b4f3fa).</description>
    <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa</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%2F4004574%2Ff1f1b787-1d13-4716-b3f7-c8d2d134849c.png</url>
      <title>DEV Community: Sonam</title>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sonam_50a41a4ced7e6b4f3fa"/>
    <language>en</language>
    <item>
      <title>A/B Test AI Prompts at the Edge with Telnyx Stateful Actors</title>
      <dc:creator>Sonam</dc:creator>
      <pubDate>Tue, 04 Aug 2026 23:40:32 +0000</pubDate>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa/ab-test-ai-prompts-at-the-edge-with-telnyx-stateful-actors-5a3</link>
      <guid>https://dev.to/sonam_50a41a4ced7e6b4f3fa/ab-test-ai-prompts-at-the-edge-with-telnyx-stateful-actors-5a3</guid>
      <description>&lt;p&gt;Changing a prompt is easy. Knowing whether the new prompt is actually better is the hard part.&lt;/p&gt;

&lt;p&gt;This example builds a small prompt A/B testing API on Telnyx Edge Compute. You send one task and two prompt variants. The app runs both variants through Telnyx AI Inference, stores the experiment in a Stateful Actor, and lets users vote on which result they prefer.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-prompt-ab-tester" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-prompt-ab-tester&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;The app gives you a tiny evaluation loop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create an experiment&lt;/li&gt;
&lt;li&gt;compare two model responses&lt;/li&gt;
&lt;li&gt;vote for variant A or B&lt;/li&gt;
&lt;li&gt;close the experiment&lt;/li&gt;
&lt;li&gt;check aggregate stats&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Routes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /experiments&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /experiments/&amp;lt;id&amp;gt;/vote&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /experiments/&amp;lt;id&amp;gt;/close&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /experiments&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /experiments/&amp;lt;id&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /stats&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /health/liveness&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /health/readiness&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create a prompt experiment
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://edge-prompt-ab-tester-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;.telnyxcompute.com/experiments &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "task": "Write a one-sentence tagline for an edge compute platform.",
    "variant_a": "You are a concise marketing copywriter. Return just the tagline.",
    "variant_b": "You are a technical explainer. Return just the tagline, focus on latency."
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Response:&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;"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;"exp-msf712rs-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;"task"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Write a one-sentence tagline for an edge compute platform."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"variant_a"&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;"prompt"&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 are a concise marketing copywriter. Return just the tagline."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Real-time compute, right where your data lives."&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;"variant_b"&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;"prompt"&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 are a technical explainer. Return just the tagline, focus on latency."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Execute code milliseconds from your users to eliminate network latency."&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;"votes_a"&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;"votes_b"&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;"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;"open"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-08-04T21:51:55Z"&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;
  
  
  Vote on a result
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://edge-prompt-ab-tester-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;.telnyxcompute.com/experiments/exp-msf712rs-0/vote &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"variant":"a"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Close the experiment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://edge-prompt-ab-tester-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;.telnyxcompute.com/experiments/exp-msf712rs-0/close
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check stats:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://edge-prompt-ab-tester-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;.telnyxcompute.com/stats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&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;"total_experiments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"open_experiments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;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;"closed_experiments"&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;"total_votes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"leader"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"variant_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;"leader_votes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&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;
  
  
  The AI call
&lt;/h2&gt;

&lt;p&gt;The app uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v2/ai/chat/completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Default model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zai-org/GLM-5.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each prompt variant becomes the system message. The task becomes the user message. Both variants run against the same input, which makes the comparison easier to reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Stateful Actors?
&lt;/h2&gt;

&lt;p&gt;Prompt tests need a little bit of memory.&lt;/p&gt;

&lt;p&gt;This example uses an &lt;code&gt;ABTester&lt;/code&gt; Stateful Actor to store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;experiments&lt;/li&gt;
&lt;li&gt;prompt variants&lt;/li&gt;
&lt;li&gt;model responses&lt;/li&gt;
&lt;li&gt;vote counts&lt;/li&gt;
&lt;li&gt;open or closed status&lt;/li&gt;
&lt;li&gt;aggregate stats&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means the API can remember experiment state without adding a separate database just for the demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/team-telnyx/telnyx-code-examples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;telnyx-code-examples/edge-prompt-ab-tester
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store your API key as an Edge Compute secret:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;telnyx-edge auth api-key &lt;span class="nb"&gt;set&lt;/span&gt; &amp;lt;YOUR_API_KEY&amp;gt;
telnyx-edge secrets add TELNYX_API_KEY &lt;span class="s2"&gt;"KEY0123..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install and deploy:&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;telnyx-edge ship
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use the deployed URL to create experiments and collect votes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production notes
&lt;/h2&gt;

&lt;p&gt;Before using this pattern for real product decisions, I would add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication&lt;/li&gt;
&lt;li&gt;evaluator identity&lt;/li&gt;
&lt;li&gt;duplicate vote prevention&lt;/li&gt;
&lt;li&gt;randomized or blinded variants&lt;/li&gt;
&lt;li&gt;fixed evaluation sets&lt;/li&gt;
&lt;li&gt;scoring rubrics&lt;/li&gt;
&lt;li&gt;prompt version history&lt;/li&gt;
&lt;li&gt;privacy controls for sensitive tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But even in this small form, it is useful. Prompt changes should not be judged only by vibes. They should leave a trail of examples, votes, and outcomes.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-prompt-ab-tester" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-prompt-ab-tester&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx Edge Compute docs: &lt;a href="https://developers.telnyx.com/docs/edge-compute" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/edge-compute&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI Inference docs: &lt;a href="https://developers.telnyx.com/docs/inference" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/inference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI skills and toolkits: &lt;a href="https://github.com/team-telnyx/ai" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/ai&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx Portal: &lt;a href="https://portal.telnyx.com/" rel="noopener noreferrer"&gt;https://portal.telnyx.com/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>edge</category>
      <category>typescript</category>
      <category>telnyx</category>
    </item>
    <item>
      <title>Build an Edge Crop Advisory API with Telnyx AI Inference</title>
      <dc:creator>Sonam</dc:creator>
      <pubDate>Tue, 04 Aug 2026 20:50:37 +0000</pubDate>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-an-edge-crop-advisory-api-with-telnyx-ai-inference-15lo</link>
      <guid>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-an-edge-crop-advisory-api-with-telnyx-ai-inference-15lo</guid>
      <description>&lt;p&gt;I built this as the next step after the Edge URL Summarizer example. The URL summarizer showed a simple pattern: run an AI workflow at the edge, fetch external content when needed, summarize it, and keep useful state close to the request. This crop advisory example takes that same pattern into a more real-world workflow.&lt;/p&gt;

&lt;p&gt;Instead of only summarizing a page, the app accepts a farmer’s field note or an agriculture advisory URL, classifies the crop issue, returns structured JSON, stores the advisory in a Stateful Actor, tracks issue/severity stats, and flags critical cases for escalation.&lt;/p&gt;

&lt;p&gt;So the goal is not “AI gives farming advice” in a vacuum. The goal is to show how an edge-hosted AI app can turn messy field input into something operational: triage, history, stats, and a clear handoff path when a human expert needs to step in.&lt;br&gt;
Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-agri-crop-advisory" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-agri-crop-advisory&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;You send the app a crop issue description:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://edge-agri-crop-advisory-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;.telnyxcompute.com/advisory &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"description":"Tomato leaves have holes all over them. I can see green caterpillars on the underside of the leaves."}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns a structured advisory:&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;"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;"adv-msf1zxyc-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;"farmer_description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tomato leaves have holes..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"crop_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;"tomato"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"issue_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;"pest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"medium"&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.76&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"recommendation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Inspect the underside of leaves and remove visible caterpillars. Consider an appropriate biological or labeled treatment if damage continues."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"escalate"&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;"generated_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-08-04T19:31:04Z"&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;If the case is critical, it gets flagged:&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;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"critical"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"escalate"&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;"escalated_to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"agronomist-on-call"&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;
  
  
  Routes
&lt;/h2&gt;

&lt;p&gt;The example includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;POST /advisory&lt;/code&gt; - create an advisory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /advisories&lt;/code&gt; - list recent advisories&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /advisories/&amp;lt;id&amp;gt;&lt;/code&gt; - get one advisory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /stats&lt;/code&gt; - see issue/severity/escalation stats&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /health/liveness&lt;/code&gt; - liveness check&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /health/readiness&lt;/code&gt; - readiness check&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;POST /advisory&lt;/code&gt; accepts either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;description&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;url&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you pass a URL, the app fetches the page, strips HTML, and uses that text as input.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AI call
&lt;/h2&gt;

&lt;p&gt;The app calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v2/ai/chat/completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current code path uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zai-org/GLM-5.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The prompt asks the model to return JSON only with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;crop_type&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;issue_type&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;severity&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;confidence&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;recommendation&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Issue types are constrained to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;disease | pest | nutrient | water | weather | unknown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Severity is constrained to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;low | medium | high | critical
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That structure makes the response easier to store, display, route, and review.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stateful Actor part
&lt;/h2&gt;

&lt;p&gt;The app uses a &lt;code&gt;CropAdvisory&lt;/code&gt; Stateful Actor.&lt;/p&gt;

&lt;p&gt;It stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;advisories by ID&lt;/li&gt;
&lt;li&gt;total advisory count&lt;/li&gt;
&lt;li&gt;counts by issue type&lt;/li&gt;
&lt;li&gt;counts by severity&lt;/li&gt;
&lt;li&gt;escalation count&lt;/li&gt;
&lt;li&gt;recent crop types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So after a few requests, you can inspect the accumulated stats:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://edge-agri-crop-advisory-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;.telnyxcompute.com/stats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;

&lt;p&gt;Clone 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;git clone https://github.com/team-telnyx/telnyx-code-examples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;telnyx-code-examples/edge-agri-crop-advisory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set your Telnyx 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;telnyx-edge auth api-key &lt;span class="nb"&gt;set&lt;/span&gt; &amp;lt;YOUR_API_KEY&amp;gt;
telnyx-edge secrets add TELNYX_API_KEY &lt;span class="s2"&gt;"KEY0123..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install and deploy:&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;telnyx-edge ship
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Health check:&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;-sS&lt;/span&gt; &lt;span class="nt"&gt;--retry&lt;/span&gt; 30 &lt;span class="nt"&gt;--retry-delay&lt;/span&gt; 5 &lt;span class="se"&gt;\&lt;/span&gt;
  https://edge-agri-crop-advisory-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;.telnyxcompute.com/health/liveness
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create an advisory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://edge-agri-crop-advisory-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;.telnyxcompute.com/advisory &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"description":"My corn has yellow streaks on bottom leaves with dark brown spots. About 30% of plants affected."}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Production notes
&lt;/h2&gt;

&lt;p&gt;This is a triage example, not a replacement for an agronomist.&lt;/p&gt;

&lt;p&gt;Before using this pattern in production, I would add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication&lt;/li&gt;
&lt;li&gt;farmer/account identity&lt;/li&gt;
&lt;li&gt;region and crop stage&lt;/li&gt;
&lt;li&gt;photo input&lt;/li&gt;
&lt;li&gt;weather data&lt;/li&gt;
&lt;li&gt;human review for high and critical cases&lt;/li&gt;
&lt;li&gt;localized treatment guidance&lt;/li&gt;
&lt;li&gt;safety warnings&lt;/li&gt;
&lt;li&gt;SMS or webhook escalation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Still, the pattern is useful: edge function for intake, AI model for structured classification, Stateful Actor for advisory history and stats.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-agri-crop-advisory" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-agri-crop-advisory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Stateful Actors Quick Start: &lt;a href="https://developers.telnyx.com/docs/edge-compute/stateful-actors/quick-start" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/edge-compute/stateful-actors/quick-start&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI Inference docs: &lt;a href="https://developers.telnyx.com/docs/inference" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/inference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chat Completions API: &lt;a href="https://developers.telnyx.com/api/inference/chat-completions" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/chat-completions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI skills and toolkits: &lt;a href="https://github.com/team-telnyx/ai" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/ai&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>edge</category>
      <category>typescript</category>
      <category>telnyx</category>
    </item>
    <item>
      <title>Build a URL Summarizer at the Edge with Telnyx AI Inference</title>
      <dc:creator>Sonam</dc:creator>
      <pubDate>Tue, 04 Aug 2026 19:06:39 +0000</pubDate>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-a-url-summarizer-at-the-edge-with-telnyx-ai-inference-41e</link>
      <guid>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-a-url-summarizer-at-the-edge-with-telnyx-ai-inference-41e</guid>
      <description>&lt;p&gt;I have been playing with a pattern that feels useful for small AI tools:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;accept a request&lt;/li&gt;
&lt;li&gt;call an AI model&lt;/li&gt;
&lt;li&gt;cache the result close to where the request runs&lt;/li&gt;
&lt;li&gt;avoid building extra infrastructure until you actually need it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This example applies that pattern to URL summarization using Telnyx Edge Compute Stateful Actors.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-url-summarizer" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-url-summarizer&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it builds
&lt;/h2&gt;

&lt;p&gt;The app is a Node.js / TypeScript Edge Compute example.&lt;/p&gt;

&lt;p&gt;You send it a URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://edge-url-summarizer-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;.telnyxcompute.com/summarize &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"url":"https://telnyx.com/blog"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the first request, it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fetches the page&lt;/li&gt;
&lt;li&gt;extracts text from the HTML&lt;/li&gt;
&lt;li&gt;sends the text to Telnyx AI Inference&lt;/li&gt;
&lt;li&gt;asks for exactly three bullet points&lt;/li&gt;
&lt;li&gt;stores the result in Stateful Actor storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On repeat requests for the same URL, it returns the cached summary.&lt;/p&gt;

&lt;h2&gt;
  
  
  API routes
&lt;/h2&gt;

&lt;p&gt;The example includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;POST /summarize&lt;/code&gt; - summarize a URL&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /summarize/cached?url=...&lt;/code&gt; - read a cached summary&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /summarize/refresh&lt;/code&gt; - invalidate a cached URL&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /stats&lt;/code&gt; - view cache hit/miss stats&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /cached&lt;/code&gt; - list cached URLs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /health/liveness&lt;/code&gt; - liveness check&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /health/readiness&lt;/code&gt; - readiness check&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example response
&lt;/h2&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;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/article"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Article"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bullets"&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="s2"&gt;"The article explains the main problem."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"The implementation uses an edge function and AI model."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Cached results make repeat requests faster."&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;"word_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"generated_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-08-04T12:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cached"&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="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;Call the same URL again and the response comes back with:&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;"cached"&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="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;
  
  
  The Telnyx AI call
&lt;/h2&gt;

&lt;p&gt;The app calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v2/ai/chat/completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current sample uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zai-org/GLM-5.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model is prompted to return JSON only:&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;"bullets"&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;"point 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;"point 2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"point 3"&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;That keeps the app response easy to consume from a dashboard, workflow, or internal tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stateful Actor part
&lt;/h2&gt;

&lt;p&gt;The cache lives in a Telnyx Stateful Actor.&lt;/p&gt;

&lt;p&gt;The actor stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;summaries by URL&lt;/li&gt;
&lt;li&gt;cache hits&lt;/li&gt;
&lt;li&gt;cache misses&lt;/li&gt;
&lt;li&gt;total requests&lt;/li&gt;
&lt;li&gt;unique URL count&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means the app can remember previous summaries without adding Redis or a database just for the demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;

&lt;p&gt;Clone 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;git clone https://github.com/team-telnyx/telnyx-code-examples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;telnyx-code-examples/edge-url-summarizer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set your Telnyx 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;telnyx-edge auth api-key &lt;span class="nb"&gt;set&lt;/span&gt; &amp;lt;YOUR_API_KEY&amp;gt;
telnyx-edge secrets add TELNYX_API_KEY &lt;span class="s2"&gt;"KEY0123..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install and deploy:&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;telnyx-edge ship
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test the deployment:&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;-sS&lt;/span&gt; &lt;span class="nt"&gt;--retry&lt;/span&gt; 30 &lt;span class="nt"&gt;--retry-delay&lt;/span&gt; 5 &lt;span class="se"&gt;\&lt;/span&gt;
  https://edge-url-summarizer-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;.telnyxcompute.com/health/liveness
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Summarize a page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://edge-url-summarizer-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;.telnyxcompute.com/summarize &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"url":"https://telnyx.com/blog"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check cache stats:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://edge-url-summarizer-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;.telnyxcompute.com/stats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What I would add before production
&lt;/h2&gt;

&lt;p&gt;For a production version, I would add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication&lt;/li&gt;
&lt;li&gt;rate limiting&lt;/li&gt;
&lt;li&gt;URL allowlists or SSRF protections&lt;/li&gt;
&lt;li&gt;URL normalization&lt;/li&gt;
&lt;li&gt;TTL-based cache expiration&lt;/li&gt;
&lt;li&gt;better HTML extraction&lt;/li&gt;
&lt;li&gt;retries and observability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But as a runnable example, this is a clean way to see Edge Compute, Stateful Actors, and Telnyx AI Inference working together.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-url-summarizer" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-url-summarizer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Stateful Actors Quick Start: &lt;a href="https://developers.telnyx.com/docs/edge-compute/stateful-actors/quick-start" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/edge-compute/stateful-actors/quick-start&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI Inference docs: &lt;a href="https://developers.telnyx.com/docs/inference" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/inference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chat Completions API: &lt;a href="https://developers.telnyx.com/api/inference/chat-completions" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/chat-completions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI skills and toolkits: &lt;a href="https://github.com/team-telnyx/ai" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/ai&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>edge</category>
      <category>typescript</category>
      <category>telnyx</category>
    </item>
    <item>
      <title>Route Voicemails with Python and Telnyx AI</title>
      <dc:creator>Sonam</dc:creator>
      <pubDate>Thu, 30 Jul 2026 18:18:05 +0000</pubDate>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa/route-voicemails-with-python-and-telnyx-ai-39n1</link>
      <guid>https://dev.to/sonam_50a41a4ced7e6b4f3fa/route-voicemails-with-python-and-telnyx-ai-39n1</guid>
      <description>&lt;p&gt;I built a small Flask example that turns voicemail into a routing workflow.&lt;/p&gt;

&lt;p&gt;Code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/voicemail-smart-router-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/voicemail-smart-router-python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app accepts either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a voicemail transcript&lt;/li&gt;
&lt;li&gt;an uploaded voicemail audio file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For audio, it transcribes the voicemail first. Then it uses Telnyx AI Inference to classify the message and decide where it should go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Categories
&lt;/h2&gt;

&lt;p&gt;The app classifies voicemails into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;urgent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;billing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;support&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sales&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;spam&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;routine&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each category maps to a route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;urgent  -&amp;gt; Slack alert
billing -&amp;gt; email
support -&amp;gt; ticket queue
sales   -&amp;gt; CRM lead
spam    -&amp;gt; blocklist + archive
routine -&amp;gt; daily digest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/team-telnyx/telnyx-code-examples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;telnyx-code-examples/voicemail-smart-router-python
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TELNYX_API_KEY=your_telnyx_api_key
AI_MODEL=zai-org/GLM-5.2
FALLBACK_MODEL=meta-llama/Llama-3.3-70B-Instruct
HOST=127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optional Slack webhook for urgent messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SLACK_WEBHOOK=https://hooks.slack.com/...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Classify a transcript
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/voicemails/transcript &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "transcript": "This is an emergency. Our production system is down and we need help immediately.",
    "caller_number": "+17177247292"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example response:&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;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"urgent"&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;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The caller reports a production system outage requiring immediate attention."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"suggested_action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Escalate immediately to the on-call engineering team."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"route"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"slack"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"routed_to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#oncall-alerts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"routing_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;"delivered"&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;
  
  
  Process voicemail audio
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/voicemails/process &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"file=@voicemail.wav"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"caller_number=+17177247292"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For audio, the app calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v2/ai/audio/transcriptions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;distil-whisper/distil-large-v2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v2/ai/chat/completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to classify the transcript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routes included
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /voicemails/transcript&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /voicemails/process&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /voicemails&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /voicemails/&amp;lt;id&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /routes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /health&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Production ideas
&lt;/h2&gt;

&lt;p&gt;This sample uses in-memory storage and a simple routing map.&lt;/p&gt;

&lt;p&gt;For production, I would add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;auth&lt;/li&gt;
&lt;li&gt;durable storage&lt;/li&gt;
&lt;li&gt;webhook ingestion from real voicemail events&lt;/li&gt;
&lt;li&gt;retries for failed delivery&lt;/li&gt;
&lt;li&gt;real email, ticket, and CRM integrations&lt;/li&gt;
&lt;li&gt;review queues for low-confidence messages&lt;/li&gt;
&lt;li&gt;audit logs&lt;/li&gt;
&lt;li&gt;configurable routing rules&lt;/li&gt;
&lt;li&gt;PII handling before storing transcripts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The useful pattern is not just classification. It is classification plus action. The model turns a voicemail into structured intent, and the application routes it to the right workflow.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/voicemail-smart-router-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/voicemail-smart-router-python&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI Inference docs: &lt;a href="https://developers.telnyx.com/docs/inference" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/inference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Audio Transcriptions API: &lt;a href="https://developers.telnyx.com/api/inference/create-transcription" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/create-transcription&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chat Completions API: &lt;a href="https://developers.telnyx.com/api/inference/chat-completions" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/chat-completions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI skills and toolkits: &lt;a href="https://github.com/team-telnyx/ai" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/ai&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>flask</category>
      <category>automation</category>
    </item>
    <item>
      <title>Redact PII from Call Recordings with Python and Telnyx AI</title>
      <dc:creator>Sonam</dc:creator>
      <pubDate>Wed, 29 Jul 2026 19:24:41 +0000</pubDate>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa/redact-pii-from-call-recordings-with-python-and-telnyx-ai-28pl</link>
      <guid>https://dev.to/sonam_50a41a4ced7e6b4f3fa/redact-pii-from-call-recordings-with-python-and-telnyx-ai-28pl</guid>
      <description>&lt;p&gt;I put together a small Flask example that redacts PII from call transcripts and call recordings using Telnyx AI.&lt;/p&gt;

&lt;p&gt;Code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/call-recording-redactor-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/call-recording-redactor-python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app has two workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;submit an existing transcript&lt;/li&gt;
&lt;li&gt;upload an audio file, transcribe it, then redact the transcript&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it redacts
&lt;/h2&gt;

&lt;p&gt;The prompt asks the model to replace common PII with placeholders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;names -&amp;gt; &lt;code&gt;[NAME]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;credit cards -&amp;gt; &lt;code&gt;[CREDIT_CARD]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;SSNs / national IDs -&amp;gt; &lt;code&gt;[SSN]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;phone numbers -&amp;gt; &lt;code&gt;[PHONE]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;emails -&amp;gt; &lt;code&gt;[EMAIL]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;street addresses -&amp;gt; &lt;code&gt;[ADDRESS]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;dates of birth -&amp;gt; &lt;code&gt;[DOB]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;account numbers -&amp;gt; &lt;code&gt;[ACCOUNT_NUMBER]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The useful part is that the response is structured JSON, not just rewritten text.&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;"redacted_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;"Hi, this is [NAME] calling. My card number is [CREDIT_CARD]."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"redactions"&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;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;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"original"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Smith"&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"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[NAME]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"count"&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="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;span class="nl"&gt;"items_redacted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;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;"pii_types_found"&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;"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;"credit_card"&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;That means your app can show the sanitized transcript while still keeping an audit-friendly redaction map.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/team-telnyx/telnyx-code-examples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;telnyx-code-examples/call-recording-redactor-python
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TELNYX_API_KEY=your_telnyx_api_key
AI_MODEL=meta-llama/Llama-3.3-70B-Instruct
HOST=127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Redact a transcript
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/redact &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "transcript": "Hi, this is John Smith calling. My card number is 4532-1234-5678-9012 and my SSN is 123-45-6789."
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This calls Telnyx AI Inference through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v2/ai/chat/completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Redact an audio file
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/redact/audio &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"file=@recording.wav"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For audio, the app first calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v2/ai/audio/transcriptions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;distil-whisper/distil-large-v2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it sends the transcript through the same PII redaction flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routes included
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /redact&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /redact/audio&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /redactions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /redactions/&amp;lt;id&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /health&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Production ideas
&lt;/h2&gt;

&lt;p&gt;This is a starter app, so it stores redaction jobs in memory.&lt;/p&gt;

&lt;p&gt;For production, I would add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;auth&lt;/li&gt;
&lt;li&gt;persistent storage&lt;/li&gt;
&lt;li&gt;async processing for long recordings&lt;/li&gt;
&lt;li&gt;call recording webhook ingestion&lt;/li&gt;
&lt;li&gt;schema validation for model output&lt;/li&gt;
&lt;li&gt;audit logs&lt;/li&gt;
&lt;li&gt;custom PII categories&lt;/li&gt;
&lt;li&gt;role-based access to original transcripts&lt;/li&gt;
&lt;li&gt;audio masking if the original recording must be sanitized too&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main pattern is reusable: turn communications data into structured, safer application data before it moves deeper into your systems.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/call-recording-redactor-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/call-recording-redactor-python&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI Inference docs: &lt;a href="https://developers.telnyx.com/docs/inference" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/inference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Audio Transcriptions API: &lt;a href="https://developers.telnyx.com/api/inference/create-transcription" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/create-transcription&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chat Completions API: &lt;a href="https://developers.telnyx.com/api/inference/chat-completions" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/chat-completions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI skills and toolkits: &lt;a href="https://github.com/team-telnyx/ai" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/ai&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>flask</category>
      <category>privacy</category>
    </item>
    <item>
      <title>Build an AI Quiz Generator in Python</title>
      <dc:creator>Sonam</dc:creator>
      <pubDate>Wed, 29 Jul 2026 17:42:57 +0000</pubDate>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-an-ai-quiz-generator-in-python-4gk0</link>
      <guid>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-an-ai-quiz-generator-in-python-4gk0</guid>
      <description>&lt;p&gt;I put together a small Flask example that turns any article, blog post, documentation page, or training note into a multiple-choice quiz using Telnyx AI Inference.&lt;/p&gt;

&lt;p&gt;Code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/quiz-generator-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/quiz-generator-python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea is simple: send the source text to an LLM, ask for structured JSON, and return a quiz your app can render, store, or export.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it generates
&lt;/h2&gt;

&lt;p&gt;The app returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a quiz title&lt;/li&gt;
&lt;li&gt;a short description&lt;/li&gt;
&lt;li&gt;multiple-choice questions&lt;/li&gt;
&lt;li&gt;A/B/C/D choices&lt;/li&gt;
&lt;li&gt;one correct answer per question&lt;/li&gt;
&lt;li&gt;explanations for the answer key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main endpoint is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /quiz/generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/quiz/generate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "text": "The Telnyx Call Control API allows developers to programmatically control phone calls. You can answer, hangup, transfer, bridge, and record calls. The API is event-driven, meaning you receive webhooks when call events happen.",
    "num_questions": 5,
    "difficulty": "medium"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example response shape:&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;"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;"quiz-1750280400"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Telnyx Call Control API Fundamentals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&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 your understanding of the Telnyx Call Control API."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"difficulty"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"medium"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"questions"&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;span class="nl"&gt;"id"&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;"question"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What setup is required to receive event notifications?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"choices"&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;"A"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Assign a number to a Call Control Application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enable SMS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Install a softphone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"D"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Register with SIP"&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;"correct_answer"&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;"explanation"&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 need a phone number assigned to a Call Control Application with a webhook URL."&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;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;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The app calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v2/ai/chat/completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default model is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;moonshotai/Kimi-K2.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TELNYX_API_KEY=your_telnyx_api_key
AI_MODEL=moonshotai/Kimi-K2.6
HOST=127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The prompt asks the model to return JSON only, with 4 choices per question and short explanations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routes included
&lt;/h2&gt;

&lt;p&gt;The sample includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /quiz/generate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /quizzes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /quizzes/&amp;lt;id&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /quizzes/&amp;lt;id&amp;gt;/answers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /health&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I like the separate answer-key route because it maps nicely to real learning apps. The student view and instructor view usually need different fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production ideas
&lt;/h2&gt;

&lt;p&gt;The example stores quizzes in memory so the core flow is easy to see.&lt;/p&gt;

&lt;p&gt;For production, I would add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;persistent storage&lt;/li&gt;
&lt;li&gt;authentication&lt;/li&gt;
&lt;li&gt;review workflows&lt;/li&gt;
&lt;li&gt;long-document chunking&lt;/li&gt;
&lt;li&gt;exports to JSON, CSV, or LMS formats&lt;/li&gt;
&lt;li&gt;support for true/false or short-answer questions&lt;/li&gt;
&lt;li&gt;stronger JSON validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a starter pattern, but it is a useful one: the LLM is not just returning prose. It is generating structured app data.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/quiz-generator-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/quiz-generator-python&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI Inference docs: &lt;a href="https://developers.telnyx.com/docs/inference" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/inference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chat Completions API: &lt;a href="https://developers.telnyx.com/api/inference/chat-completions" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/chat-completions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI skills and toolkits: &lt;a href="https://github.com/team-telnyx/ai" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/ai&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>flask</category>
      <category>learning</category>
    </item>
    <item>
      <title>Build an AI Moderation Classifier in Python</title>
      <dc:creator>Sonam</dc:creator>
      <pubDate>Wed, 22 Jul 2026 22:17:32 +0000</pubDate>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-an-ai-moderation-classifier-in-python-3p2</link>
      <guid>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-an-ai-moderation-classifier-in-python-3p2</guid>
      <description>&lt;p&gt;Moderation is one of those product features where "just ask an LLM" sounds tempting, but it is not always the best workflow.&lt;/p&gt;

&lt;p&gt;Some content is obvious. Known spam, repeated abuse patterns, and common scam text should be caught quickly and consistently.&lt;/p&gt;

&lt;p&gt;Other content needs judgment. It may be contextual, vague, sarcastic, or borderline.&lt;/p&gt;

&lt;p&gt;I put together a Python Flask example that handles both paths with Telnyx AI Inference:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/moderation-classifier-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/moderation-classifier-python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app uses a two-stage pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Embeddings pre-filter against a known-bad blocklist.&lt;/li&gt;
&lt;li&gt;LLM moderation judgment when there is no strong blocklist match.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The flow
&lt;/h2&gt;

&lt;p&gt;Before moderating content, build the blocklist index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/blocklist/index
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That embeds the bundled &lt;code&gt;sample_blocklist.json&lt;/code&gt; entries through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v2/ai/openai/embeddings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can classify a single piece of content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/moderate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "content": "Great product, really enjoyed using it.",
    "source": "review",
    "author_id": "user-123"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app returns structured fields:&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;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"safe"&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;"flags"&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;"blocklist_match"&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;"recommended_action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Benign positive product review with no policy violations."&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;If content matches the blocklist strongly enough, the app skips the LLM and returns the matched category directly.&lt;/p&gt;

&lt;p&gt;For anything else, it calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v2/ai/chat/completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default models are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI_MODEL=moonshotai/Kimi-K2.6
EMBEDDING_MODEL=thenlper/gte-large
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Endpoints included
&lt;/h2&gt;

&lt;p&gt;The example includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /blocklist/index&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /moderate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /moderate/batch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /blocklist&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /blocklist&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /moderations&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /moderations/&amp;lt;id&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /stats&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /health&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Batch moderation supports up to 20 items:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/moderate/batch &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "items": [
      {"content": "Great product!", "source": "review"},
      {"content": "Buy cheap followers now!", "source": "message"}
    ]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why this shape is useful
&lt;/h2&gt;

&lt;p&gt;The important idea is separating obvious moderation cases from nuanced ones.&lt;/p&gt;

&lt;p&gt;Known-bad patterns can be handled with embeddings similarity.&lt;/p&gt;

&lt;p&gt;Ambiguous content can go to an LLM for classification and reasoning.&lt;/p&gt;

&lt;p&gt;The response is structured enough to plug into product logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;allow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flag&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;remove&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;escalate&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For production, I would add persistence, audit logs, human review queues, rate limiting, and a feedback loop so reviewers can tune the blocklist and thresholds over time.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/moderation-classifier-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/moderation-classifier-python&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI Inference docs: &lt;a href="https://developers.telnyx.com/docs/inference" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/inference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Embeddings API: &lt;a href="https://developers.telnyx.com/api/inference/create-embeddings" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/create-embeddings&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chat Completions API: &lt;a href="https://developers.telnyx.com/api/inference/chat-completions" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/chat-completions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telnyx AI skills and toolkits: &lt;a href="https://github.com/team-telnyx/ai" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/ai&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>flask</category>
      <category>moderation</category>
    </item>
    <item>
      <title>Build an AI Adventure Game in Python</title>
      <dc:creator>Sonam</dc:creator>
      <pubDate>Wed, 22 Jul 2026 19:14:09 +0000</pubDate>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-an-ai-adventure-game-in-python-7b6</link>
      <guid>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-an-ai-adventure-game-in-python-7b6</guid>
      <description>&lt;p&gt;Most LLM demos are one prompt and one answer.&lt;/p&gt;

&lt;p&gt;This one is a little more fun: a text-based choose-your-own-adventure game.&lt;/p&gt;

&lt;p&gt;The player picks a genre, names a character, reads a generated scene, and chooses option 1, 2, or 3. The app keeps track of game state while Telnyx AI Inference generates the next scene.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/adventure-game-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/adventure-game-python&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the app does
&lt;/h2&gt;

&lt;p&gt;The Flask API exposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /game/start
POST /game/&amp;lt;id&amp;gt;/choose
GET /game/&amp;lt;id&amp;gt;
GET /games
GET /health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each game tracks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;genre&lt;/li&gt;
&lt;li&gt;player name&lt;/li&gt;
&lt;li&gt;current scene&lt;/li&gt;
&lt;li&gt;available choices&lt;/li&gt;
&lt;li&gt;location&lt;/li&gt;
&lt;li&gt;health&lt;/li&gt;
&lt;li&gt;inventory&lt;/li&gt;
&lt;li&gt;turn count&lt;/li&gt;
&lt;li&gt;status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Statuses can be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ongoing
won
lost
escaped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How it uses Telnyx AI Inference
&lt;/h2&gt;

&lt;p&gt;The app calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v2/ai/chat/completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Default model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI_MODEL=moonshotai/Kimi-K2.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system prompt asks the model to act as a game master and return JSON only:&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;"scene"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"the scene description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"choices"&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;"choice 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;"choice 2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"choice 3"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"state"&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;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"health"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inventory"&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;"turn"&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="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;"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;"ongoing"&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;That structure is what makes the example useful. The model writes the scene, but the app can still parse the result, store state, validate choices, and decide whether the game continues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;

&lt;p&gt;Clone 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;git clone https://github.com/team-telnyx/telnyx-code-examples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;telnyx-code-examples/adventure-game-python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create your &lt;code&gt;.env&lt;/code&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;cp&lt;/span&gt; .env.example .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your Telnyx API key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TELNYX_API_KEY=your_telnyx_api_key
AI_MODEL=moonshotai/Kimi-K2.6
HOST=127.0.0.1
PORT=5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install and start:&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; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check health:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:5000/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start a fantasy adventure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/game/start &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "genre": "fantasy",
    "player_name": "Aria"
  }'&lt;/span&gt; | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose your next move:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/game/game-&amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/choose &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"choice":1}'&lt;/span&gt; | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try other genres:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/game/start &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"genre":"cyberpunk","player_name":"Void"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Valid genres:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fantasy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sci-fi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mystery&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;horror&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cyberpunk&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;post-apocalyptic&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why this is a useful pattern
&lt;/h2&gt;

&lt;p&gt;The game is playful, but the app pattern is practical.&lt;/p&gt;

&lt;p&gt;It shows how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep state in your backend&lt;/li&gt;
&lt;li&gt;pass recent history back to the model&lt;/li&gt;
&lt;li&gt;ask for structured JSON&lt;/li&gt;
&lt;li&gt;validate user choices&lt;/li&gt;
&lt;li&gt;continue or end a session based on model output&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That same pattern can power training simulations, support flows, onboarding tutorials, guided troubleshooting, or interactive learning tools.&lt;/p&gt;

&lt;p&gt;The model handles the creative generation. Your app owns the rules.&lt;/p&gt;

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

&lt;p&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/adventure-game-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/adventure-game-python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx AI skills and toolkits: &lt;a href="https://github.com/team-telnyx/ai" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx AI Inference docs: &lt;a href="https://developers.telnyx.com/docs/inference" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/inference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chat Completions API: &lt;a href="https://developers.telnyx.com/api/inference/chat-completions" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/chat-completions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx Portal: &lt;a href="https://portal.telnyx.com/" rel="noopener noreferrer"&gt;https://portal.telnyx.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>flask</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Build Semantic Search for Support Tickets in Python</title>
      <dc:creator>Sonam</dc:creator>
      <pubDate>Mon, 20 Jul 2026 22:06:27 +0000</pubDate>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-semantic-search-for-support-tickets-in-python-11jb</link>
      <guid>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-semantic-search-for-support-tickets-in-python-11jb</guid>
      <description>&lt;p&gt;Keyword search is useful until users describe the same problem ten different ways.&lt;/p&gt;

&lt;p&gt;"International SMS is failing."&lt;/p&gt;

&lt;p&gt;"Texts to Germany are not going through."&lt;/p&gt;

&lt;p&gt;"Messages to +49 numbers are stuck."&lt;/p&gt;

&lt;p&gt;Those might all point to the same issue, but exact keyword matching may not connect them.&lt;/p&gt;

&lt;p&gt;This Python example builds semantic search for support tickets using Telnyx AI Inference embeddings.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/semantic-search-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/semantic-search-python&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the app does
&lt;/h2&gt;

&lt;p&gt;The Flask app lets you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;index a bundled support-ticket dataset&lt;/li&gt;
&lt;li&gt;search tickets by meaning&lt;/li&gt;
&lt;li&gt;add a new ticket to the index&lt;/li&gt;
&lt;li&gt;fetch a ticket by ID&lt;/li&gt;
&lt;li&gt;inspect index stats&lt;/li&gt;
&lt;li&gt;check health&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /index
POST /search
POST /tickets
GET /tickets/&amp;lt;id&amp;gt;
GET /stats
GET /health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app calls the Telnyx embeddings endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v2/ai/openai/embeddings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Default model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EMBEDDING_MODEL=thenlper/gte-large
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;For each support ticket, the app combines the subject and body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"{subject}. {body}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;sends those strings to the Telnyx embeddings API&lt;/li&gt;
&lt;li&gt;stores the returned vectors in a numpy matrix&lt;/li&gt;
&lt;li&gt;embeds the search query&lt;/li&gt;
&lt;li&gt;calculates cosine similarity&lt;/li&gt;
&lt;li&gt;returns the top matching tickets&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That gives you meaning-based search without introducing a full vector database for the first version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;

&lt;p&gt;Clone 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;git clone https://github.com/team-telnyx/telnyx-code-examples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;telnyx-code-examples/semantic-search-python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create your &lt;code&gt;.env&lt;/code&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;cp&lt;/span&gt; .env.example .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your Telnyx API key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TELNYX_API_KEY=your_telnyx_api_key
EMBEDDING_MODEL=thenlper/gte-large
HOST=127.0.0.1
PORT=5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install and start:&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; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:5000/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build the index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/index
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Search by meaning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/search &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "query": "I cannot send text messages to international phone numbers",
    "top_k": 3
  }'&lt;/span&gt; | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example result:&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;"query"&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 cannot send text messages to international phone numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"thenlper/gte-large"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_indexed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"results"&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;span class="nl"&gt;"ticket_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;"TKT-1002"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"subject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"International SMS routing issue"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"messaging"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"score"&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.9077&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;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;
  
  
  Try more queries
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/search &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"query":"audio quality problems on calls","top_k":3}'&lt;/span&gt; | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/search &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"query":"my API key stopped working after I changed it","top_k":3}'&lt;/span&gt; | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/search &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"query":"phone number transfer is taking too long","top_k":3}'&lt;/span&gt; | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add a new ticket
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/tickets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "subject": "Cannot receive faxes",
    "body": "Inbound faxes from certain senders are failing to render.",
    "category": "fax",
    "priority": "medium"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app embeds the new ticket and appends it to the in-memory vector index.&lt;/p&gt;

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

&lt;p&gt;This pattern is useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;support-ticket search&lt;/li&gt;
&lt;li&gt;duplicate ticket detection&lt;/li&gt;
&lt;li&gt;incident triage&lt;/li&gt;
&lt;li&gt;internal knowledge search&lt;/li&gt;
&lt;li&gt;agent assist tools&lt;/li&gt;
&lt;li&gt;routing similar issues to the right team&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For production, you would probably swap the in-memory numpy store for pgvector, Qdrant, Weaviate, Pinecone, Redis, or another persistent vector store. You could also combine semantic search with filters for category, priority, date, account, or product.&lt;/p&gt;

&lt;p&gt;The core idea stays simple: Telnyx turns text into vectors, and your app decides how to rank and return the results.&lt;/p&gt;

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

&lt;p&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/semantic-search-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/semantic-search-python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx AI skills and toolkits: &lt;a href="https://github.com/team-telnyx/ai" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx AI Inference docs: &lt;a href="https://developers.telnyx.com/docs/inference" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/inference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Embeddings API: &lt;a href="https://developers.telnyx.com/api/inference/create-embeddings" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/create-embeddings&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx Portal: &lt;a href="https://portal.telnyx.com/" rel="noopener noreferrer"&gt;https://portal.telnyx.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>flask</category>
      <category>search</category>
    </item>
    <item>
      <title>Build an Edge Backend for a Telnyx AI Assistant</title>
      <dc:creator>Sonam</dc:creator>
      <pubDate>Thu, 16 Jul 2026 05:46:30 +0000</pubDate>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-an-edge-backend-for-a-telnyx-ai-assistant-4ooi</link>
      <guid>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-an-edge-backend-for-a-telnyx-ai-assistant-4ooi</guid>
      <description>&lt;p&gt;Voice AI demos get interesting when the assistant needs real backend context.&lt;/p&gt;

&lt;p&gt;It is one thing to have an assistant answer a call. It is another thing to have that assistant greet the caller with dynamic context, collect information, call a backend tool, and read a confirmation back during the same phone call.&lt;/p&gt;

&lt;p&gt;This Go example shows how to use one Telnyx Edge Compute function as the backend for a Telnyx AI Assistant.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-ai-assistant-backend-go" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/edge-ai-assistant-backend-go&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full guide: &lt;a href="https://developers.telnyx.com/docs/edge-compute/guides/ai-assistant-backend" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/edge-compute/guides/ai-assistant-backend&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;The app is a Go Edge Compute function with one public URL.&lt;/p&gt;

&lt;p&gt;That one URL handles two AI Assistant callbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dynamic variables at call start&lt;/li&gt;
&lt;li&gt;a webhook tool call during the conversation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the demo, the assistant is a home-services lead screener. It can resolve a company name for the greeting, then call a &lt;code&gt;schedule_estimate&lt;/code&gt; webhook tool after collecting enough information from the caller.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I like this pattern
&lt;/h2&gt;

&lt;p&gt;Usually, the moment an AI assistant needs application context, you need to build a webhook server.&lt;/p&gt;

&lt;p&gt;That means hosting, deployment, secrets, request verification, and a public URL.&lt;/p&gt;

&lt;p&gt;With Edge Compute, that backend can live close to the Telnyx communications layer. You deploy a function, store secrets, and point the assistant callbacks to the function URL.&lt;/p&gt;

&lt;p&gt;No separate server. No Docker setup. No Kubernetes just to answer a webhook.&lt;/p&gt;

&lt;h2&gt;
  
  
  The important pieces
&lt;/h2&gt;

&lt;p&gt;The handler does three useful things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;verifies Telnyx Ed25519 signatures&lt;/li&gt;
&lt;li&gt;dispatches based on request body shape&lt;/li&gt;
&lt;li&gt;returns the right JSON format for either dynamic variables or tool results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Dynamic variables must be returned under a &lt;code&gt;dynamic_variables&lt;/code&gt; key:&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;"dynamic_variables"&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;"company_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;"Pinecrest Home Services"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"timeframe"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"two business days"&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;The webhook tool returns data the assistant can use in the live conversation:&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;"scheduled_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2025-04-10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scheduled_time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confirmation_number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CONF-1715234567"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estimate_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;"EST-1715234567"&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;
  
  
  Run it
&lt;/h2&gt;

&lt;p&gt;Scaffold a Go function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;telnyx-edge new-func &lt;span class="nt"&gt;-l&lt;/span&gt; go &lt;span class="nt"&gt;-n&lt;/span&gt; edge-ai-assistant-backend
&lt;span class="nb"&gt;cd &lt;/span&gt;edge-ai-assistant-backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fetch your Telnyx public key and store it as an Edge secret:&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="nv"&gt;PUBLIC_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TELNYX_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://api.telnyx.com/v2/public_key | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.data.public'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

telnyx-edge secrets add TELNYX_PUBLIC_KEY &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PUBLIC_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;telnyx-edge ship
telnyx-edge list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then configure your AI Assistant so both the dynamic variables webhook URL and the &lt;code&gt;schedule_estimate&lt;/code&gt; webhook tool URL point to the same Edge Compute invoke URL.&lt;/p&gt;

&lt;p&gt;The full setup is in the guide: &lt;a href="https://developers.telnyx.com/docs/edge-compute/guides/ai-assistant-backend" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/edge-compute/guides/ai-assistant-backend&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this could go
&lt;/h2&gt;

&lt;p&gt;This example uses a scheduling flow, but the backend pattern applies to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;order status lookups&lt;/li&gt;
&lt;li&gt;appointment booking&lt;/li&gt;
&lt;li&gt;account verification&lt;/li&gt;
&lt;li&gt;lead qualification&lt;/li&gt;
&lt;li&gt;dynamic greetings&lt;/li&gt;
&lt;li&gt;warm transfer decisions&lt;/li&gt;
&lt;li&gt;support ticket creation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core idea is simple: keep the assistant conversational, and put the callback logic at the edge.&lt;/p&gt;

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

&lt;p&gt;Edge Compute quickstart: &lt;a href="https://developers.telnyx.com/docs/edge-compute/quickstart" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/edge-compute/quickstart&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AI Assistant dynamic variables: &lt;a href="https://developers.telnyx.com/docs/inference/ai-assistants/dynamic-variables" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/inference/ai-assistants/dynamic-variables&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Webhook signing: &lt;a href="https://developers.telnyx.com/development/api-fundamentals/webhooks/receiving-webhooks#webhook-signing" rel="noopener noreferrer"&gt;https://developers.telnyx.com/development/api-fundamentals/webhooks/receiving-webhooks#webhook-signing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx AI skills and toolkits: &lt;a href="https://github.com/team-telnyx/ai" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>ai</category>
      <category>serverless</category>
      <category>voice</category>
    </item>
    <item>
      <title>Build a Natural Language to SQL API in Python</title>
      <dc:creator>Sonam</dc:creator>
      <pubDate>Wed, 15 Jul 2026 23:51:45 +0000</pubDate>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-a-natural-language-to-sql-api-in-python-11lo</link>
      <guid>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-a-natural-language-to-sql-api-in-python-11lo</guid>
      <description>&lt;p&gt;Most data questions start in plain English.&lt;/p&gt;

&lt;p&gt;"Which customers spent the most?"&lt;/p&gt;

&lt;p&gt;"How many orders are pending?"&lt;/p&gt;

&lt;p&gt;"What products generated revenue last month?"&lt;/p&gt;

&lt;p&gt;Someone can turn those questions into SQL, but that usually means waiting on a developer, analyst, or dashboard update.&lt;/p&gt;

&lt;p&gt;This Python example shows how to build a small natural language to SQL API with Telnyx AI Inference.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/sql-natural-language-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/sql-natural-language-python&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;The Flask app exposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /query
POST /query/sample
POST /validate
GET /queries
GET /queries/&amp;lt;id&amp;gt;
GET /health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;POST /query&lt;/code&gt; accepts a natural-language question, SQL dialect, and schema DDL. It returns structured JSON with the generated SQL, explanation, tables used, and metadata.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POST /query/sample&lt;/code&gt; uses a bundled SQLite sample dataset, so you can ask a question and see real rows come back without connecting a production database.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POST /validate&lt;/code&gt; dry-runs a SQL string against the sample dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why validation matters
&lt;/h2&gt;

&lt;p&gt;Natural language to SQL needs guardrails.&lt;/p&gt;

&lt;p&gt;This example asks the model for read-only SQL and then checks the generated query before execution. The validation layer rejects multiple statements, comments, and write-oriented SQL keywords.&lt;/p&gt;

&lt;p&gt;That keeps the example focused on the useful workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ask a question&lt;/li&gt;
&lt;li&gt;include schema context&lt;/li&gt;
&lt;li&gt;generate a query&lt;/li&gt;
&lt;li&gt;validate the query&lt;/li&gt;
&lt;li&gt;return structured results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The model does the language translation. The app still owns the safety checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;

&lt;p&gt;Clone the examples repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/team-telnyx/telnyx-code-examples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;telnyx-code-examples/sql-natural-language-python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create your &lt;code&gt;.env&lt;/code&gt; file:&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;cp&lt;/span&gt; .env.example .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your Telnyx API key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TELNYX_API_KEY=your_telnyx_api_key
AI_MODEL=moonshotai/Kimi-K2.6
HOST=127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install and start:&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; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask a question against the sample dataset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/query/sample &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"question": "Show me the top 3 customers by total order revenue"}'&lt;/span&gt; | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validate a query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/validate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"sql": "SELECT * FROM orders WHERE total &amp;gt; 100"}'&lt;/span&gt; | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where this could go
&lt;/h2&gt;

&lt;p&gt;This is a small API, but it maps to real internal tooling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;analytics assistants&lt;/li&gt;
&lt;li&gt;support dashboards&lt;/li&gt;
&lt;li&gt;sales operations tools&lt;/li&gt;
&lt;li&gt;data warehouse query helpers&lt;/li&gt;
&lt;li&gt;product usage exploration&lt;/li&gt;
&lt;li&gt;internal admin tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The useful part is the boundary. The app does not blindly trust generated SQL. It asks for structured output, validates the query, and returns JSON that another system can inspect or display.&lt;/p&gt;

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

&lt;p&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/sql-natural-language-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/sql-natural-language-python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx AI skills and toolkits: &lt;a href="https://github.com/team-telnyx/ai" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx AI Inference docs: &lt;a href="https://developers.telnyx.com/docs/inference" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/inference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chat Completions API: &lt;a href="https://developers.telnyx.com/api/inference/chat-completions" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/chat-completions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx Portal: &lt;a href="https://portal.telnyx.com/" rel="noopener noreferrer"&gt;https://portal.telnyx.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>flask</category>
      <category>sql</category>
    </item>
    <item>
      <title>Build a Natural Language to SQL API in Python</title>
      <dc:creator>Sonam</dc:creator>
      <pubDate>Wed, 15 Jul 2026 23:21:04 +0000</pubDate>
      <link>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-a-natural-language-to-sql-api-in-python-3a7p</link>
      <guid>https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-a-natural-language-to-sql-api-in-python-3a7p</guid>
      <description>&lt;p&gt;Most data questions start in plain English.&lt;/p&gt;

&lt;p&gt;"Which customers spent the most?"&lt;/p&gt;

&lt;p&gt;"How many orders are pending?"&lt;/p&gt;

&lt;p&gt;"What products generated revenue last month?"&lt;/p&gt;

&lt;p&gt;Someone can turn those questions into SQL, but that usually means waiting on a developer, analyst, or dashboard update.&lt;/p&gt;

&lt;p&gt;This Python example shows how to build a small natural language to SQL API with Telnyx AI Inference.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/sql-natural-language-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/sql-natural-language-python&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;The Flask app exposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /query
POST /query/sample
POST /validate
GET /queries
GET /queries/&amp;lt;id&amp;gt;
GET /health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;POST /query&lt;/code&gt; accepts a natural-language question, SQL dialect, and schema DDL. It returns structured JSON with the generated SQL, explanation, tables used, and metadata.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POST /query/sample&lt;/code&gt; uses a bundled SQLite sample dataset, so you can ask a question and see real rows come back without connecting a production database.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POST /validate&lt;/code&gt; dry-runs a SQL string against the sample dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why validation matters
&lt;/h2&gt;

&lt;p&gt;Natural language to SQL needs guardrails.&lt;/p&gt;

&lt;p&gt;This example asks the model for read-only SQL and then checks the generated query before execution. The validation layer rejects multiple statements, comments, and write-oriented SQL keywords.&lt;/p&gt;

&lt;p&gt;That keeps the example focused on the useful workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ask a question&lt;/li&gt;
&lt;li&gt;include schema context&lt;/li&gt;
&lt;li&gt;generate a query&lt;/li&gt;
&lt;li&gt;validate the query&lt;/li&gt;
&lt;li&gt;return structured results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The model does the language translation. The app still owns the safety checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;

&lt;p&gt;Clone the examples repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/team-telnyx/telnyx-code-examples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;telnyx-code-examples/sql-natural-language-python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create your &lt;code&gt;.env&lt;/code&gt; file:&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;cp&lt;/span&gt; .env.example .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your Telnyx API key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TELNYX_API_KEY=your_telnyx_api_key
AI_MODEL=moonshotai/Kimi-K2.6
HOST=127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install and start:&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; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask a question against the sample dataset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/query/sample &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"question": "Show me the top 3 customers by total order revenue"}'&lt;/span&gt; | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validate a query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/validate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"sql": "SELECT * FROM orders WHERE total &amp;gt; 100"}'&lt;/span&gt; | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where this could go
&lt;/h2&gt;

&lt;p&gt;This is a small API, but it maps to real internal tooling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;analytics assistants&lt;/li&gt;
&lt;li&gt;support dashboards&lt;/li&gt;
&lt;li&gt;sales operations tools&lt;/li&gt;
&lt;li&gt;data warehouse query helpers&lt;/li&gt;
&lt;li&gt;product usage exploration&lt;/li&gt;
&lt;li&gt;internal admin tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The useful part is the boundary. The app does not blindly trust generated SQL. It asks for structured output, validates the query, and returns JSON that another system can inspect or display.&lt;/p&gt;

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

&lt;p&gt;Code: &lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/sql-natural-language-python" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/telnyx-code-examples/tree/main/sql-natural-language-python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx AI skills and toolkits: &lt;a href="https://github.com/team-telnyx/ai" rel="noopener noreferrer"&gt;https://github.com/team-telnyx/ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx AI Inference docs: &lt;a href="https://developers.telnyx.com/docs/inference" rel="noopener noreferrer"&gt;https://developers.telnyx.com/docs/inference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chat Completions API: &lt;a href="https://developers.telnyx.com/api/inference/chat-completions" rel="noopener noreferrer"&gt;https://developers.telnyx.com/api/inference/chat-completions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Telnyx Portal: &lt;a href="https://portal.telnyx.com/" rel="noopener noreferrer"&gt;https://portal.telnyx.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>flask</category>
      <category>sql</category>
    </item>
  </channel>
</rss>
