<?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: dongwei-polyred</title>
    <description>The latest articles on DEV Community by dongwei-polyred (@dongweipolyred).</description>
    <link>https://dev.to/dongweipolyred</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%2F4185752%2F445af629-c2b3-4d73-b5f5-d768b05a0492.png</url>
      <title>DEV Community: dongwei-polyred</title>
      <link>https://dev.to/dongweipolyred</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dongweipolyred"/>
    <language>en</language>
    <item>
      <title>FollowUp Local: a Gemma model on your laptop that tells you why the customer went quiet</title>
      <dc:creator>dongwei-polyred</dc:creator>
      <pubDate>Thu, 15 Oct 2026 02:49:30 +0000</pubDate>
      <link>https://dev.to/dongweipolyred/followup-local-a-gemma-model-on-your-laptop-that-tells-you-why-the-customer-went-quiet-154k</link>
      <guid>https://dev.to/dongweipolyred/followup-local-a-gemma-model-on-your-laptop-that-tells-you-why-the-customer-went-quiet-154k</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;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Most small sales don't die with a "no". They die with "let me check with her and get back to you", and then nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FollowUp Local&lt;/strong&gt; is a small tool for people who sell through chat: someone making candles and taking orders over Instagram DMs, a bike mechanic booking repairs on WhatsApp, a private tutor talking to parents on WeChat. You paste the conversation, and a Gemma model running on your own machine tells you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;where the customer is stuck&lt;/strong&gt;: one of eight stages, such as &lt;code&gt;waiting_on_someone_else&lt;/code&gt;, &lt;code&gt;price_hesitation&lt;/code&gt;, &lt;code&gt;comparing_options&lt;/code&gt;, &lt;code&gt;gone_quiet&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;the real concern&lt;/strong&gt; behind their words, which is often not what they literally said&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;one line of evidence&lt;/strong&gt;, quoted from the customer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;the next message to send&lt;/strong&gt;, and when to send it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what it said about a (fictional) wedding-favour order that stalled:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Stage:&lt;/strong&gt; waiting_on_someone_else&lt;br&gt;
&lt;strong&gt;Stuck on:&lt;/strong&gt; She needs her fiancÃ©e to approve the sample.&lt;br&gt;
&lt;strong&gt;Real concern:&lt;/strong&gt; She's seeking reassurance about the label quality and wants to see it before committing to a larger order.&lt;br&gt;
&lt;strong&gt;Evidence:&lt;/strong&gt; "Let me check with her and get back to you"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Earlier in that chat the customer had mentioned seeing labels "that peeled off in photos". The model connected that to the stall, and that is the part I actually care about. "Follow up in 2 days" is easy. Spotting that the hesitation is really about the sticker is the useful bit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who would pay for it?&lt;/strong&gt; Solo sellers and tiny shops whose income depends on a few dozen open conversations at a time. A tutor who turns one extra "I'll ask my husband" into a booking gets paid back for a year of a small subscription. I think there are two realistic ways to sell it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;strong&gt;one-time paid download&lt;/strong&gt;, a packaged desktop app with the model bundled, for people who will never open a terminal.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;niche version for one trade&lt;/strong&gt;, such as tutoring centres or wedding vendors, with stage names, signals and example replies tuned to how that trade's customers actually hesitate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because inference runs on the customer's own hardware, each extra user costs me nothing to serve. That is what makes a cheap price workable at all (more on that below).&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;A real, unedited 32-second run on a CPU-only Linux box with no GPU. Paste a chat, click once, and gemma3:4b answers in about 19 seconds:&lt;/p&gt;

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

&lt;p&gt;The CLI does the same thing for people who prefer a terminal:&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%2Fyquqz53iatoyz2pb2sut.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%2Fyquqz53iatoyz2pb2sut.png" alt="CLI output" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It also handles Chinese chats. For the bundled tutoring sample, where a parent says the price is "æœ‰ç‚¹è´µ" (a bit expensive) and that she'll ask the child's father, it labels the stage &lt;code&gt;price_hesitation&lt;/code&gt;, picks up that a previous course "didn't work", and drafts a reply in Chinese that leads with the free diagnostic trial lesson.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dongwei-polyred" rel="noopener noreferrer"&gt;
        dongwei-polyred
      &lt;/a&gt; / &lt;a href="https://github.com/dongwei-polyred/followup-local" rel="noopener noreferrer"&gt;
        followup-local
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Paste a customer chat, a local Gemma model (Ollama) tells you where they're stuck and writes the next follow-up. Nothing leaves your machine.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;FollowUp Local&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Paste a customer chat. A &lt;strong&gt;Gemma&lt;/strong&gt; model running on your own computer (via &lt;a href="https://ollama.com" rel="nofollow noopener noreferrer"&gt;Ollama&lt;/a&gt;) tells you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;where the customer is stuck&lt;/strong&gt; (&lt;code&gt;waiting_on_someone_else&lt;/code&gt;, &lt;code&gt;price_hesitation&lt;/code&gt;, &lt;code&gt;gone_quiet&lt;/code&gt;, ...)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;the real concern&lt;/strong&gt; behind what they said&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;one line of evidence&lt;/strong&gt; quoted from the chat&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;the next message to send&lt;/strong&gt;, and when to send it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nothing leaves your machine. No API key, no account, no per-message cost.&lt;/p&gt;
&lt;p&gt;Built for the DEV Hacktoberfest 2026 Open-Source AI Challenge, Week 2 ("Side Hustle"), between Oct 12 and Oct 18, 2026.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/dongwei-polyred/followup-local/docs/followup-local-demo.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fdongwei-polyred%2Ffollowup-local%2FHEAD%2Fdocs%2Ffollowup-local-demo.gif" alt="demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Who it is for&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;People who sell through chat and lose deals to silence: a candle maker on Instagram DMs, a bike mechanic on WhatsApp, a private tutor on WeChat
Their customer chats are private, and they don't want to paste them into a cloud chatbot.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick start&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Requirements: Python 3.9+ (standard library only) and Ollama.&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;ollama pull gemma3:4b          &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/dongwei-polyred/followup-local" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;One Python file using only the standard library, plus three fictional sample chats and their real outputs. MIT licensed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull gemma3:4b
python3 followup.py samples/candle_shop_sample.txt   &lt;span class="c"&gt;# CLI&lt;/span&gt;
python3 followup.py &lt;span class="nt"&gt;--serve&lt;/span&gt;                          &lt;span class="c"&gt;# web UI on :8765&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Model: Gemma 3 through Ollama.&lt;/strong&gt; I tried two sizes on the same CPU-only machine (8 vCPUs, no GPU):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;model&lt;/th&gt;
&lt;th&gt;time per chat&lt;/th&gt;
&lt;th&gt;what I saw&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gemma3:1b&lt;/td&gt;
&lt;td&gt;~6â€“9 s&lt;/td&gt;
&lt;td&gt;Often labelled everything &lt;code&gt;asking_questions&lt;/code&gt;, and its messages were generic ("Would you like me to send a picture?")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gemma3:4b&lt;/td&gt;
&lt;td&gt;~15â€“24 s&lt;/td&gt;
&lt;td&gt;Picked sensible stages, reused the seller's own facts ($8 sample, refunded on order), and answered Chinese chats in Chinese&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;4B is the default. 1B is still available through &lt;code&gt;FOLLOWUP_MODEL=gemma3:1b&lt;/code&gt; for older laptops.&lt;/p&gt;

&lt;p&gt;Four things made a small local model usable for this. None of them is clever on its own:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Structured output instead of hoping for JSON.&lt;/strong&gt; Ollama's &lt;code&gt;format&lt;/code&gt; field takes a JSON schema. I give it the six fields and an &lt;code&gt;enum&lt;/code&gt; of the eight stages, so the model can't invent a stage or return half a sentence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One worked example.&lt;/strong&gt; A three-line example chat ("My partner handles the budget, I'll ask him") with the ideal answer did more for quality than any extra instructions I tried.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyword signals as hints, not rules.&lt;/strong&gt; A tiny pass looks for phrases in the customer's lines only: "check with", "my wife", "é—®é—®", "said $", "think about it". It passes them to Gemma as &lt;code&gt;HINT: waiting_on_someone_else, gone_quiet&lt;/code&gt;. With the hint, the 1B model went from always answering &lt;code&gt;asking_questions&lt;/code&gt; to usually picking the right stage. The 4B model sometimes disagrees with the hint, and that's intended: in the bike-repair chat the hints say three different things, and the model correctly settles on &lt;code&gt;price_hesitation&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checking the model's quote.&lt;/strong&gt; The model is asked to copy one customer line as evidence. If the quote it returns isn't actually in the chat, I replace it with the last real customer line. Small models paraphrase, and a made-up quote is worse than none.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The prompt also tells the model to mention only prices and services the seller has already stated, to end with one easy yes/no question, and to avoid fake urgency or new discounts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What still goes wrong.&lt;/strong&gt; I'd rather be upfront about this, because it's the reason there's no "send" button. In my test runs the 4B model sometimes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;claimed an action that hadn't happened ("I've just sent a photo of the sticker")&lt;/li&gt;
&lt;li&gt;added a comparison the seller never made ("things the other shop doesn't offer")&lt;/li&gt;
&lt;li&gt;got a relationship wrong in Chinese, writing "your dad" where it meant "the child's father"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So FollowUp Local writes a draft for a person to read. It doesn't send anything for you. For something going out under a small business owner's name, I think that's the right design anyway.&lt;/p&gt;

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

&lt;p&gt;For this particular tool, open weights are what make it possible in the first place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The data is the most private thing a small seller has.&lt;/strong&gt; A chat log holds customers' names, budgets, family situations, and sometimes addresses. "Paste your customers' WhatsApps into our cloud" is a hard sell, and it may not even be the seller's to share. With Gemma running locally, the chat never leaves the laptop. The UI says so, and you can check it by unplugging the network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The economics work at a small-business price.&lt;/strong&gt; The value of each analysis is real but small, and a seller may run dozens a day. With a hosted API every analysis costs me money, so I'd have to charge per message or as a subscription. Locally, the marginal cost is zero, so a one-time price is possible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model size is a dial I control.&lt;/strong&gt; Because the weights are open, I can choose 1B for an old laptop or 4B for better answers. And the "niche version" idea from above is really a fine-tuning project: a Gemma tuned on one trade's (consented) conversations. That's something you can do with open weights and can't do with a closed endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No lock-in for the seller.&lt;/strong&gt; If I stop maintaining this, the tool and the model still run on their machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A closed frontier model would probably write slightly nicer follow-ups. But for this user, the privacy and cost arguments matter more than the last bit of polish.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt;: Gemma 3 (4B, with 1B as a lighter option) runs locally through Ollama and is the core of the product. It does the stage classification, the concern analysis and the bilingual message drafting, using schema-constrained JSON output.&lt;/li&gt;
&lt;/ul&gt;

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