<?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: Ryan Cotten</title>
    <description>The latest articles on DEV Community by Ryan Cotten (@littlestjames82sys).</description>
    <link>https://dev.to/littlestjames82sys</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%2F4181281%2F390eabfd-be9e-4b62-b06d-9a1614087e84.png</url>
      <title>DEV Community: Ryan Cotten</title>
      <link>https://dev.to/littlestjames82sys</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/littlestjames82sys"/>
    <language>en</language>
    <item>
      <title>I built an after-hours front desk that runs on the shop's own laptop, in the owner's voice, with no cloud AI</title>
      <dc:creator>Ryan Cotten</dc:creator>
      <pubDate>Wed, 14 Oct 2026 02:07:12 +0000</pubDate>
      <link>https://dev.to/littlestjames82sys/i-built-an-after-hours-front-desk-that-runs-on-the-shops-own-laptop-in-the-owners-voice-with-no-3873</link>
      <guid>https://dev.to/littlestjames82sys/i-built-an-after-hours-front-desk-that-runs-on-the-shops-own-laptop-in-the-owners-voice-with-no-3873</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The call every small shop misses
&lt;/h2&gt;

&lt;p&gt;It is 7:04 PM in East Tennessee. The shop is dark, the trucks are&lt;br&gt;
parked, and the owner is at the kitchen table. The office phone rings&lt;br&gt;
four times and goes to voicemail. On the other end is a homeowner whose&lt;br&gt;
heat just quit, with a baby in the house, deciding which name on Google&lt;br&gt;
to try next. She does not leave a message. Almost nobody does. She&lt;br&gt;
calls the next shop.&lt;/p&gt;

&lt;p&gt;I build software for small trade businesses out here: HVAC companies,&lt;br&gt;
plumbers, excavators, tree crews. Most of them are one or two trucks.&lt;br&gt;
They cannot staff a phone at night, and the answering services they can&lt;br&gt;
afford sound like answering services. So I built them a front desk that&lt;br&gt;
answers after hours, in the shop's own voice, from a computer the shop&lt;br&gt;
already owns. It holds a real conversation, figures out how urgent the&lt;br&gt;
problem is by the shop's own definition of urgent, and leaves the owner&lt;br&gt;
a clean summary card to work from in the morning.&lt;/p&gt;

&lt;p&gt;One honest note before the demo: the first voice engine I picked for&lt;br&gt;
this carried a non-commercial license, which would have made the whole&lt;br&gt;
product illegal to sell. Catching that line is part of the story below,&lt;br&gt;
because a side hustle lives or dies on exactly that kind of fine print.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;After-Hours Front Desk&lt;/strong&gt;: a voice receptionist for small trade shops&lt;br&gt;
that runs entirely on the shop's own computer. No cloud AI bills per&lt;br&gt;
call, no customer data leaving the building.&lt;/p&gt;

&lt;p&gt;When a call comes in, the desk answers out loud, asks what the problem&lt;br&gt;
is, takes a name, a callback number, an address, and a requested time,&lt;br&gt;
judges the urgency against the shop's own written rules, and at hang-up&lt;br&gt;
extracts a summary card like this one (real output from a real demo run,&lt;br&gt;
not a mock-up):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caller:&lt;/strong&gt; Sarah Daniels · &lt;strong&gt;Phone:&lt;/strong&gt; 423-555-0147 · &lt;strong&gt;Job:&lt;/strong&gt; Heat quit&lt;br&gt;
&lt;strong&gt;Urgency: emergency&lt;/strong&gt; · &lt;strong&gt;Address:&lt;/strong&gt; 418 Pine Street, Oakdale&lt;br&gt;
&lt;em&gt;"Heat failure with a four-month-old baby in the house."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finished calls also land in an owner review list, the "morning list,"&lt;br&gt;
so the day starts with every after-hours call already sorted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is built today, labeled plainly:&lt;/strong&gt; a call simulator. You type&lt;br&gt;
the caller's side into a browser page; the desk thinks and speaks out&lt;br&gt;
loud for real. Wiring it to an actual phone line, with local&lt;br&gt;
speech-to-text for the caller's voice, is the paid next step, and I am&lt;br&gt;
not going to pretend it is done. The two shops in the demo, an HVAC&lt;br&gt;
company and a plumbing company you can switch between, are fictional.&lt;br&gt;
The voice is a bundled demo profile standing in for the shop owner's&lt;br&gt;
own consented voice clone, which is how the paid version works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who pays and why:&lt;/strong&gt; the buyer is the owner of a one or two-truck&lt;br&gt;
shop who loses evening jobs to the next name on Google. Cloud AI&lt;br&gt;
receptionists run about $30 to $100 a month; human answering services&lt;br&gt;
run $200 to $500 or more. I would sell this at &lt;strong&gt;$49 a month&lt;/strong&gt;, flat.&lt;br&gt;
The math section below explains why flat is even possible: when the&lt;br&gt;
brain and the voice run on hardware the shop already owns, there is no&lt;br&gt;
per-minute meter running to pass along.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/9rvh89mGnDY" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The video above is two real calls, recorded live in the simulator: a&lt;br&gt;
no-heat call with a baby in the house at the HVAC shop, and a burst&lt;br&gt;
pipe at the plumbing shop. Both are answered by the local model and&lt;br&gt;
spoken by the local voice, and each ends on its owner summary card.&lt;br&gt;
Nothing in it is a mock-up: the frames are the actual page during the&lt;br&gt;
calls, and the audio is the exact speech the desk generated for those&lt;br&gt;
replies.&lt;/p&gt;



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

&lt;p&gt;A call in progress: the desk holding the conversation and asking for&lt;br&gt;
the details it needs.&lt;/p&gt;



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

&lt;p&gt;The second demo shop, Riverbend Plumbing &amp;amp; Drain, in the same&lt;br&gt;
simulator. A shop is one JSON profile: its own services, prices,&lt;br&gt;
service area, and definition of emergency. Retooling the desk for a&lt;br&gt;
different trade is editing that file, not retraining anything.&lt;/p&gt;



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

&lt;p&gt;Owner review, the morning list: every finished call lands here,&lt;br&gt;
flagged by urgency, before the owner's first coffee. This list is&lt;br&gt;
the surface the whole product exists to produce.&lt;/p&gt;



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

&lt;p&gt;And the card itself, from a real call driven through this same page:&lt;br&gt;
name, callback number, job, urgency, address, and what the caller&lt;br&gt;
asked for, extracted by the same local model at hang-up. The desk's&lt;br&gt;
closing readback sits above it, and the call is already filed in the&lt;br&gt;
morning list below it.&lt;/p&gt;

&lt;p&gt;Everything in the repo's &lt;code&gt;demo-evidence/&lt;/code&gt; folder is from real runs:&lt;br&gt;
the video and its caption file, the screenshots, a full recorded call&lt;br&gt;
(&lt;code&gt;sample-call.wav&lt;/code&gt;) with its transcript, the before and after voice&lt;br&gt;
clips from the tuning sweep described below, and the eval outputs in&lt;br&gt;
&lt;code&gt;eval/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I also put up a &lt;a href="https://littlestjames82-sys.github.io/after-hours-front-desk/docs/" rel="noopener noreferrer"&gt;demo page&lt;/a&gt;&lt;br&gt;
that gathers the video, the screenshots, and the eval table in one&lt;br&gt;
place. Be clear about what it is: a page of recorded evidence, not&lt;br&gt;
the desk running live. The desk itself only runs locally, on purpose:&lt;br&gt;
a customer's details should not have to leave the building to get a&lt;br&gt;
call answered. To run the real thing, follow the README's Run section&lt;br&gt;
(a worked example, with the exact paths from my machine), start&lt;br&gt;
&lt;code&gt;desk/server.py&lt;/code&gt;, and press Call.&lt;/p&gt;
&lt;h2&gt;
  
  
  The eval: 20 scripted calls the desk had never seen
&lt;/h2&gt;

&lt;p&gt;A demo call proves a demo works. So after the build, I wrote 20&lt;br&gt;
scripted caller scenarios and ran them against the finished desk&lt;br&gt;
through its real API, scoring what came back field by field:&lt;br&gt;
emergencies, urgent jobs, and routine work across both demo shops,&lt;br&gt;
each judged by that shop's own written definition of emergency, plus&lt;br&gt;
edge cases (a vague caller, a prank call, a caller who refuses to give&lt;br&gt;
a number or an address, a caller outside the service area).&lt;/p&gt;

&lt;p&gt;The desk was not tuned against these scenarios first. They were run&lt;br&gt;
once each, as written. Full data, transcripts, and timings are in&lt;br&gt;
&lt;code&gt;eval/RESULTS.md&lt;/code&gt; and &lt;code&gt;eval/results.json&lt;/code&gt; in the repo.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Measure&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Urgency judged right&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;19 of 20 (95%)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Emergencies flagged as emergencies&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8 of 8&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extraction fields right (name, phone, address, job)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;79 of 80&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scenarios completely right&lt;/td&gt;
&lt;td&gt;18 of 20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Details invented that the caller never gave&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The two failures, named on purpose:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;An over-triage.&lt;/strong&gt; A caller reported a water heater leaking across
a garage floor, puddle growing, and said tomorrow morning was fine.
The shop's card reserves "emergency" for a leak flooding the home,
so the expected answer was urgent. The extractor read "active leak,
growing puddle" and flagged emergency. Every other field was exact.
It fails toward sending help faster, but it is a miss, and it is
reported as one. The likely fix is one sentence of extraction
guidance about contained leaks. I have deliberately not applied it:
retuning after seeing the test would make the 19 of 20 mean less.
The fix is written down in the eval report as future work, with
this failure next to it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The prank call.&lt;/strong&gt; A caller opened with the "is your refrigerator
running" joke, then apologized and said nobody needed anything. The
extractor still had to fill the card, and it wrote job:
"Refrigerator." Urgency (routine) and the withheld fields (correctly
"not given") were right. A better desk files a joke call as no job
at all. Today it files the joke.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What the edge cases proved matters more to me than the headline&lt;br&gt;
number. Across the vague caller, the refusal, and the prank, withheld&lt;br&gt;
names, numbers, and addresses came back "not given" every single time.&lt;br&gt;
Nothing was invented. That specific failure, a model making up an&lt;br&gt;
address, is what got the smaller model fired from this project (see&lt;br&gt;
the Gemma comparison below). And on the call where the caller smelled&lt;br&gt;
gas, the desk's first reply was: "Oh no, I'm sorry to hear that.&lt;br&gt;
Please leave the house immediately and call 911." Safety advice first,&lt;br&gt;
intake questions second. That ordering is in the shop card, and the&lt;br&gt;
eval caught it working in conversation, not just written in a prompt.&lt;/p&gt;

&lt;p&gt;On speed, I will only claim what I measured: on my 2-core build box, a&lt;br&gt;
desk turn end to end (brain plus voice) took a median of about 24&lt;br&gt;
seconds, and the summary card about 54 seconds after hang-up. Sandbox&lt;br&gt;
numbers, not a production promise. The speech ran 1 to 12 seconds per&lt;br&gt;
reply.&lt;/p&gt;
&lt;h2&gt;
  
  
  The math: why $49 flat is not a fantasy price
&lt;/h2&gt;

&lt;p&gt;I measured what one call actually costs this system, on the record,&lt;br&gt;
with the real shop prompt loaded:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each desk turn processes roughly 800 to 900 tokens, and nearly all of
it is the shop card system prompt. llama.cpp caches that prefix, so
after the first turn of a call, most of it is served from cache (on
the second turn I measured, 768 of 831 prompt tokens were cache
hits). The model only generates about 20 tokens per spoken reply.&lt;/li&gt;
&lt;li&gt;A full call, greeting plus three turns plus the summary extraction,
comes to roughly 4,500 tokens total.&lt;/li&gt;
&lt;li&gt;The API bill for those tokens is $0. There is no API.&lt;/li&gt;
&lt;li&gt;The electricity is the only meter running: even charging a 65-watt
laptop for a whole 3-minute call at $0.15 per kilowatt-hour works out
to about a twentieth of a cent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the marginal cost of call number 500 is the same as call number 1:&lt;br&gt;
effectively nothing. That is what makes a flat $49 a month honest.&lt;br&gt;
Per-minute cloud pricing has to charge for the meter; this design does&lt;br&gt;
not have one. And the privacy story (customer details never leave the&lt;br&gt;
building) falls out of the same architecture instead of being a policy&lt;br&gt;
someone has to trust.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/littlestjames82-sys/after-hours-front-desk" rel="noopener noreferrer"&gt;https://github.com/littlestjames82-sys/after-hours-front-desk&lt;/a&gt;&lt;br&gt;
(MIT)&lt;/p&gt;

&lt;p&gt;The pieces worth reading: &lt;code&gt;desk/prompts.py&lt;/code&gt; (the system prompt is&lt;br&gt;
generated from a one-page shop card, including the shop's own&lt;br&gt;
definition of emergency and its safety rules), &lt;code&gt;desk/speech.py&lt;/code&gt; (the&lt;br&gt;
speech-prep pass every reply goes through), &lt;code&gt;desk/shops/&lt;/code&gt; (each&lt;br&gt;
business is one JSON profile), &lt;code&gt;eval/&lt;/code&gt; (the 20-scenario harness and&lt;br&gt;
its full results), and &lt;code&gt;smoke_test.py&lt;/code&gt; (a headless end-to-end check&lt;br&gt;
that plays a scripted call and verifies every field of the summary&lt;br&gt;
card; 8 of 8 on the final code).&lt;/p&gt;
&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;The whole call path, on one machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;caller (typed, simulator) --&amp;gt; desk/server.py --&amp;gt; llama.cpp + Gemma 3 4B
                                    |              conversation, triage,
                                    |              safety rules
                                    +----------&amp;gt; Sopro V2 Turbo
                                    |              spoken replies
                                    '--&amp;gt; at hang-up: Gemma extracts
                                         the owner summary card
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Brain:&lt;/strong&gt; Gemma 3 4B-it (Q4_K_M GGUF) served by llama.cpp on&lt;br&gt;
localhost. The desk may only speak from the shop card: services, area,&lt;br&gt;
prices, hours, and the emergency definition. If a caller asks for&lt;br&gt;
something outside the card, the desk takes a message instead of&lt;br&gt;
improvising.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Gemma choice was empirical.&lt;/strong&gt; I started with the 1B to keep&lt;br&gt;
things light. It did not survive contact with the test call:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Same test call, two models&lt;/th&gt;
&lt;th&gt;Gemma 3 1B&lt;/th&gt;
&lt;th&gt;Gemma 3 4B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;No heat + baby, shop defines it as emergency&lt;/td&gt;
&lt;td&gt;Judged "urgent" in 2 of 3 runs&lt;/td&gt;
&lt;td&gt;Judged emergency, every run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Address the caller never gave&lt;/td&gt;
&lt;td&gt;Invented "123 Maple Street"&lt;/td&gt;
&lt;td&gt;"not given"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job extraction on an early run&lt;/td&gt;
&lt;td&gt;Wrote "customer"&lt;/td&gt;
&lt;td&gt;"Heat quit"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20-scenario held-out eval&lt;/td&gt;
&lt;td&gt;Not run; it had already failed selection&lt;/td&gt;
&lt;td&gt;19/20 urgency, 79/80 fields&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 4B is slower on my little build box. It is also the difference&lt;br&gt;
between a demo and something a shop could trust at 7 PM. A front desk&lt;br&gt;
that occasionally invents an address is a liability with a phone&lt;br&gt;
number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Voice:&lt;/strong&gt; Sopro V2 Turbo, open-weights voice cloning that runs on CPU,&lt;br&gt;
kept resident as a local service so replies do not pay a model load&lt;br&gt;
each time. The demo voice is a bundled synthetic profile, labeled as&lt;br&gt;
such everywhere it appears.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The robot was not in the voice.&lt;/strong&gt; My first demo sounded like a&lt;br&gt;
voicemail system from 2009, so I went looking for an expressiveness&lt;br&gt;
knob, and Sopro does not have one: no rate, no pitch, just sampling&lt;br&gt;
controls and a step count for how much each sound gets refined. So I&lt;br&gt;
measured instead of guessing. A fixed-seed sweep (write-up and before&lt;br&gt;
and after clips in &lt;code&gt;demo-evidence/voice-ab/&lt;/code&gt;) showed more refinement&lt;br&gt;
steps made the same words smoother with zero behavioral risk, and&lt;br&gt;
warmer sampling gave the readbacks room to breathe. But the bigger fix&lt;br&gt;
was the script: the brain was writing for a screen. Now it writes for&lt;br&gt;
a mouth: contractions, short sentences, "Got it." and "Oh no, I'm&lt;br&gt;
sorry to hear that.", and a speech-prep pass that turns phone numbers&lt;br&gt;
into grouped spoken digits and prices into words before anything is&lt;br&gt;
spoken. The transcript and the summary card keep the original text;&lt;br&gt;
only the spoken form is shaped.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shops are data.&lt;/strong&gt; Each business is one JSON profile: name, services,&lt;br&gt;
prices, area, emergency definition, demo scenarios. Onboarding a real&lt;br&gt;
trade is editing a file, not retraining anything. Finished calls&lt;br&gt;
append to a local call log behind the morning list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Because this product exists only where open licenses let it.&lt;/p&gt;

&lt;p&gt;The first voice engine I adopted for paid studio work shipped its&lt;br&gt;
weights under a non-commercial license. Good engine, and completely&lt;br&gt;
unusable for a receptionist somebody pays for. That is the kind of&lt;br&gt;
detail that kills a side hustle quietly, after the demo already works.&lt;br&gt;
I switched to &lt;strong&gt;Sopro&lt;/strong&gt; (Apache-2.0), a small voice-cloning model that&lt;br&gt;
runs on a plain CPU, and the $49 price became legal to charge. Gemma's&lt;br&gt;
weights, llama.cpp (MIT), Sopro (Apache-2.0): every layer of this stack&lt;br&gt;
is something a one-person studio can build a business on without&lt;br&gt;
asking permission or paying a toll per call. The openness is not a&lt;br&gt;
philosophy section in this post. It is the bill of materials.&lt;/p&gt;

&lt;p&gt;It also changes who gets to have this. A per-minute cloud receptionist&lt;br&gt;
is priced for businesses that already have margin. A local one, on a&lt;br&gt;
laptop the shop owns, is priced for a two-truck shop in rural&lt;br&gt;
Tennessee. Open weights are why that second product can exist at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A first real pilot shop.&lt;/strong&gt; The honest status is that no shop is
using this yet, and the next step is not more features. It is
finding one trade business I already work with to run it as a pilot
and tell me what the morning list gets wrong. That search is the
work now, and I would rather say so than dress up a demo as
traction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consent-first voice setup:&lt;/strong&gt; the owner records a short script;
that clip, and only that clip, becomes their front desk's voice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The phone bridge:&lt;/strong&gt; answer the real line after hours, local
speech-to-text on the caller side, same brain, same voice, same
card. Plus the contained-leak extraction fix the eval found,
verified against fresh scenarios rather than the ones that exposed
it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The code is MIT and the demo runs on any machine with a few spare&lt;br&gt;
cores. If you run a small shop: what does a missed 7 PM call cost you?&lt;/p&gt;

&lt;p&gt;Ryan Cotten, Ghost Developer Studio, Oakdale, TN&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: this project and this post were built with an AI coding&lt;br&gt;
assistant, which the challenge FAQ expressly allows. Every result&lt;br&gt;
quoted above is from runs on my machine, and the failures are reported&lt;br&gt;
the same way as the passes.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;This project was designed, built, and tested with an AI coding&lt;br&gt;
assistant working in my studio environment. The shop-card prompt&lt;br&gt;
system, the speech-prep pass, the measured voice tuning sweep, the&lt;br&gt;
20-scenario eval harness, and this post all came out of that&lt;br&gt;
workflow, and the two eval failures above were caught and written&lt;br&gt;
down inside it. I am not linking a hosted session replay: the&lt;br&gt;
environment I build in keeps its sessions local, and I would rather&lt;br&gt;
say that plainly than dress up a transcript export as one. The repo&lt;br&gt;
is the record instead: the eval harness and its raw results, the&lt;br&gt;
voice A/B notes, and the build reports are all in it, in the open.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Best Use of Gemma&lt;/strong&gt;: Gemma 3 4B-it, running locally via llama.cpp, is&lt;br&gt;
the desk's entire brain. It holds the spoken conversation, follows the&lt;br&gt;
shop card's triage and safety rules, and extracts the owner summary&lt;br&gt;
card. The choice was measured, not assumed: the 1B mis-triaged the&lt;br&gt;
emergency test call and invented an address; the 4B passed the same&lt;br&gt;
call, then scored 19 of 20 on urgency and 79 of 80 on extraction&lt;br&gt;
across 20 held-out scripted scenarios. Gemma is not a component in&lt;br&gt;
this build. It is the employee.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>hacktoberfest</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
