<?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: Waleed Shamhan</title>
    <description>The latest articles on DEV Community by Waleed Shamhan (@waleedshamhan2050sys).</description>
    <link>https://dev.to/waleedshamhan2050sys</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%2F4044503%2F21d445ad-a539-425a-9c8d-2fb0458d3466.jpg</url>
      <title>DEV Community: Waleed Shamhan</title>
      <link>https://dev.to/waleedshamhan2050sys</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/waleedshamhan2050sys"/>
    <language>en</language>
    <item>
      <title>Ghost in the Machine: Necromancing Dead Codebases Locally with Gemma 3 &amp; Ollama</title>
      <dc:creator>Waleed Shamhan</dc:creator>
      <pubDate>Thu, 29 Oct 2026 23:50:31 +0000</pubDate>
      <link>https://dev.to/waleedshamhan2050sys/ghost-in-the-machine-necromancing-dead-codebases-locally-with-gemma-3-ollama-c9p</link>
      <guid>https://dev.to/waleedshamhan2050sys/ghost-in-the-machine-necromancing-dead-codebases-locally-with-gemma-3-ollama-c9p</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week4-2026-10-26"&gt;Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; this project was built with AI assistance — a local Gemma 3 model performed the code autopsy and drafted rewrites through Ollama, and a human verified every finding, rejected the invented ones, and wrote the tests. No cloud AI service was used.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Ghost in the Machine: Necromancing Dead Codebases Locally with Gemma 3 &amp;amp; Ollama
&lt;/h1&gt;

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

&lt;p&gt;Every developer’s GitHub profile is a graveyard. We've all got legacy repositories—abandoned scripts, forgotten utilities, and stale experiments written years ago that now sit gathering digital dust. For this year’s Hacktoberfest (&lt;em&gt;Ghost in the Machine&lt;/em&gt; challenge), instead of building a trivial app, I decided to build something that resurrects the dead: &lt;strong&gt;The Legacy Code Necromancer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s a local-first, zero-dependency CLI tool built in pure Python that uses &lt;strong&gt;Gemma 3 via Ollama&lt;/strong&gt; to perform an autopsy on dead code, refactor it safely, and generate a haunted markdown audit report.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture: Privacy-First Code Necromancy
&lt;/h2&gt;

&lt;p&gt;When you're dealing with legacy code, the biggest fear is leaking hardcoded API keys, database credentials, or sensitive secrets to cloud LLMs. That's why &lt;em&gt;The Legacy Code Necromancer&lt;/em&gt; was built with strict constraints:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Local Loopback Only:&lt;/strong&gt; It communicates strictly with &lt;code&gt;127.0.0.1&lt;/code&gt; where Ollama runs. Any remote server connection is strictly rejected unless explicitly authorized.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret Scrubber:&lt;/strong&gt; Before a single line of code is sent to Gemma 3, a built-in regex scrubber purges any potential keys, tokens, or sensitive strings, leaving the structural vulnerabilities (&lt;code&gt;eval&lt;/code&gt;, &lt;code&gt;pickle&lt;/code&gt;, etc.) exposed for analysis.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Three Engines of the Necromancer
&lt;/h2&gt;

&lt;p&gt;The tool runs three distinct phases against any legacy directory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 1: Code Autopsy:&lt;/strong&gt; Scans the file tree (safely ignoring &lt;code&gt;.git&lt;/code&gt;, &lt;code&gt;node_modules&lt;/code&gt;, and binaries) and produces structured findings as JSON — severity, category, file path, and line — rendered into the Markdown report.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phase 2: Revival &amp;amp; Patching:&lt;/strong&gt; Refactors the haunted code into a clean, modern, testable structure (with syntax verification for Python targets).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phase 3: The Haunted Audit Report:&lt;/strong&gt; Generates a chilling, Halloween-themed Markdown report detailing the cause of death and the resurrection steps, complete with a persistent JSON session manifest (&lt;code&gt;.necromancer-manifest.json&lt;/code&gt;) to resume work without duplication.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Recorded Séance — what actually happened
&lt;/h2&gt;

&lt;p&gt;No claims without evidence. On 30 October 2026 I ran the tool over the included haunted sample (two Python files, 57 lines, fake credentials planted deliberately) with &lt;code&gt;gemma3:1b&lt;/code&gt; running locally on CPU through Ollama. The run took &lt;strong&gt;404 seconds, 5 model calls, 16,388 characters sent, 18,208 received&lt;/strong&gt; — and every raw reply is preserved.&lt;/p&gt;

&lt;p&gt;The autopsy returned &lt;strong&gt;15 findings. Human review confirmed 8&lt;/strong&gt; — including every planted critical flaw: the hardcoded credentials, &lt;code&gt;eval&lt;/code&gt;, &lt;code&gt;pickle&lt;/code&gt; deserialization, shell injection, SQL string interpolation, MD5 password hashing, and the removed &lt;code&gt;time.clock&lt;/code&gt; / &lt;code&gt;collections.Mapping&lt;/code&gt; APIs. &lt;strong&gt;The other 7 were invented or mislabeled&lt;/strong&gt; — a "race condition" in single-threaded code, a "hardcoded credential" in a file that has none, "missing retries/backoff" for local file code — and the model's line numbers were guesses, not real line numbers. I rejected those, and the report says so.&lt;/p&gt;

&lt;p&gt;The rewrite pass was the honest disappointment of the run: the small model's drafts &lt;strong&gt;echoed the redacted input verbatim&lt;/strong&gt; — &lt;code&gt;eval&lt;/code&gt;, &lt;code&gt;pickle&lt;/code&gt;, SQL interpolation, MD5 and &lt;code&gt;time.clock&lt;/code&gt; all survived. "Verified" in the report means only "compiles". Those drafts are not safe to run, and the report's "Cause of Death" prose (which invents a 2023 date and fixes that never happened) is preserved as evidence of what a small local model produces — not as documentation. The full annotated report, with a human curator's note on top, is in the repository at &lt;code&gt;docs/example-haunted-audit-report.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is the real story: the autopsy is strong, the curation is the product, and the audit trail is what makes it trustworthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Gemma 3?
&lt;/h2&gt;

&lt;p&gt;The recorded run used &lt;code&gt;gemma3:1b&lt;/code&gt; (806 MB) because this machine is RAM-constrained — and it delivered exactly the balance I needed for the autopsy: fast enough on CPU, with enough structural reasoning to understand chaotic, unmaintained legacy code, without sacrificing a single byte of code privacy. The tool accepts any local Gemma 3 tag; the 4B &lt;code&gt;gemma3&lt;/code&gt; is supported and is the recommended next run for stronger rewrites (untested on this machine).&lt;/p&gt;

&lt;h2&gt;
  
  
  Try the Haunted Sample Yourself
&lt;/h2&gt;

&lt;p&gt;Clone the repository, feed it the included haunted sample directory containing fake secrets and old bugs, and watch the necromancy unfold locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama serve
ollama pull gemma3:1b

python3 necromancer.py fixtures/haunted-legacy &lt;span class="nt"&gt;--model&lt;/span&gt; gemma3:1b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Demo — the recorded séance
&lt;/h2&gt;

&lt;p&gt;This is the real console output of the run recorded on 30 October 2026, on CPU, against the included haunted sample:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exhumed 2 file(s), 15 finding(s), 2 resurrected, 0 failed.
Report: necromancer-out/haunted-audit-report.md
Revived code: necromancer-out/revived
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;What the generated report recorded (verbatim vitals):&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;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Source files examined&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total lines&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secret lines redacted before prompting&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Findings&lt;/td&gt;
&lt;td&gt;15 (4 Critical · 4 High · 4 Medium · 3 Low)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Files resurrected&lt;/td&gt;
&lt;td&gt;2 (drafts compile; curator review found they echo the input — see below)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A sample of the confirmed findings: hardcoded credential (Critical), &lt;code&gt;eval()&lt;/code&gt; code execution, &lt;code&gt;pickle&lt;/code&gt; deserialization, SQL string interpolation, MD5 password hashing, and the removed &lt;code&gt;time.clock&lt;/code&gt; API. The full annotated report, with the human curator's note on what the model invented and what the rewrite drafts failed to fix, is in the repository at &lt;code&gt;docs/example-haunted-audit-report.md&lt;/code&gt;.&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/waleedshamhan2050-sys" rel="noopener noreferrer"&gt;
        waleedshamhan2050-sys
      &lt;/a&gt; / &lt;a href="https://github.com/waleedshamhan2050-sys/legacy-code-necromancer" rel="noopener noreferrer"&gt;
        legacy-code-necromancer
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Local-first CLI that autopsies abandoned code, drafts safe rewrites, and writes a haunted audit report — powered by Gemma 3 via Ollama. No cloud, no secrets leave localhost.
    &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;👻 The Legacy Code Necromancer&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hacktoberfest 2026 — "Ghost in the Machine" challenge entry, Best Use of Gemma category.&lt;/strong&gt;
A local-first CLI that dissects abandoned code, resurrects it with
&lt;strong&gt;Gemma 3 running entirely on your own machine through Ollama&lt;/strong&gt;, and
writes a haunted audit report you can verify line by line
No cloud. No API keys. No code ever leaves localhost.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every codebase has a graveyard: the utility written in 2019 that
everyone is afraid to touch, the intern's bot, the script with the
password still in it. The Necromancer does not delete the dead — it
performs an autopsy, determines the cause of death, and brings the
code back in a form that is safe to run. The ghost in the machine is
not something to fear. It is something to understand.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The pipeline — three engines, one séance&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;abandoned project ──► 1. CODE AUTOPSY ──► 2. AUTO-REFACTORING&lt;/code&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/waleedshamhan2050-sys/legacy-code-necromancer" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;p&gt;Because a closed API would have made this project impossible in the way that mattered. Abandoned code is the most personal code a developer owns — half-finished, half-secret, full of old credentials. Open-weight Gemma 3 running locally meant the autopsy never depended on a service that can disappear, change its prices, or read my code. Anyone can rerun the identical séance offline and audit every finding against the preserved raw output. A closed model gives you an answer; an open model gives you a process you can inspect. For a student on a metered connection in Yemen, that is the difference between a ghost story and a resurrection.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spirit of It
&lt;/h2&gt;

&lt;p&gt;Día de los Muertos is about honouring the dead without fearing them. This tool does the same for old code: you do not delete your past work because it is flawed. You sit with it, understand it, and bring it back better — with a local model that never judges, never leaks, and never leaves the room.&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 (via Ollama, local inference) is the engine of the entire project: autopsy, rewrite drafts, and report prose all run through the open-weight model on localhost.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
      <category>ollama</category>
    </item>
    <item>
      <title>I Launched a WhatsApp Automation Service for Small Shops — Powered by Local Open Models</title>
      <dc:creator>Waleed Shamhan</dc:creator>
      <pubDate>Tue, 20 Oct 2026 14:31:30 +0000</pubDate>
      <link>https://dev.to/waleedshamhan2050sys/i-launched-a-whatsapp-automation-service-for-small-shops-powered-by-local-open-models-lf</link>
      <guid>https://dev.to/waleedshamhan2050sys/i-launched-a-whatsapp-automation-service-for-small-shops-powered-by-local-open-models-lf</guid>
      <description>&lt;p&gt;Small shops and restaurants in my region lose customers every day for a simple reason: nobody answers WhatsApp fast enough. The owner is busy, the same questions repeat — prices, opening hours, location, "do you deliver?" — and by the time someone replies, the customer has moved on.&lt;/p&gt;

&lt;p&gt;So I built a service around a simple idea: &lt;strong&gt;an AI assistant on the shop's WhatsApp number that answers instantly, 24/7&lt;/strong&gt; — and it runs on open-weight models, locally.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Answers frequent questions (prices, hours, location, menu/services) in seconds&lt;/li&gt;
&lt;li&gt;Takes orders and notifies the owner immediately&lt;/li&gt;
&lt;li&gt;Runs on &lt;strong&gt;Gemma 3 via Ollama&lt;/strong&gt; on a local machine — no per-message API cost, and customer data stays with the business&lt;/li&gt;
&lt;li&gt;Falls back to the owner when a question is outside what it knows&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why local open models?
&lt;/h2&gt;

&lt;p&gt;Two reasons: cost and privacy. A cloud API bill grows with every conversation; a local model does not. And a small shop's customer chats never leave the shop's own hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Packages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Basic — $80:&lt;/strong&gt; FAQ auto-replies + welcome message&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced — $200:&lt;/strong&gt; + order taking + instant owner alerts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro — $500:&lt;/strong&gt; + spreadsheet logging of orders + weekly reports&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Service page: &lt;a href="https://github.com/waleedshamhan2050-sys/AI-Post-Generator/blob/master/SERVICE.md" rel="noopener noreferrer"&gt;https://github.com/waleedshamhan2050-sys/AI-Post-Generator/blob/master/SERVICE.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live site: &lt;a href="https://whatsapp-automation-service-waleedshamhan2050-4299.vercel.app" rel="noopener noreferrer"&gt;https://whatsapp-automation-service-waleedshamhan2050-4299.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This grew out of my earlier project, an AI post generator for WhatsApp and Telegram channels — the same stack (Python + Ollama + Gemma 3), aimed at a different job: not creating content, but answering customers.&lt;/p&gt;

&lt;p&gt;If you run a small business and drown in repeated WhatsApp questions, I'd love your feedback: what are the five questions your customers ask the most?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>whatsapp</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>I Built a Local Agent That Reads My Chats Overnight and Writes My Morning Digest (Gemma 3 + Ollama)</title>
      <dc:creator>Waleed Shamhan</dc:creator>
      <pubDate>Tue, 20 Oct 2026 12:59:43 +0000</pubDate>
      <link>https://dev.to/waleedshamhan2050sys/i-built-a-local-agent-that-reads-my-chats-overnight-and-writes-my-morning-digest-gemma-3-ollama-11ne</link>
      <guid>https://dev.to/waleedshamhan2050sys/i-built-a-local-agent-that-reads-my-chats-overnight-and-writes-my-morning-digest-gemma-3-ollama-11ne</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Every morning used to start the same way: me, half awake, scrolling through hundreds of unread messages across my group chats — a study group, a project team, friends — trying to figure out what I actually missed while I slept. A lecture moved. A deadline confirmed. A decision made without me. All buried under memes and "good morning" stickers.&lt;/p&gt;

&lt;p&gt;So for &lt;strong&gt;Slow and Steady&lt;/strong&gt;, I built the laziest possible solution: &lt;strong&gt;Morning Digest&lt;/strong&gt;, a small local agent that does the scrolling for me.&lt;/p&gt;

&lt;p&gt;It takes a Telegram Desktop export (or a plain-text chat log), looks at the last 12 hours of messages, and produces a short Arabic morning digest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;headline&lt;/strong&gt; of at most two lines,&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;key topics&lt;/strong&gt; as bullets,&lt;/li&gt;
&lt;li&gt;and any &lt;strong&gt;decisions or action items&lt;/strong&gt;, if there were any.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wake up, run one command, and read for 30 seconds instead of scrolling for 15 minutes. That's the whole product: my future, better-rested self gets to be a little lazier — on International Sloth Day and every day after. 🦥&lt;/p&gt;

&lt;p&gt;And it runs &lt;strong&gt;entirely on my own machine&lt;/strong&gt; with &lt;strong&gt;Gemma 3&lt;/strong&gt; via &lt;strong&gt;Ollama&lt;/strong&gt;. No cloud, no API key, no subscription.&lt;/p&gt;

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

&lt;p&gt;The project ships with a synthetic sample export (&lt;code&gt;sample/result.json&lt;/code&gt; — 30 fictional messages across two groups, so nobody's real chats are involved). Running:&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
python3 digest.py sample/result.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And here is the actual digest it produced from that sample (24 messages in the 12-hour window, generated locally by &lt;code&gt;gemma3&lt;/code&gt; — the full output is committed in the repo as &lt;code&gt;sample_output.md&lt;/code&gt;):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ملخص الصباح&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;تطور مشروع الهاكاثون مع التركيز على تطوير "وكيل ملخص الصباح"، بالإضافة إلى مناقشات حول جدول الأعمال والمواعيد.&lt;/p&gt;

&lt;p&gt;أهم المواضيع:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;تطوير "وكيل ملخص الصباح" باستخدام Gemma 3.&lt;/li&gt;
&lt;li&gt;إعدادات مشروع الهاكاثون (تاريخ التقديم، مراجعة المسودة، اختبار الملخص).&lt;/li&gt;
&lt;li&gt;مناقشة حول محاضرة قواعد البيانات ومحاضرة الشبكات.&lt;/li&gt;
&lt;li&gt;تذكير بواجب التشفير.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;قرارات ومهام:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;تاريخ التقديم لمشروع الهاكاثون: الخميس.&lt;/li&gt;
&lt;li&gt;مراجعة مسودة منشور DEV من قبل الجميع.&lt;/li&gt;
&lt;li&gt;إعداد عينة محادثة وهمية لاختبار الملخص (عمر خالد).&lt;/li&gt;
&lt;li&gt;إرسال ملخص محاضرة الشبكات (أحمد صالح).&lt;/li&gt;
&lt;li&gt;تعد مسودة ملف README الليلة (سارة أحمد).&lt;/li&gt;
&lt;li&gt;البدء في العمل على واجب التشفير الليلة (خالد عمر).&lt;/li&gt;
&lt;li&gt;تذكير بتسليم واجب التشفير يوم الخميس (ليلى حسن).&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every item in that list is really in the sample chats — the moved database lecture, the Thursday submission, who owes whom the network notes. Nothing was edited or touched up; that's the raw model output. On this machine's CPU the 4B model took about 5 minutes end to end; &lt;code&gt;gemma3:1b&lt;/code&gt; does the same job in under 2 minutes with a shorter, rougher digest (also committed in the repo for comparison).&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/waleedshamhan2050-sys" rel="noopener noreferrer"&gt;
        waleedshamhan2050-sys
      &lt;/a&gt; / &lt;a href="https://github.com/waleedshamhan2050-sys/morning-digest" rel="noopener noreferrer"&gt;
        morning-digest
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Morning Digest — a local agent that reads your Telegram chat exports overnight and writes a short Arabic morning digest. Gemma 3 + Ollama, fully local. Hacktoberfest 2026 Week 3: Slow and Steady.
    &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;☀️ Morning Digest — read less chat, know everything&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;A tiny local agent that reads your group chats overnight and hands you a short
Arabic morning digest: a two-line headline, the key topics, and any decisions
or action items — so you can be gloriously lazy and still miss nothing.&lt;/p&gt;
&lt;p&gt;Built for the &lt;strong&gt;Hacktoberfest Open-Source AI Challenge — Week 3: "Slow and
Steady"&lt;/strong&gt; (build something with open-weight models that rewards laziness 🦥).&lt;/p&gt;
&lt;p&gt;It runs &lt;strong&gt;100% locally&lt;/strong&gt; with &lt;strong&gt;Gemma 3&lt;/strong&gt; via &lt;strong&gt;Ollama&lt;/strong&gt;. Your chats are
private — they should never have to visit a cloud API just to be summarized.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&lt;/h2&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Export a chat from &lt;strong&gt;Telegram Desktop&lt;/strong&gt; (&lt;code&gt;Settings → Advanced → Export Telegram data&lt;/code&gt;, JSON format) — or use any plain-text chat log.&lt;/li&gt;
&lt;li&gt;Run the digest on the export. It takes the last N hours of messages
(default 12 — last night), anchored at the latest…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/waleedshamhan2050-sys/morning-digest" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The whole tool is one Python file (&lt;code&gt;digest.py&lt;/code&gt;) with a single dependency (&lt;code&gt;requests&lt;/code&gt;). The repo also includes a parser test that runs &lt;strong&gt;without&lt;/strong&gt; the model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 tests/test_parse.py   &lt;span class="c"&gt;# 5/5 passing: window filtering, entity flattening, service-message dropping, multi-chat exports, text-log parsing&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;The stack is deliberately boring — boring is what you want at 7 AM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 3&lt;/strong&gt; (Google's open-weight model family) served locally by &lt;strong&gt;Ollama&lt;/strong&gt;, called through its native HTTP API. The default model is &lt;code&gt;gemma3&lt;/code&gt; (configurable via &lt;code&gt;OLLAMA_MODEL&lt;/code&gt;); &lt;code&gt;gemma3:1b&lt;/code&gt; is there when I'm in a hurry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parsing:&lt;/strong&gt; Telegram Desktop exports message text either as a plain string or as a list of formatting entities, and pads the file with service events (joins, pins) and empty media messages. The parser flattens entities, drops the noise, and keeps a flat &lt;code&gt;{timestamp, chat, sender, text}&lt;/code&gt; list. Plain &lt;code&gt;.txt&lt;/code&gt; logs work too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time window:&lt;/strong&gt; the digest covers the last &lt;code&gt;--hours N&lt;/code&gt; (default 12), anchored at the latest message in the export — because exports are made in the morning, "recent" means the tail of the file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chunking:&lt;/strong&gt; a busy night can overflow a small model's context, so messages are split into chunks, each chunk is summarized, and then the summaries are summarized into the final digest. Two passes, no lost middle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provider pattern:&lt;/strong&gt; this reuses the pattern from my Week 2 project (AI Post Generator): Ollama by default, OpenAI as an optional &lt;code&gt;--provider&lt;/code&gt;, model chosen from the environment. One codebase, local-first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Verified locally: the agent ran end to end against &lt;strong&gt;Gemma 3 served by Ollama 0.40.6 on this machine&lt;/strong&gt; — with &lt;code&gt;gemma3&lt;/code&gt; (4B) for the digest shown above, and with &lt;code&gt;gemma3:1b&lt;/code&gt; for a faster comparison run. Both outputs are committed in the repo. The parser tests pass 5/5 without a model, and pointing the tool at a stopped Ollama server produces a friendly "start it with &lt;code&gt;ollama serve&lt;/code&gt;" error instead of a stack trace (also tested).&lt;/p&gt;

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

&lt;p&gt;This project only makes sense because the model is open-weight and the inference is local:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy is the feature.&lt;/strong&gt; A chat export is one of the most personal files on your computer. Sending it to a closed API so a stranger's server can summarize your friends' messages is a terrible trade. With Gemma 3 on my own machine, the file never leaves the laptop — the summary is computed a meter away from where the chats live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It works where I live.&lt;/strong&gt; I'm a student in Yemen. Internet cuts, no international payment card for API credits, no PayPal. A closed API makes my morning digest a luxury I literally cannot pay for. An open-weight model makes it free forever: set up once, run every day, owe nobody anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No lock-in, real ownership.&lt;/strong&gt; If a better small open model ships next month, I change one environment variable. My tool doesn't break when a provider changes pricing, deprecates a model, or suspends an account.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A closed API could summarize the chats too — but it couldn't give me &lt;em&gt;this&lt;/em&gt;: a private, offline, zero-cost habit that runs on hardware I already own. That's what open made possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;p&gt;The honest math: catching up on my groups used to take roughly &lt;strong&gt;15 minutes of scrolling&lt;/strong&gt; every morning, most of it noise. The digest takes about &lt;strong&gt;30 seconds to read&lt;/strong&gt;. Even better, I no longer have to &lt;em&gt;remember&lt;/em&gt; to check whether the database lecture moved or who promised to send the network notes — if it was said overnight, it's in the digest, under "Decisions and action items."&lt;/p&gt;

&lt;p&gt;Setup cost: one &lt;code&gt;ollama pull&lt;/code&gt; and one Python file. Daily effort since then: zero. Slow and steady, indeed.&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; — the digest is generated by Gemma 3 running locally via Ollama; the open-weight model is the core of the project, not an accessory.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Cybersecurity Roadmap #2: Computer Basics Every Security Learner Needs</title>
      <dc:creator>Waleed Shamhan</dc:creator>
      <pubDate>Fri, 16 Oct 2026 18:07:23 +0000</pubDate>
      <link>https://dev.to/waleedshamhan2050sys/cybersecurity-roadmap-2-computer-basics-every-security-learner-needs-5c24</link>
      <guid>https://dev.to/waleedshamhan2050sys/cybersecurity-roadmap-2-computer-basics-every-security-learner-needs-5c24</guid>
      <description>&lt;p&gt;This is episode 2 of my &lt;strong&gt;Cybersecurity Roadmap&lt;/strong&gt; series, where I learn cybersecurity in public. Last time: what cybersecurity is and the CIA triad. Today: the computer basics you need &lt;em&gt;before&lt;/em&gt; any hacking or defending makes sense.&lt;/p&gt;

&lt;p&gt;You cannot protect what you do not understand. So let us build the mental model.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Hardware: what actually runs your code
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CPU&lt;/strong&gt; — executes instructions. Every program, including malware, is ultimately instructions for the CPU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAM&lt;/strong&gt; — fast, temporary memory. Turn the power off and it is gone. Passwords and keys sitting in RAM can be stolen while the machine runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage (SSD/HDD)&lt;/strong&gt; — permanent memory. Deleted files are often recoverable, because "delete" usually just marks space as reusable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network card&lt;/strong&gt; — connects the machine to other machines. Every attack from the internet arrives through it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Security lesson: data in RAM is exposed while the machine runs, and "deleted" does not mean "gone".&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Operating system: the boss of the machine
&lt;/h2&gt;

&lt;p&gt;The OS (Windows, Linux, macOS) sits between programs and hardware. It decides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Which program runs when&lt;/strong&gt; (processes)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who can read or change which file&lt;/strong&gt; (permissions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which program may use the network&lt;/strong&gt; (firewall rules)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two security ideas live here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Processes:&lt;/strong&gt; every running program is a process. Malware is just a process you did not want. Task Manager (Windows) or &lt;code&gt;ps&lt;/code&gt; (Linux) shows you what is running.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Users and permissions:&lt;/strong&gt; files and programs have owners and permission levels. A normal user account cannot change system files; an administrator can. This is why you should not browse the web as administrator — any malware you run inherits your permissions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Files, extensions, and why they matter
&lt;/h2&gt;

&lt;p&gt;A file's extension hints at what it is — but it is only a hint:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.txt&lt;/code&gt;, &lt;code&gt;.pdf&lt;/code&gt;, &lt;code&gt;.jpg&lt;/code&gt; — usually data, not programs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.exe&lt;/code&gt;, &lt;code&gt;.bat&lt;/code&gt;, &lt;code&gt;.sh&lt;/code&gt; — programs that &lt;em&gt;run&lt;/em&gt; when opened&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.docx&lt;/code&gt;, &lt;code&gt;.xlsx&lt;/code&gt; — documents that can contain macros (code!) — a classic malware carrier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Security lesson: "invoice.pdf.exe" is a program, not a PDF. Windows hides extensions by default — turn "show file extensions" on. It is a five-second change that stops a whole class of tricks.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The command line is not optional
&lt;/h2&gt;

&lt;p&gt;A lot of security work happens in the terminal: checking processes, inspecting files, testing networks. You do not need to memorize everything — you need to be comfortable with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listing files and moving between folders (&lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;dir&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Reading a file (&lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;type&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Seeing what is running (&lt;code&gt;ps&lt;/code&gt;, Task Manager)&lt;/li&gt;
&lt;li&gt;Checking network connections (&lt;code&gt;netstat&lt;/code&gt;, &lt;code&gt;ss&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the command line scares you, practice ten minutes a day. It pays off in every later episode.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Updates: the most boring, most important defense
&lt;/h2&gt;

&lt;p&gt;Most successful attacks do not use genius zero-days. They use &lt;strong&gt;known vulnerabilities in unpatched software&lt;/strong&gt; — bugs the vendor already fixed. Updating your OS, browser, and apps closes those holes. Automatic updates exist for a reason: turn them on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick checklist before the next episode
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] You can explain CPU, RAM, storage, and network card in one sentence each&lt;/li&gt;
&lt;li&gt;[ ] You know what a process is and how to list running ones&lt;/li&gt;
&lt;li&gt;[ ] You know why running as administrator is risky&lt;/li&gt;
&lt;li&gt;[ ] File extensions are visible on your machine&lt;/li&gt;
&lt;li&gt;[ ] Your OS and browser are up to date&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next episode: &lt;strong&gt;Networks — how data actually moves&lt;/strong&gt;, and why that matters for attackers and defenders. Follow along, and tell me in the comments: &lt;strong&gt;Windows, Linux, or macOS — what do you learn on?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>beginners</category>
      <category>security</category>
      <category>learning</category>
    </item>
    <item>
      <title>Cybersecurity Roadmap #1: What Is Cybersecurity, Really?</title>
      <dc:creator>Waleed Shamhan</dc:creator>
      <pubDate>Fri, 16 Oct 2026 18:07:22 +0000</pubDate>
      <link>https://dev.to/waleedshamhan2050sys/cybersecurity-roadmap-1-what-is-cybersecurity-really-24oi</link>
      <guid>https://dev.to/waleedshamhan2050sys/cybersecurity-roadmap-1-what-is-cybersecurity-really-24oi</guid>
      <description>&lt;p&gt;Welcome to my &lt;strong&gt;Cybersecurity Roadmap&lt;/strong&gt; — a series where I learn cybersecurity in public, one topic at a time, and share everything I learn. No fluff, no assumed knowledge. If you are a student or a beginner wondering where to start, this series is for you.&lt;/p&gt;

&lt;p&gt;In this first episode: what cybersecurity actually is, why it matters, and the three ideas everything else is built on.&lt;/p&gt;

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

&lt;p&gt;Cybersecurity is the practice of protecting systems, networks, and data from digital attacks. Those attacks usually aim to do one of three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Steal&lt;/strong&gt; information (passwords, personal data, business secrets)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Damage&lt;/strong&gt; systems (delete data, shut down services, spread malware)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trick&lt;/strong&gt; people (phishing, scams, fake websites)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every defense you will ever learn — firewalls, encryption, strong passwords, updates — exists to stop one of those three.&lt;/p&gt;

&lt;h2&gt;
  
  
  The foundation: the CIA triad
&lt;/h2&gt;

&lt;p&gt;Almost everything in cybersecurity comes back to three goals, known as the &lt;strong&gt;CIA triad&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Confidentiality — only the right people see the data
&lt;/h3&gt;

&lt;p&gt;Your messages, passwords, and files should be readable only by the people allowed to see them. Tools: passwords, encryption, access control.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Integrity — the data stays correct and unmodified
&lt;/h3&gt;

&lt;p&gt;Nobody should be able to secretly change your data — not a bank balance, not a grade, not a medical record. Tools: hashing, digital signatures, backups.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Availability — the system works when you need it
&lt;/h3&gt;

&lt;p&gt;Security means nothing if the service is down. Systems must stay up and reachable for legitimate users. Tools: redundancy, backups, protection against denial-of-service attacks.&lt;/p&gt;

&lt;p&gt;A real attack usually breaks at least one of the three. A phishing email that steals your password? That breaks &lt;strong&gt;confidentiality&lt;/strong&gt;. Ransomware that encrypts your files? That breaks &lt;strong&gt;availability&lt;/strong&gt; (and often confidentiality too). A tampered download? That breaks &lt;strong&gt;integrity&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should you care?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Your accounts, photos, and messages are targets — attackers automate their work, so you do not need to be famous to be attacked.&lt;/li&gt;
&lt;li&gt;Companies lose money and trust after breaches, so cybersecurity is one of the most in-demand skills in tech right now.&lt;/li&gt;
&lt;li&gt;The basics stop most attacks. You do not need to be a hacker to be safer — you need the fundamentals, applied consistently.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next in this series
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What is cybersecurity (this post)&lt;/li&gt;
&lt;li&gt;Computer basics every security learner needs&lt;/li&gt;
&lt;li&gt;Networks: how data actually moves&lt;/li&gt;
&lt;li&gt;The CIA triad in depth: encryption and hashing&lt;/li&gt;
&lt;li&gt;Common attacks: phishing, malware, and social engineering&lt;/li&gt;
&lt;li&gt;And more — one topic at a time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are learning too, follow along and tell me in the comments: &lt;strong&gt;what made you interested in cybersecurity?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>beginners</category>
      <category>security</category>
      <category>learning</category>
    </item>
    <item>
      <title>AI Post Generator, Now Running on Local Open-Weight Models (Gemma 3 + Ollama)</title>
      <dc:creator>Waleed Shamhan</dc:creator>
      <pubDate>Fri, 16 Oct 2026 18:02:00 +0000</pubDate>
      <link>https://dev.to/waleedshamhan2050sys/ai-post-generator-now-running-on-local-open-weight-models-gemma-3-ollama-a7c</link>
      <guid>https://dev.to/waleedshamhan2050sys/ai-post-generator-now-running-on-local-open-weight-models-gemma-3-ollama-a7c</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;&lt;strong&gt;AI-Post-Generator&lt;/strong&gt; is a Python command-line tool that generates professional Arabic posts for WhatsApp and Telegram channels. I originally built it on a hosted API — and for this challenge I added a new mode that runs it on a &lt;strong&gt;local open-weight model (Gemma 3)&lt;/strong&gt; through &lt;strong&gt;Ollama&lt;/strong&gt;, with no hosted API involved.&lt;/p&gt;

&lt;p&gt;Who would pay for it? Anyone who runs a channel and posts every day: channel owners, small businesses, media coordinators, and community managers. Writing fresh, consistent posts daily is the tedious task they all complain about — this tool turns a topic + a template into a ready post in seconds.&lt;/p&gt;

&lt;p&gt;The problem it solves is threefold: the blank page (what do I post today?), consistency (same voice across every post), and cost/privacy (with the local mode, there is no per-post API bill and the channel's content never leaves the owner's machine).&lt;/p&gt;

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

&lt;p&gt;Run it with the local open-weight model (default):&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
python main.py
&lt;span class="c"&gt;# or explicitly:&lt;/span&gt;
python main.py &lt;span class="nt"&gt;--provider&lt;/span&gt; ollama &lt;span class="nt"&gt;--model&lt;/span&gt; gemma3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The original hosted mode still works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python main.py &lt;span class="nt"&gt;--provider&lt;/span&gt; openai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is a &lt;strong&gt;real post generated by the tool running Gemma 3:1b locally via Ollama&lt;/strong&gt; — topic "daily reading", template "morning motivation". The exact output is also saved in the repo as &lt;code&gt;examples/gemma3_local_sample.txt&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;صباح الخير يا أصدقائي! 📚&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;هل تبحث عن طريقة رائعة لتهدئة ذهنك، وتعزيز تركيزك، وفتح أبواب جديدة للمعرفة؟ القراءة اليومية هي الحل! ☀️&lt;/p&gt;

&lt;p&gt;تذكروا، القراءة ليست مجرد قراءة، بل هي رحلة استكشافية، وتطوير الذات، وراحة البال. 🧘‍♀️&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;اكتشفوا قوة القراءة&lt;/strong&gt;! 📖&lt;/p&gt;

&lt;p&gt;شاركوا معنا أفكاركم حول القراءة اليومية. ما هي الكتب التي تحبون قراءتها؟ 🤔&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;دعونا نُشجع بعضكم البعض!&lt;/strong&gt; 🤝&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#صباح_الخير #تحفيز #إيجابية&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;&lt;a href="https://github.com/waleedshamhan2050-sys/AI-Post-Generator" rel="noopener noreferrer"&gt;https://github.com/waleedshamhan2050-sys/AI-Post-Generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The open-model mode is a &lt;code&gt;--provider&lt;/code&gt; flag in &lt;code&gt;main.py&lt;/code&gt;: &lt;code&gt;get_client()&lt;/code&gt; points the same OpenAI-compatible client at the local Ollama server (&lt;code&gt;http://localhost:11434/v1&lt;/code&gt;) instead of the hosted API, and the model defaults to &lt;code&gt;gemma3&lt;/code&gt; (configurable via &lt;code&gt;OLLAMA_MODEL&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt; or &lt;code&gt;--model&lt;/code&gt;). The prompt, the JSON templates, and the saving logic are unchanged — only the provider changes.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ollama&lt;/strong&gt; for local inference — it exposes an OpenAI-compatible API, so the same client code works for both the hosted and the local path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 3&lt;/strong&gt;, an open-weight model, as the default local model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON templates&lt;/strong&gt; for each post type (announcement, quick tip, morning motivation, upcoming event, interactive question) with guiding examples.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;python-dotenv&lt;/strong&gt; for configuration (&lt;code&gt;OLLAMA_MODEL&lt;/code&gt;, &lt;code&gt;OLLAMA_BASE_URL&lt;/code&gt;, and the optional &lt;code&gt;OPENAI_API_KEY&lt;/code&gt; for the hosted mode).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key design decision: one codebase, two providers. The tool does not care where the model lives — the templates and the flow stay the same.&lt;/p&gt;

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

&lt;p&gt;This project is the reason I believe in open innovation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cost:&lt;/strong&gt; a channel owner posting daily would pay per-post API fees forever. With a local open-weight model, the marginal cost of a post is zero — which is what makes the business actually work for small channels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy:&lt;/strong&gt; channel content, business announcements, and audience ideas never leave the owner's machine. Nothing is sent to a third-party API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No lock-in:&lt;/strong&gt; no vendor can change the pricing, rate limits, or terms under you. If one model stops suiting you, you swap it — &lt;code&gt;llama3.2&lt;/code&gt;, &lt;code&gt;qwen2.5&lt;/code&gt;, &lt;code&gt;mistral&lt;/code&gt; — without rewriting the tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works offline:&lt;/strong&gt; the tool runs on a laptop with no connection, which matters for users with unreliable internet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built for a niche:&lt;/strong&gt; the templates are tuned for Arabic WhatsApp/Telegram channel style — a niche a general-purpose hosted API handles poorly out of the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open weights made this possible. A closed API could never offer all five at once.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Best Use of Gemma&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Customer Purchase Prediction with Logistic Regression - A Beginner's End-to-End ML Project</title>
      <dc:creator>Waleed Shamhan</dc:creator>
      <pubDate>Fri, 16 Oct 2026 16:38:45 +0000</pubDate>
      <link>https://dev.to/waleedshamhan2050sys/customer-purchase-prediction-with-logistic-regression-a-beginners-end-to-end-ml-project-2d24</link>
      <guid>https://dev.to/waleedshamhan2050sys/customer-purchase-prediction-with-logistic-regression-a-beginners-end-to-end-ml-project-2d24</guid>
      <description>&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%2F3bgdvv87pcjcs9h5j2tw.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%2F3bgdvv87pcjcs9h5j2tw.png" alt=" " width="800" height="336"&gt;&lt;/a&gt;When I finished my first machine learning lectures, I wanted a project that used everything I had learned: data loading, preprocessing, train-test split, scaling, training, and evaluation. So I built a small but complete project: predicting whether a customer will purchase a product, based on their age, salary, experience, and gender.&lt;/p&gt;

&lt;p&gt;The dataset is tiny (8 customers), which makes it perfect for learning — you can follow every number by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Age&lt;/th&gt;
&lt;th&gt;Salary&lt;/th&gt;
&lt;th&gt;Experience&lt;/th&gt;
&lt;th&gt;Gender&lt;/th&gt;
&lt;th&gt;Approved&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Male&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;600&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Female&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;700&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Male&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;td&gt;800&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Female&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;td&gt;900&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Male&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Female&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;1100&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Male&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;43&lt;/td&gt;
&lt;td&gt;1200&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Female&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Approved is the target: Yes means the customer bought, No means they didn't. The rest are the features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Load the data and encode the categories
&lt;/h2&gt;

&lt;p&gt;Models work with numbers, so the Gender and Approved columns need encoding: Male = 0, Female = 1, No = 0, Yes = 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.model_selection&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;train_test_split&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.preprocessing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StandardScaler&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.linear_model&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LogisticRegression&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;accuracy_score&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Age&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Salary&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Experience&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Gender&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Male&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Female&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Male&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Female&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Male&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Female&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Male&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Female&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Approved&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;No&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;No&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;No&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Yes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Yes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Yes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Yes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Yes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Gender&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Gender&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Male&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Female&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Approved&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Approved&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;No&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Yes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Split features and target, then train/test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Age&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Salary&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Experience&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Gender&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Approved&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;train_test_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Train shape: (6, 4) — Test shape: (2, 4)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;test_size=0.2 means 20% of the data goes to testing. random_state=42 makes the split reproducible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Scale the features
&lt;/h2&gt;

&lt;p&gt;Age ranges up to 43, Salary up to 1200. Without scaling, the bigger numbers dominate the model. StandardScaler fixes that — and the key rule is: fit only on the training data, then transform both sets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;scaler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StandardScaler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;X_train&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scaler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;X_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scaler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# never fit_transform on test data!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Train and evaluate
&lt;/h2&gt;

&lt;p&gt;Since the target is yes/no, this is a classification problem, and logistic regression is the natural first model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LogisticRegression&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;y_pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Actual:   &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;   &lt;span class="c1"&gt;# [0, 1]
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Predicted:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_pred&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;   &lt;span class="c1"&gt;# [0, 1]
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accuracy: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;accuracy_score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_pred&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# 1.0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model predicted both test customers correctly: accuracy 1.0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Predict a new customer
&lt;/h2&gt;

&lt;p&gt;Now the fun part — a brand-new customer: age 36, salary 950, 6 years of experience, female. The new data must go through the same scaler (transform, not fit):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;new_customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;950&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="n"&gt;new_customer_scaled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scaler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;prediction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_customer_scaled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Approved&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;prediction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Not Approved&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Approved
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result: Approved (Yes) — the model predicts this customer will purchase.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Preprocessing is half the project. Encoding categories and scaling features matter as much as the model itself.&lt;/li&gt;
&lt;li&gt;Never fit on test data. Fitting the scaler on test data leaks information and gives fake results.&lt;/li&gt;
&lt;li&gt;Small data teaches the pipeline. With 8 rows I could trace every step; the same pipeline scales to thousands of rows.&lt;/li&gt;
&lt;li&gt;Accuracy on 2 test samples is not proof. A 1.0 here is encouraging, not conclusive — real evaluation needs more data and more metrics (precision, recall, confusion matrix).&lt;/li&gt;
&lt;li&gt;If you are learning ML, build this project yourself and change one thing at a time: try a different random_state, add a feature, or compare logistic regression with a decision tree. That is where the real learning happens.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>machinelearning</category>
      <category>python</category>
      <category>datascience</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I Built an AI Post Generator for WhatsApp and Telegram - Here's What I Learned</title>
      <dc:creator>Waleed Shamhan</dc:creator>
      <pubDate>Fri, 16 Oct 2026 16:21:37 +0000</pubDate>
      <link>https://dev.to/waleedshamhan2050sys/i-built-an-ai-post-generator-for-whatsapp-and-telegram-heres-what-i-learned-3glg</link>
      <guid>https://dev.to/waleedshamhan2050sys/i-built-an-ai-post-generator-for-whatsapp-and-telegram-heres-what-i-learned-3glg</guid>
      <description>&lt;p&gt;I'm an IT student, and I also work as a media coordinator. That means I live in two worlds: writing code, and writing content. One day I got tired of staring at a blank screen every time I needed a post for a WhatsApp or Telegram channel, so I built a small tool to solve my own problem: &lt;strong&gt;AI-Post-Generator&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's a Python command-line tool that generates professional posts for WhatsApp and Telegram channels using AI. You can find it here: &lt;a href="https://github.com/waleedshamhan2050-sys/AI-Post-Generator" rel="noopener noreferrer"&gt;https://github.com/waleedshamhan2050-sys/AI-Post-Generator&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Running a channel means publishing constantly: announcements, tips, motivational posts, interactive questions. Writing all of that by hand is slow, and the tone drifts from post to post. I wanted something that could produce good drafts fast, in a consistent voice, and in Arabic.&lt;/p&gt;

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

&lt;p&gt;The flow is deliberately simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You pick a topic and a template from the command line.&lt;/li&gt;
&lt;li&gt;The tool loads a JSON template for that post type (announcement, tip, motivation, interactive question) with guiding examples.&lt;/li&gt;
&lt;li&gt;It sends the prompt to the OpenAI API (using &lt;code&gt;gpt-4.1-mini&lt;/code&gt;) and gets back a generated post.&lt;/li&gt;
&lt;li&gt;The generated post is saved automatically in an &lt;code&gt;examples/&lt;/code&gt; folder, so you can reuse or review it later.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The tech stack is small: &lt;strong&gt;Python 3.x&lt;/strong&gt;, the &lt;strong&gt;OpenAI API&lt;/strong&gt;, &lt;strong&gt;python-dotenv&lt;/strong&gt; for managing the API key safely in a &lt;code&gt;.env&lt;/code&gt; file, and &lt;strong&gt;JSON&lt;/strong&gt; for the templates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design decisions I am proud of
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Templates instead of free-form prompts.&lt;/strong&gt; Every post type has a JSON template with examples. This keeps the output consistent and lets me steer the AI toward a specific kind of post instead of hoping for a good result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Arabic-first.&lt;/strong&gt; The tool generates posts in Modern Standard Arabic with appropriate emojis, because that is the audience I write for. Most AI writing tools I tried defaulted to English, so this mattered to me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep the secrets out of the code.&lt;/strong&gt; The API key lives in a &lt;code&gt;.env&lt;/code&gt; file, never in the source. It is a small thing, but it is the kind of habit I want to keep for every project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;Building this taught me more than the tool itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python CLI apps:&lt;/strong&gt; structuring a command-line program and keeping the code clean and documented.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Working with AI APIs:&lt;/strong&gt; how to call the OpenAI API, shape prompts through templates, and handle the response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured data:&lt;/strong&gt; using JSON to store and manage templates in an organized way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment management:&lt;/strong&gt; keeping sensitive data like API keys secure with &lt;code&gt;.env&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt design:&lt;/strong&gt; writing templates that guide the AI toward a specific post type is a skill of its own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content automation:&lt;/strong&gt; how the whole loop of creating content for social channels can be automated.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is next
&lt;/h2&gt;

&lt;p&gt;I want to add direct publishing to channels, more template types, and support for scheduling posts. The goal is the same as when I started: less time staring at a blank screen, more time on the ideas that matter.&lt;/p&gt;

&lt;p&gt;If you run a channel or create content regularly, I would love to hear how you handle the blank-page problem. And if you try the tool, feedback is welcome.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>openai</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
