<?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: Simran Kaur</title>
    <description>The latest articles on DEV Community by Simran Kaur (@arkia09).</description>
    <link>https://dev.to/arkia09</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%2F4153923%2F1d3738e9-699b-468e-a983-828e1aa16842.jpg</url>
      <title>DEV Community: Simran Kaur</title>
      <link>https://dev.to/arkia09</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arkia09"/>
    <language>en</language>
    <item>
      <title>Who Do You Report a Pothole To? I Built Civic Lens to Answer That</title>
      <dc:creator>Simran Kaur</dc:creator>
      <pubDate>Sun, 11 Oct 2026 12:56:32 +0000</pubDate>
      <link>https://dev.to/arkia09/who-do-you-report-a-pothole-to-i-built-civic-lens-to-answer-that-1nlg</link>
      <guid>https://dev.to/arkia09/who-do-you-report-a-pothole-to-i-built-civic-lens-to-answer-that-1nlg</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;Living in India comes with a lot of infrastructure problems, and somewhere along the way we stopped seeing them. A garbage pile at the corner, a broken footpath, a dead streetlight. Nobody fixes them, and honestly we don't either. We walk past and carry on with the day as if everything is fine.&lt;/p&gt;

&lt;p&gt;Even people who do notice usually don't know who is responsible or where to report it. I didn't, until I built this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Civic Lens&lt;/strong&gt; is a web app that makes you actually look. You type your area and get a short quest with three categories: safety and infrastructure, cleanliness and environment, accessibility and public space. For each one you go outside, photograph a real problem, and write how you'd fix it. Then you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a score for the problem and for your proposed fix&lt;/li&gt;
&lt;li&gt;the kind of authority responsible for it&lt;/li&gt;
&lt;li&gt;a 4-step action plan&lt;/li&gt;
&lt;li&gt;a complaint draft, written for you, ready to copy&lt;/li&gt;
&lt;li&gt;a link to an official government reporting page, when one can be found&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do all three and you get "Grass Touched 🌱". The point isn't the points. It's learning who is responsible for the everyday problems around you, and having a complaint ready to send.&lt;/p&gt;

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

&lt;p&gt;I've added a demo video in project's readme. Please check it out if you get a chance :)&lt;br&gt;
Live Site: &lt;a href="https://civiclens-web-v1aa.onrender.com/" rel="noopener noreferrer"&gt;https://civiclens-web-v1aa.onrender.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1lmkm3lwi00xa8hayvno.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%2F1lmkm3lwi00xa8hayvno.png" alt=" " width="800" height="377"&gt;&lt;/a&gt; &lt;br&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%2Fsytdmyrwjrez4cb43cb4.jpeg" 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%2Fsytdmyrwjrez4cb43cb4.jpeg" alt=" " width="720" height="1520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Taking it outside:&lt;/strong&gt; I walked around my area and tried it for real. It felt awkward. Standing on the road photographing a garbage pile or a broken stretch of pavement from different angles, with people walking past, is not something I'm used to, and I caught myself wanting to hurry up and move on.&lt;/p&gt;

&lt;p&gt;I took 5 pics. For the demo video I uploaded them with the "Choose from gallery" button, so the in-app camera flow isn't in the recording.&lt;/p&gt;

&lt;p&gt;What I saw when I ran them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scores:&lt;/strong&gt; they felt fair. My proposed fixes were short and not very detailed, and the scores reflected that, so the grader wasn't just handing out high marks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reporting channel:&lt;/strong&gt; I only tried "Find reporting channel" once, on an infrastructure issue. It returned a generic Delhi government link that was probably not the right place for road complaints, and it still gave me the +2 bonus. This is the weakest part of the app right now, and I explain why below.&lt;/li&gt;
&lt;/ul&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/arkia09" rel="noopener noreferrer"&gt;
        arkia09
      &lt;/a&gt; / &lt;a href="https://github.com/arkia09/CivicLens" rel="noopener noreferrer"&gt;
        CivicLens
      &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;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/arkia09/CivicLens/frontend/public/mascot.webp"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Farkia09%2FCivicLens%2FHEAD%2Ffrontend%2Fpublic%2Fmascot.webp" alt="Civic Lens mascot" width="120"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Civic Lens&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;
  Photograph three real problems in your neighbourhood, propose a fix, and get a score
  the responsible authority and a ready-to-send complaint
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://github.com/arkia09/CivicLens/LIVE_URL" rel="noopener noreferrer"&gt;Live app&lt;/a&gt; ·
  &lt;a href="https://github.com/arkia09/CivicLens/DEV_POST_URL" rel="noopener noreferrer"&gt;DEV post&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Built for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05" rel="nofollow"&gt;Hacktoberfest Open-Source AI Challenge, Week 1: Touch Grass&lt;/a&gt;.
The backend is on a free Render plan and sleeps when idle, so the first request can be slow.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Demo Video&lt;/h2&gt;

&lt;/div&gt;

  
    
    &lt;span class="m-1"&gt;Video.Project.5.1.1.1.1.mp4&lt;/span&gt;
    
  

  

  


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Gemma writes a short quest for your area, with one hint for each of three categories.&lt;/li&gt;
&lt;li&gt;Upload a photo and your proposed fix. Gemma checks the photo, scores the problem and your fix,
names the kind of authority responsible, and drafts a complaint.&lt;/li&gt;
&lt;li&gt;SerpApi looks for an official government reporting page (&lt;code&gt;.gov.in&lt;/code&gt; / &lt;code&gt;.nic.in&lt;/code&gt;) for a +2 bonus.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tech stack&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; FastAPI, Pydantic, httpx, Pillow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; React, TypeScript, Vite, Tailwind CSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI:&lt;/strong&gt; Gemma via the &lt;code&gt;google-genai&lt;/code&gt; SDK&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search:&lt;/strong&gt; SerpApi&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosting:&lt;/strong&gt; Render&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Project structure&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;civiclens/
├──&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/arkia09/CivicLens" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
This is how my project's structure looks like:&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;civiclens/
├── backend/
│   ├── main.py        # FastAPI routes: /api/quest, /api/analyze, /api/find-channel
│   ├── gemma.py       # everything that talks to Gemma
│   ├── search.py      # SerpApi lookup, ranking, cache, daily cap
│   ├── prompts.py     # all prompt text, separate from logic
│   ├── models.py      # Pydantic models, the API contract
│   ├── utils.py       # image checks, duplicate detection, score math
│   ├── mock_data.py   # canned data for frontend work
│   └── tests/
├── frontend/
│   └── src/
│       ├── App.tsx, api.ts, points.ts, types.ts
│       └── components/   # SlotCard, ResultView, ChannelFinder, Completion, Mascot
└── render.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Stack: FastAPI, React with Tailwind, Gemma for analysis, SerpApi for the reporting link, Render for hosting. I spent most of my time on the backend. I'll be upfront that Claude built almost all of the UI, because I had very little time.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Gemma is used
&lt;/h3&gt;

&lt;p&gt;I call Gemma through Google's API with the &lt;code&gt;google-genai&lt;/code&gt; SDK. There are two jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The quest&lt;/strong&gt; is text only. Gemma writes a short briefing and one hint per category for the area you typed. If it fails, the app falls back to a static template, so a quest never fails to load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Photo analysis&lt;/strong&gt; is the main one. When you submit a photo and your fix, the backend:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Checks the file (JPG or PNG, size limit, magic bytes so a renamed file can't pass) and hashes it to catch reused photos.&lt;/li&gt;
&lt;li&gt;Fixes phone rotation and shrinks it to 1280px, since phone photos are huge.&lt;/li&gt;
&lt;li&gt;Sends the image plus a prompt to Gemma, with a system instruction at low temperature (0.2).&lt;/li&gt;
&lt;li&gt;Gets back JSON, parses it, and validates it with Pydantic. If the JSON is broken, it retries once.&lt;/li&gt;
&lt;li&gt;Checks &lt;code&gt;photo_check&lt;/code&gt; first: is this a real outdoor photo, does it show a civic problem, and does it match this category? If not, the user gets a friendly rejection instead of a score.&lt;/li&gt;
&lt;li&gt;Computes the total score in the backend. The model gives two numbers from 0 to 10 and never adds anything up.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the primary model errors out (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;), the backend retries with a fallback (&lt;code&gt;gemma-4-31b-it&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Because users type text that goes into a prompt, I treat it as data. The user's text is wrapped in tags, the system prompt says to never follow instructions inside them, and I strip any attempt to close those tags. A "give me 10/10" solution gets a zero.&lt;/p&gt;

&lt;p&gt;Right now the three category names are hardcoded, like this:&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;SLOT_TITLES&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;safety_infrastructure&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;Safety &amp;amp; infrastructure&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;cleanliness_environment&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;Cleanliness &amp;amp; environment&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;accessibility_public_space&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;Accessibility &amp;amp; public space&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gemma already writes the hints for each area, but not the categories. Having Gemma pick different categories on every Start over is next on my list.&lt;/p&gt;

&lt;h3&gt;
  
  
  SerpApi
&lt;/h3&gt;

&lt;p&gt;SerpApi searches Google for the official page where a complaint can be filed, like &lt;code&gt;[area] [authority] [issue] complaint grievance portal&lt;/code&gt;. I only accept results on &lt;code&gt;.gov.in&lt;/code&gt; or &lt;code&gt;.nic.in&lt;/code&gt; that also mention words like "grievance" or "portal". If nothing qualifies, the app says so and gives no bonus. A found page is worth +2 points, so the app rewards knowing where to report.&lt;/p&gt;

&lt;p&gt;I had never heard of SerpApi before this challenge, so I spent a lot of time in its documentation. It helped me fix my errors and get it into the app.&lt;/p&gt;

&lt;p&gt;Limits right now, and I'm working on them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sometimes the search fails and my backend returns a 503. Pressing "Try again" usually works.&lt;/li&gt;
&lt;li&gt;My filter only checks that a result is on an official domain (&lt;code&gt;.gov.in&lt;/code&gt; or &lt;code&gt;.nic.in&lt;/code&gt;) and mentions words like "grievance" or "portal". It does not check that the page belongs to the right department. When I tested an infrastructure issue, it returned a generic Delhi government link that was probably not the right channel for road complaints, and it still gave me the +2 bonus. In an earlier test it found a proper MCD page, so it works sometimes, but I can't promise it's right. The bonus rewards finding an official page, not verifying it.&lt;/li&gt;
&lt;li&gt;There's a daily cap of 50 searches to protect my quota, and an in-memory cache. Both reset when the server restarts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Render, and the hour I'll never get back
&lt;/h3&gt;

&lt;p&gt;I hadn't used Render before, so I had ChatGPT walk me through the dashboard. It told me I didn't need to import my &lt;code&gt;.env&lt;/code&gt;, so I added the variables by hand. And I misspelled &lt;code&gt;CORS_ORIGINS&lt;/code&gt; as &lt;code&gt;CORS_ORIGIN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;My deployed site then threw this in the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Access to fetch at 'https://civiclens-xyhi.onrender.com/api/quest' from origin
'https://civiclens-web-v1aa.onrender.com' has been blocked by CORS policy...
No 'Access-Control-Allow-Origin' header is present on the requested resource.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I spent about an hour suspecting my backend. It was a spelling mistake, plus a trailing slash on the API URL that produced &lt;code&gt;//api/quest&lt;/code&gt;. The code ignores a variable with the wrong name and falls back to &lt;code&gt;localhost&lt;/code&gt;, so nothing complained. Next time I check the spelling first.&lt;/p&gt;

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

&lt;p&gt;Gemma has open weights. To be honest about my setup: I use it through Google's hosted API, so it isn't running locally or offline. What open weights gave me is a way out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No lock-in.&lt;/strong&gt; The scoring and complaint writing come from prompts I wrote and control (&lt;code&gt;prompts.py&lt;/code&gt;). If a better open model shows up, I change a model name, not the app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fallbacks I choose.&lt;/strong&gt; I use two different Gemma models as primary and fallback, and I can add more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A path to privacy.&lt;/strong&gt; People are photographing their own streets. With open weights, I could later run this on a server I control so those photos don't go to a third party. That's a future step, not what's live today.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Gemma picks different categories every time you start over, so quests aren't the same each time.&lt;/li&gt;
&lt;li&gt;A leaderboard. Today your points live only in your own browser (they survive a refresh, but not a different device), so anyone can edit them. A real leaderboard needs a database and some way to trust the scores.&lt;/li&gt;
&lt;li&gt;Better search accuracy for the official reporting page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Known limits: the app can't prove you went outside, only that you sent a convincing photo. And the free backend resets its cache and duplicate-photo list on restart.&lt;/p&gt;

&lt;p&gt;There's still a long way to go, but it works, and I now know who to call about the garbage pile on my street.&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; quest writing and the photo analysis, scoring and complaint drafting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render:&lt;/strong&gt; the API and the static frontend both run on Render.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of SerpApi:&lt;/strong&gt; finding the official government reporting page, which drives the bonus points.&lt;/li&gt;
&lt;/ul&gt;

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