<?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: Divyansh</title>
    <description>The latest articles on DEV Community by Divyansh (@divyansh0208).</description>
    <link>https://dev.to/divyansh0208</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%2F4000840%2F098e3b98-1b1d-4fa7-9f95-c273d2504c9d.png</url>
      <title>DEV Community: Divyansh</title>
      <link>https://dev.to/divyansh0208</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/divyansh0208"/>
    <language>en</language>
    <item>
      <title>Tuft: a nature quest that turns your screen black, judged by an open model on your own device</title>
      <dc:creator>Divyansh</dc:creator>
      <pubDate>Sun, 11 Oct 2026 18:29:59 +0000</pubDate>
      <link>https://dev.to/divyansh0208/tuft-a-nature-quest-that-turns-your-screen-black-judged-by-an-open-model-on-your-own-device-3091</link>
      <guid>https://dev.to/divyansh0208/tuft-a-nature-quest-that-turns-your-screen-black-judged-by-an-open-model-on-your-own-device-3091</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I wanted an app whose best feature is that you stop using it.&lt;/p&gt;

&lt;p&gt;Tuft gives you one small quest, like &lt;em&gt;find moss or lichen&lt;/em&gt;, &lt;em&gt;find sky between branches&lt;/em&gt;, or &lt;em&gt;find a shadow with a shape&lt;/em&gt;. You pick 5, 10 or 20 minutes and tap &lt;strong&gt;Go outside&lt;/strong&gt;. The screen goes pure black (off pixels on an OLED phone), the quest is read aloud, and the app disappears into your pocket.&lt;/p&gt;

&lt;p&gt;When the timer ends the phone buzzes and talks to you. You take one photo, no retakes. A vision model decides whether it completes the quest, says what it saw, and drops the result into a small field log on your device, thumbnail included.&lt;/p&gt;

&lt;p&gt;So the screen only matters for the first ten seconds and the last ten. Everything in between is you, outside.&lt;/p&gt;

&lt;p&gt;I made it for anyone who needs a reason to look up for ten minutes, and for a school club or hiking group that wants a tool it can host on its own.&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/PASTE-YOUR-IMAGE-LINK" 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/PASTE-YOUR-IMAGE-LINK" alt="Tuft quest screen on a teal background: " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Live app: &lt;strong&gt;&lt;a href="https://tuft.onrender.com" rel="noopener noreferrer"&gt;https://tuft.onrender.com&lt;/a&gt;&lt;/strong&gt;. On a phone, use &lt;em&gt;Add to Home Screen&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There's also a benchmark page at &lt;a href="https://tuft.onrender.com/bench/" rel="noopener noreferrer"&gt;https://tuft.onrender.com/bench/&lt;/a&gt; for testing the judge on your own photos.&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/PASTE-YOUR-IMAGE-LINK" 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/PASTE-YOUR-IMAGE-LINK" alt="Tuft bench page: add photos, run CLIP or an Ollama model, copy a results table" width="800" height="400"&gt;&lt;/a&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/Divyansh0208" rel="noopener noreferrer"&gt;
        Divyansh0208
      &lt;/a&gt; / &lt;a href="https://github.com/Divyansh0208/Tuft" rel="noopener noreferrer"&gt;
        Tuft
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;Tuft&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;A quest that ends outside.&lt;/strong&gt; Tuft hands you a small nature quest, turns your screen black, and tells you to put the phone in your pocket. When time is up you take one photo, and an open-weight vision model on your own device decides if you did it.&lt;/p&gt;
&lt;p&gt;Built for the Hacktoberfest 2026 Open-Source AI Challenge, Week 1: Touch Grass.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;App: &lt;code&gt;/&lt;/code&gt; (single page, no build step, no backend)&lt;/li&gt;
&lt;li&gt;Benchmark: &lt;code&gt;/bench/&lt;/code&gt; (measure the judge on your own photos)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&lt;/h2&gt;
&lt;/div&gt;

  &lt;div class="js-render-enrichment-target"&gt;
    &lt;div class="render-plaintext-hidden"&gt;
      &lt;pre&gt;flowchart LR
  quest["Quest&amp;lt;br/&amp;gt;built-in pool, or written by a local model"] --&amp;gt; pocket["Black pocket screen&amp;lt;br/&amp;gt;wake lock, timer, voice cue"]
  pocket --&amp;gt; shot["One photo, no retakes"]
  shot --&amp;gt; judge{"Judge"}
  judge --&amp;gt;|"Ollama reachable"| vlm["Vision model via Ollama&amp;lt;br/&amp;gt;e.g. gemma3:4b"]
  judge --&amp;gt;|"otherwise"| clip["CLIP in the browser&amp;lt;br/&amp;gt;transformers.js, offline after first load"]
  vlm --&amp;gt; verdict["Spoken verdict"]
  clip --&amp;gt; verdict
  verdict --&amp;gt; log["Field log&amp;lt;br/&amp;gt;stored on this device only"]
&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;span class="js-render-enrichment-loader d-flex flex-justify-center flex-items-center width-full"&gt;
    &lt;span&gt;
      &lt;span class="sr-only"&gt;Loading&lt;/span&gt;
&lt;/span&gt;
  &lt;/span&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pocket screen:&lt;/strong&gt; pure black (off pixels on…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Divyansh0208/Tuft" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;No backend, no build step, no framework. It's one &lt;code&gt;index.html&lt;/code&gt;, a service worker, a manifest and the benchmark page. MIT licensed.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;The judge has two modes.&lt;/strong&gt; If Ollama is running and has a vision model, Tuft uses it. It picks up Gemma, LLaVA and similar models on its own, and the same model can write new quests. If there's no Ollama, it falls back to CLIP running in the browser through transformers.js.&lt;/p&gt;

&lt;p&gt;CLIP compares the photo with the quest description and with six "not this" labels: a room indoors, a computer screen, a face, a plain wall, a road, a blurry photo. The quest passes if its description ranks first or scores above 25%. A second pass picks what the photo shows from eleven nature words, so the spoken verdict can say what it saw. If Ollama dies halfway through, Tuft switches to CLIP instead of showing an error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The black screen.&lt;/strong&gt; It's a black overlay plus the Screen Wake Lock API, because phones pause timers and audio when the screen locks. Phones also slow timers down in the background, so when the page comes back, Tuft checks the real clock instead of trusting the timeout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Offline.&lt;/strong&gt; A service worker caches the page, the CLIP library and its files the first time they load, and transformers.js caches the model weights. The idea is that after one online run, the judge works with no signal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A benchmark page.&lt;/strong&gt; At &lt;code&gt;/bench/&lt;/code&gt; you add photos, tag each one with its quest and whether it truly completes it, and run both judges. You get accuracy with 95% intervals. The page picks a threshold on one half of your photos and tests it on the other half. It also has a "can't tell" band, an exact paired test, and a gallery of every miss. I checked the paired test against counts from another entry in this challenge (19 vs 6 should give p = 0.015) and it matched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A bug worth telling.&lt;/strong&gt; An early decorative 3D layer put &lt;code&gt;perspective&lt;/code&gt; on the page body. That quietly changes what &lt;code&gt;position: fixed&lt;/code&gt; means, so the black screen would have covered the page instead of the whole phone. A black screen that's only partly black defeats the point, so it's fixed in the shipped version.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I haven't tested
&lt;/h3&gt;

&lt;p&gt;I haven't run a field study, so there are no accuracy numbers in this post. The benchmark page is there so anyone can measure it, including you. I also haven't checked the offline path in airplane mode on a real phone. CLIP matches photos to descriptions, it doesn't know species, and a photo that looks like the quest can fool it. The built-in pool has only ten quests.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The judge should work where the signal doesn't.&lt;/strong&gt; An app that wants you outside is going to end up somewhere with no bars. A closed vision API is a network call. Tuft's judge is open weights in your browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your surroundings stay yours.&lt;/strong&gt; Photos are resized and judged on the device. The only network traffic is the first download of assets, plus your own Ollama address if you set one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing to pay for.&lt;/strong&gt; No keys, no per-photo cost, no rate limits, no accounts. Any static host works, so a club can run its own copy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swapping models is one text field.&lt;/strong&gt; The CLIP weights are open too, so a hosted model getting retired can't break the app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The trade-off.&lt;/strong&gt; Closed frontier models are better at recognising species. I picked "good enough, private, and everywhere" over "best, sometimes", and I'm not claiming open wins on accuracy.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Best Use of Render:&lt;/strong&gt; Tuft is a static site on Render. The HTTPS it provides is what makes the wake lock, the service worker and Home Screen install work.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Building a cyclone impact forecaster with only 61 data points</title>
      <dc:creator>Divyansh</dc:creator>
      <pubDate>Wed, 30 Sep 2026 19:26:09 +0000</pubDate>
      <link>https://dev.to/divyansh0208/building-a-cyclone-impact-forecaster-with-only-61-data-points-3lk1</link>
      <guid>https://dev.to/divyansh0208/building-a-cyclone-impact-forecaster-with-only-61-data-points-3lk1</guid>
      <description>&lt;p&gt;Almost every year, India’s east coast—especially Odisha, Andhra Pradesh, and West Bengal—takes a hit from a cyclone. While plenty of tools show where a storm is heading, very few tell you how many people actually live inside the impact zone. Early on, that district-level exposure is what responders really need to prioritize resources.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Cyclone Impact Forecaster&lt;/strong&gt; to bridge that gap. It combines a 6-hour intensity forecast with a district-level exposure ranking for the North Indian Ocean, rendered on a 3D satellite globe.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://cyclone-forecaster-s015.onrender.com" rel="noopener noreferrer"&gt;https://cyclone-forecaster-s015.onrender.com&lt;/a&gt; &lt;em&gt;(runs on a free Render instance that sleeps when idle, so the first load takes about 45 to 60 seconds)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/Divyansh0208/Cyclone" rel="noopener noreferrer"&gt;https://github.com/Divyansh0208/Cyclone&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&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%2F9qt4qgy634ub516mvmnp.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%2F9qt4qgy634ub516mvmnp.png" alt="A storm placed by hand near the Odisha coast, with districts ranked by expected people affected" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A simulated storm placed by hand at 17.2 N, 84.5 E (80 kt), taken on a quiet day when no real storm was active.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How the pipeline works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ingesting storm state:&lt;/strong&gt; Live storms in the North Indian Ocean are pulled from NOAA's IBTrACS ACTIVE file (using JTWC fixes). Because the basin isn't always active, I also built modes to replay historical cyclones or drop a custom storm onto the map by hand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6-hour intensity forecast:&lt;/strong&gt; An XGBoost model predicts the change in wind speed over the next 6 hours based on current position, wind, central pressure, and their recent trends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;District exposure model:&lt;/strong&gt; To estimate human impact, I fitted a 2-parameter log-linear model on 61 historical Indian cyclone records from EM-DAT, combined with Census 2011 district populations and areas. It outputs expected people affected along with a 10-90% prediction interval for every district inside the impact radius.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3D visualization:&lt;/strong&gt; Built on MapLibre GL with satellite imagery and terrain elevation. District markers scale with the estimated affected population, and clicking any district flies the camera down to inspect it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of this runs strictly on real datasets—IBTrACS (NOAA NCEI) for tracks, EM-DAT (CRED) for the 61 historical impact records, and the 2011 Census of India. I avoided synthetic data completely; even the test suite runs against a real track excerpt from Cyclone Fani.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Naive Baseline&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Intensity MAE (6 h)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3.04 +/- 0.20 kt&lt;/td&gt;
&lt;td&gt;3.49 kt (persistence / last value)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Impact log-MAE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.50 +/- 0.41&lt;/td&gt;
&lt;td&gt;2.69 (historical mean)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For the intensity model, I used 5-fold cross-validation &lt;strong&gt;grouped by storm&lt;/strong&gt;, beating the persistence baseline across all 5 folds. For the impact model, I ran 5-fold CV with 20 repeats on the log scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes from working with 61 data points
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complex models overfit fast on small disaster datasets.&lt;/strong&gt; When I first threw a RandomForest at the EM-DAT impact data, it performed &lt;em&gt;worse&lt;/em&gt; than simply predicting the historical mean. Stepping back to a 2-parameter log-linear model actually generalized. I even ended up fixing the population density coefficient at 1 (letting it fit freely gave about 1.08, so locking it simplified the model with zero performance penalty). The improvement over the baseline is still modest, so I make that explicit in the UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Random train/test splits cheat on track data.&lt;/strong&gt; Consecutive 6-hour fixes from the same cyclone look nearly identical. If you do a standard random split, adjacent points end up in both train and test sets, inflating your metrics. Grouping cross-validation folds strictly by storm ID is the only honest way to evaluate it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't hide wide error bars.&lt;/strong&gt; In the screenshot above, the top-ranked district's 10-90% range spans from roughly 17,000 to 2.2 million people. That looks massive, but that's the reality of training on 61 noisy historical events. Rather than pretending the point estimate is exact, the UI frames the output as a &lt;em&gt;relative ranking&lt;/em&gt; across districts and keeps the error band front and center.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be transparent about data lag.&lt;/strong&gt; The upstream IBTrACS ACTIVE file only rebuilds about three times a week, meaning "live" data can lag by up to two days. The backend caches responses for 15 minutes, falls back to stale data if NOAA's upstream fails, and badges every fix in the UI with its exact age.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep training and serving feature logic in one place.&lt;/strong&gt; Both the offline training scripts and the live API import from a single &lt;code&gt;features.py&lt;/code&gt; module so feature engineering can't silently drift between the two.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Current limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No track or landfall forecasting yet:&lt;/strong&gt; Every district inside the impact radius currently receives the same predicted storm wind rather than a distance-decayed wind field.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outdated census boundaries:&lt;/strong&gt; Relying on the 2011 Census means the population figures are 15 years old and several newly carved-out districts aren't represented.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wind scale mismatch:&lt;/strong&gt; JTWC reports 1-minute sustained winds, whereas the India Meteorological Department (IMD) uses a 3-minute averaging period, making storm category labels approximate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not an official warning system:&lt;/strong&gt; This is an experimental decision-support project. IMD is the sole official authority for cyclone warnings in India.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Help wanted
&lt;/h2&gt;

&lt;p&gt;I have &lt;a href="https://github.com/Divyansh0208/Cyclone/issues" rel="noopener noreferrer"&gt;13 open issues on GitHub&lt;/a&gt;—several tagged &lt;code&gt;good first issue&lt;/code&gt;—covering a proper distance-decay wind field, better calibration for the 10-90% interval, post-2011 district boundaries, regional language support (Hindi, Odia, Telugu, Bengali), and an accessibility audit.&lt;/p&gt;

&lt;p&gt;If you work in disaster response, hydrometeorology, or geospatial ML, I’d really appreciate your critique on what would make this genuinely useful in the field.&lt;/p&gt;

</description>
      <category>python</category>
      <category>machinelearning</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Sahayak — An AI Legal Assistant That Says "I Don't Know" When It Should</title>
      <dc:creator>Divyansh</dc:creator>
      <pubDate>Sun, 27 Sep 2026 19:54:40 +0000</pubDate>
      <link>https://dev.to/divyansh0208/sahayak-an-ai-legal-assistant-that-says-i-dont-know-when-it-should-42l2</link>
      <guid>https://dev.to/divyansh0208/sahayak-an-ai-legal-assistant-that-says-i-dont-know-when-it-should-42l2</guid>
      <description>&lt;p&gt;Legal help is expensive, jargon-heavy, and often out of reach for people who need it most. For PromptWars: Virtual (Exclusive Edition) — a hackathon by Hack2Skill — I built &lt;strong&gt;Sahayak&lt;/strong&gt;, a RAG-based legal assistant that answers questions and summarizes documents in plain language, grounded in real context instead of confident guesses.&lt;/p&gt;

&lt;p&gt;🔗 Live: &lt;a href="https://legal-ai-eight-liart.vercel.app/" rel="noopener noreferrer"&gt;https://legal-ai-eight-liart.vercel.app/&lt;/a&gt;&lt;br&gt;
🔗 Code: &lt;a href="https://github.com/Divyansh0208/Legal-AI" rel="noopener noreferrer"&gt;https://github.com/Divyansh0208/Legal-AI&lt;/a&gt; (MIT)&lt;/p&gt;
&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ask&lt;/strong&gt; — a tenancy, consumer-rights, or contract question. Answers are retrieved from indexed context, not hallucinated. No matching context? It says so, instead of guessing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upload&lt;/strong&gt; — a PDF (scanned or native) → plain-language summary: what kind of document it is, what it obligates you to, what's worth double-checking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Voice&lt;/strong&gt; — ask by speaking, transcribed via Whisper.
Every response is grounded in retrieved context and explicit about what it can't confirm — no confident guessing when the docs don't cover something.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User (voice/text/doc)
      │
      ▼
React + Vite Frontend
      │  REST
      ▼
FastAPI Backend
      ├─► Groq Whisper API      (speech-to-text)
      ├─► PyMuPDF + pytesseract (parsing / OCR)
      ├─► sentence-transformers (embeddings)
      ├─► ChromaDB              (vector retrieval)
      ├─► Groq LLM API          (answer generation)
      └─► SQLite                (app data)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The RAG hot path is intentionally thin — no framework ceremony for a single retrieval + one chat completion call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;answer_question&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;---&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
    &lt;span class="n"&gt;completion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GROQ_LLM_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&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;role&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;system&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SYSTEM_PROMPT&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;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RAG_ANSWER_TEMPLATE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;temperature&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;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&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="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sources&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;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&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;distance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The part I'm actually proud of: the guardrails
&lt;/h2&gt;

&lt;p&gt;Anyone can wire an LLM to a text box. The parts that took real effort:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Untrusted-context system prompt&lt;/strong&gt; — uploaded documents and retrieved chunks are treated as &lt;em&gt;data&lt;/em&gt;, never instructions. Prompt-injection resistant by design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real upload validation&lt;/strong&gt; — &lt;code&gt;python-magic&lt;/code&gt; sniffs actual file bytes; a relabeled &lt;code&gt;.exe&lt;/code&gt; doesn't sneak through as &lt;code&gt;.pdf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting&lt;/strong&gt; — &lt;code&gt;slowapi&lt;/code&gt; on query, upload, and voice endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security headers&lt;/strong&gt; — CSP, X-Frame-Options, HSTS in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5 CI workflows on every push&lt;/strong&gt; — lint, pytest, bandit (SAST), gitleaks (secrets), pip-audit (deps), axe-core (a11y) — auto-deploy to Render/Vercel on merge to &lt;code&gt;main&lt;/code&gt;.
None of that shows up in a demo GIF. All of it is why the demo GIF is trustworthy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tech&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;FastAPI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLM&lt;/td&gt;
&lt;td&gt;Groq (&lt;code&gt;openai/gpt-oss-120b&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retrieval&lt;/td&gt;
&lt;td&gt;ChromaDB + sentence-transformers (&lt;code&gt;all-MiniLM-L6-v2&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parsing&lt;/td&gt;
&lt;td&gt;PyMuPDF, pytesseract&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speech&lt;/td&gt;
&lt;td&gt;Groq Whisper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;React + Vite, Tailwind&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB&lt;/td&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deploy&lt;/td&gt;
&lt;td&gt;Render + Vercel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;Multi-language support (deferred)&lt;/li&gt;
&lt;li&gt;Persisted chat sessions (currently in-memory)&lt;/li&gt;
&lt;li&gt;More jurisdiction-specific templates
If you've hit a real legal-access gap, or want to poke holes in the grounding/refusal behavior — feedback welcome. MIT-licensed, issues/PRs open.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>rag</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I Built a Prompt Forging Engine with NVIDIA Llama 3.1 70B for Google Prompt Wars 2026</title>
      <dc:creator>Divyansh</dc:creator>
      <pubDate>Wed, 24 Jun 2026 19:08:25 +0000</pubDate>
      <link>https://dev.to/divyansh0208/i-built-a-prompt-forging-engine-with-nvidia-llama-31-70b-for-google-prompt-wars-2026-3aa1</link>
      <guid>https://dev.to/divyansh0208/i-built-a-prompt-forging-engine-with-nvidia-llama-31-70b-for-google-prompt-wars-2026-3aa1</guid>
      <description>&lt;p&gt;What if you could take any weak, vague prompt and instantly transform it into an elite, production-ready one — with a power score, technique breakdown, and warrior rank?&lt;/p&gt;

&lt;p&gt;That's exactly what &lt;strong&gt;Prompt Forge&lt;/strong&gt; does.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤔 The Problem
&lt;/h2&gt;

&lt;p&gt;Most people use AI wrong. They type something like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Write me a blog post about productivity"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And wonder why the output is generic. The secret isn't the model — it's the prompt. A better prompt unlocks dramatically better results.&lt;/p&gt;

&lt;p&gt;But most people don't know &lt;em&gt;how&lt;/em&gt; to write better prompts. That's the gap Prompt Forge fills.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚔️ What is Prompt Forge?
&lt;/h2&gt;

&lt;p&gt;Prompt Forge is a single-page web app that transforms weak prompts into elite, production-ready prompts using &lt;strong&gt;NVIDIA Llama 3.1 70B&lt;/strong&gt; via the NVIDIA NIM API.&lt;/p&gt;

&lt;p&gt;You paste a rough idea → hit &lt;strong&gt;Forge It&lt;/strong&gt; → get back:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A rewritten prompt (3–8× more detailed)&lt;/li&gt;
&lt;li&gt;Which of 8 prompt engineering techniques were applied&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Power Level score&lt;/strong&gt; from 1–10&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Warrior Rank&lt;/strong&gt; (Recruit → Bronze → Silver → Gold → Legendary)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Warrior Analysis&lt;/strong&gt; explaining every upgrade made
🔗 &lt;strong&gt;&lt;a href="https://prompt-forge-o970.onrender.com" rel="noopener noreferrer"&gt;Try it live →&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✨ Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Forging Engine&lt;/strong&gt; — rewrites weak prompts using Llama 3.1 70B Instruct&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;8 Technique Tags&lt;/strong&gt; — Context · Specificity · Constraints · Output Format · Persona · Examples · Chain-of-Thought · Negatives&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Power Level Meter&lt;/strong&gt; — 10-bar visual indicator (1–10)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Warrior Rank System&lt;/strong&gt; — gamified ranking based on power level&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Warrior Analysis Panel&lt;/strong&gt; — explains every improvement made&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typewriter Animation&lt;/strong&gt; — forged prompt streams in dramatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-click Copy&lt;/strong&gt; — instantly copy the result&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyboard Shortcut&lt;/strong&gt; — &lt;code&gt;Ctrl+Enter&lt;/code&gt; / &lt;code&gt;Cmd+Enter&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  - &lt;strong&gt;Responsive&lt;/strong&gt; — works on mobile and tablet
&lt;/h2&gt;

&lt;h2&gt;
  
  
  🛠️ Tech Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Vanilla HTML / CSS / JavaScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Python + Flask&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Model&lt;/td&gt;
&lt;td&gt;NVIDIA Llama 3.1 70B Instruct&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API&lt;/td&gt;
&lt;td&gt;NVIDIA NIM API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;Render&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Deliberately kept the stack simple — no React, no heavy frameworks. Just a single HTML file on the frontend and a lightweight Flask proxy on the backend.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 How It Works
&lt;/h2&gt;

&lt;p&gt;The architecture is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Input → Flask Server → NVIDIA NIM API → Llama 3.1 70B → Structured JSON → UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;User enters a weak prompt&lt;/li&gt;
&lt;li&gt;Frontend sends &lt;code&gt;POST /api/forge&lt;/code&gt; to Flask&lt;/li&gt;
&lt;li&gt;Flask forwards to NVIDIA NIM API with a system prompt instructing Llama to act as a master prompt engineer&lt;/li&gt;
&lt;li&gt;Model returns structured JSON:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"forged_prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"techniques_used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Context"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Specificity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Persona"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"power_level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"analysis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Added role context, specified output format..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Frontend renders with typewriter animation, technique tags, power meter, and warrior rank
&lt;/h2&gt;

&lt;h2&gt;
  
  
  📡 The Key: System Prompt Engineering
&lt;/h2&gt;

&lt;p&gt;The magic is in the system prompt sent to Llama 3.1 70B. It instructs the model to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Act as a master prompt engineer&lt;/li&gt;
&lt;li&gt;Identify weaknesses in the input prompt&lt;/li&gt;
&lt;li&gt;Apply specific prompt engineering techniques&lt;/li&gt;
&lt;li&gt;Return a structured JSON response with the forged prompt, techniques used, power level, and analysis
The model essentially uses prompt engineering &lt;em&gt;to improve prompts&lt;/em&gt; — meta, but incredibly effective.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎖️ Warrior Rank System
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Power Level&lt;/th&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1–2&lt;/td&gt;
&lt;td&gt;🪖 RECRUIT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3–4&lt;/td&gt;
&lt;td&gt;🥉 BRONZE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5–6&lt;/td&gt;
&lt;td&gt;🥈 SILVER&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7–8&lt;/td&gt;
&lt;td&gt;🥇 GOLD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9–10&lt;/td&gt;
&lt;td&gt;🏆 LEGENDARY&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🚀 Run It Yourself
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Divyansh0208/Prompt_Forge.git
&lt;span class="nb"&gt;cd &lt;/span&gt;Prompt_Forge
pip &lt;span class="nb"&gt;install &lt;/span&gt;flask python-dotenv requests
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;span class="c"&gt;# Add your NVIDIA API key to .env&lt;/span&gt;
python server.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get a free NVIDIA API key at &lt;a href="https://build.nvidia.com" rel="noopener noreferrer"&gt;build.nvidia.com&lt;/a&gt;.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;🌐 &lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://prompt-forge-o970.onrender.com" rel="noopener noreferrer"&gt;prompt-forge-o970.onrender.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  - 💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Divyansh0208/Prompt_Forge" rel="noopener noreferrer"&gt;github.com/Divyansh0208/Prompt_Forge&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Built for &lt;strong&gt;Google Prompt Wars 2026&lt;/strong&gt;. Try forging your weakest prompt and see what rank you earn ⚔️&lt;/p&gt;

</description>
      <category>promptengineering</category>
      <category>nvidia</category>
      <category>python</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How I Built a Carbon Footprint Tracker with Django + NVIDIA NIM</title>
      <dc:creator>Divyansh</dc:creator>
      <pubDate>Wed, 24 Jun 2026 16:01:00 +0000</pubDate>
      <link>https://dev.to/divyansh0208/how-i-built-a-carbon-footprint-tracker-with-django-nvidia-nim-4jp3</link>
      <guid>https://dev.to/divyansh0208/how-i-built-a-carbon-footprint-tracker-with-django-nvidia-nim-4jp3</guid>
      <description>&lt;p&gt;I wanted to build something that mattered. Climate change is one of those topics where awareness is the first barrier — most people don't know their actual footprint. So I built &lt;strong&gt;Carbon.Ledger&lt;/strong&gt;: a full-stack web app that lets you log activities, see your CO₂ impact, and get AI-powered tips to cut back.&lt;/p&gt;

&lt;p&gt;Here's how I built it, what went wrong, and the one engineering decision I'm most proud of.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Django 5&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; Tailwind CSS + htmx + Chart.js&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM:&lt;/strong&gt; NVIDIA NIM — &lt;code&gt;mistralai/mistral-large-3-675b-instruct-2512&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; SQLite (dev) / PostgreSQL (prod)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache:&lt;/strong&gt; Redis (prod)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  - &lt;strong&gt;Deployed on:&lt;/strong&gt; Render.com
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Three Pillars
&lt;/h2&gt;

&lt;p&gt;The app is built around one simple loop:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understand → Track → Reduce&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Understand
&lt;/h3&gt;

&lt;p&gt;Users can read lesson articles, browse a glossary (CO₂e, Scope 1/2/3, Net Zero), and ask free-text climate questions via an LLM-powered Q&amp;amp;A — rate limited to 10 questions/day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Track
&lt;/h3&gt;

&lt;p&gt;An activity logging form lets users log transport, energy, food, and goods. CO₂ is auto-computed on save using emission factors stored in the database — no LLM involved here. The dashboard shows a 30-day breakdown with a Chart.js donut chart and progress against a monthly goal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reduce
&lt;/h3&gt;

&lt;p&gt;Rule-based insights compare the user's totals against national average benchmarks. The top emission category drives filtered recommendations. And once per day, the LLM generates a personalized tip — cached 24h per user.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hardest Part: LLM Hallucination Guard
&lt;/h2&gt;

&lt;p&gt;This is the part I'm most proud of.&lt;/p&gt;

&lt;p&gt;LLMs make up numbers. That's a real problem when you're talking about emissions data — if the model says "beef produces 5 kg CO₂ per kg" when the real figure is 27, that's actively harmful misinformation.&lt;/p&gt;

&lt;p&gt;My solution in &lt;code&gt;services/llm.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_contains_hallucinated_numbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Extract all numbers from the LLM response.
    Check every one of them exists in the context we provided.
    If not → hallucination detected.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
    &lt;span class="n"&gt;response_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\d+\.?\d*&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;context_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\d+\.?\d*&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;response_numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;issubset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context_numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Call LLM with context (user's actual data)&lt;/li&gt;
&lt;li&gt;Extract all numbers from the response&lt;/li&gt;
&lt;li&gt;Check every number exists in the context&lt;/li&gt;
&lt;li&gt;If not → retry with explicit "do not use numbers" instruction&lt;/li&gt;
&lt;li&gt;If still fails → return a safe static fallback message
On top of that: &lt;code&gt;timeout=10.0&lt;/code&gt; and &lt;code&gt;max_retries=1&lt;/code&gt; are explicitly set to prevent hung Gunicorn worker threads on slow LLM responses.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Key principle: the LLM is never used for calculations. All math is Python/DB.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  htmx for the Category Dropdown
&lt;/h2&gt;

&lt;p&gt;The activity log form has a dependent dropdown — selecting a category dynamically loads the relevant emission factors. I used htmx for this instead of writing custom JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;select&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"category"&lt;/span&gt; 
        &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/factors/"&lt;/span&gt;
        &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#factor-select"&lt;/span&gt;
        &lt;span class="na"&gt;hx-trigger=&lt;/span&gt;&lt;span class="s"&gt;"change"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One attribute. No JS file. The server returns a partial HTML snippet with the filtered factors. This is exactly what htmx is built for.&lt;/p&gt;




&lt;h2&gt;
  
  
  Deployment on Render
&lt;/h2&gt;

&lt;p&gt;Render makes Django deployment straightforward. A few Django-specific things worth noting:&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="c1"&gt;# settings.py
&lt;/span&gt;&lt;span class="n"&gt;SECURE_PROXY_SSL_HEADER&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;HTTP_X_FORWARDED_PROTO&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;https&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;SECURE_SSL_REDIRECT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;DEBUG&lt;/span&gt;
&lt;span class="n"&gt;SESSION_COOKIE_SECURE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;DEBUG&lt;/span&gt;
&lt;span class="n"&gt;CSRF_COOKIE_SECURE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;DEBUG&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Render terminates TLS at the proxy level, so &lt;code&gt;SECURE_PROXY_SSL_HEADER&lt;/code&gt; is essential — without it Django won't recognize HTTPS requests and will redirect loop forever.&lt;/p&gt;

&lt;p&gt;Also: randomize your admin URL via env var:&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;ADMIN_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ADMIN_URL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;admin/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stops bots from hammering the default &lt;code&gt;/admin/&lt;/code&gt; endpoint.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Async LLM calls.&lt;/strong&gt; Right now the LLM calls are synchronous — a slow NVIDIA NIM response blocks a Gunicorn worker. The fix is Celery + Redis for background tasks. I skipped it for the MVP but it's the first thing I'd add.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audited emission factors.&lt;/strong&gt; The 22 factors I seeded are approximations from public sources, not peer-reviewed figures. For a production app, you'd want to integrate a verified dataset like the UK Government GHG conversion factors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Email verification.&lt;/strong&gt; Currently anyone can sign up with any email. Not a problem for an MVP, but a real gap.&lt;/p&gt;




&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;146 tests, 99% coverage&lt;/li&gt;
&lt;li&gt;Deployed and live&lt;/li&gt;
&lt;li&gt;Built in under a week&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔗 &lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://carbon-footprint-awareness-4qpf.onrender.com" rel="noopener noreferrer"&gt;carbon-footprint-awareness-4qpf.onrender.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🐙 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Divyansh0208/Carbon-Footprint-Awareness" rel="noopener noreferrer"&gt;github.com/Divyansh0208/Carbon-Footprint-Awareness&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you're building something with Django + LLMs, the hallucination guard pattern is worth stealing. And if you have thoughts on better emission factor datasets, I'd love to hear them in the comments.&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>llm</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
