<?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: Umesh Pal</title>
    <description>The latest articles on DEV Community by Umesh Pal (@umesh_pal_90bdc3fb76ae653).</description>
    <link>https://dev.to/umesh_pal_90bdc3fb76ae653</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%2F2093238%2Fe82753ed-da91-4505-9fdb-de56f96c5ded.png</url>
      <title>DEV Community: Umesh Pal</title>
      <link>https://dev.to/umesh_pal_90bdc3fb76ae653</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/umesh_pal_90bdc3fb76ae653"/>
    <language>en</language>
    <item>
      <title>I Built NatureSnap + Go: Gemma Turns a Nature Photo into an Outdoor Mission 🌿</title>
      <dc:creator>Umesh Pal</dc:creator>
      <pubDate>Mon, 12 Oct 2026 06:59:13 +0000</pubDate>
      <link>https://dev.to/umesh_pal_90bdc3fb76ae653/i-built-naturesnap-go-gemma-turns-a-nature-photo-into-an-outdoor-mission-4lg</link>
      <guid>https://dev.to/umesh_pal_90bdc3fb76ae653/i-built-naturesnap-go-gemma-turns-a-nature-photo-into-an-outdoor-mission-4lg</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;&lt;strong&gt;What if AI didn't give you another reason to stare at your screen, but a reason to put your phone away?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's the idea behind &lt;strong&gt;NatureSnap + Go&lt;/strong&gt;: a small experiment in using multimodal AI to turn a photo of something in nature into a reason to step outside.&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%2Fvctzjpkq07lgyjgnydac.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%2Fvctzjpkq07lgyjgnydac.png" alt="Home Page" width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upload a photo of a leaf, flower, bird, insect, or tree. Gemma 4 helps identify what you're looking at, points out a detail worth noticing, and suggests one outdoor mission you can complete in 5, 15, or 30 minutes.&lt;/p&gt;

&lt;p&gt;We can spend a surprising amount of time looking at nature through screens: searching for the name of a plant, wondering what kind of bird we just saw, or scrolling through pictures instead of exploring what's around us.&lt;/p&gt;

&lt;p&gt;I wanted to build something that uses AI to make that first step into the real world a little easier.&lt;/p&gt;

&lt;p&gt;NatureSnap + Go turns a photo of something in nature into a small invitation to explore.&lt;/p&gt;

&lt;p&gt;Here's how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Snap:&lt;/strong&gt; Upload a photo of a plant, flower, tree, bird, insect, or something else from nature. You can also choose an example photo or add a short note about where you found it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discover:&lt;/strong&gt; Gemma 4 examines the image and provides a likely identification, a short explanation, and a confidence label: High, Medium, or Low.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Look closer:&lt;/strong&gt; Instead of giving you a long article to read, it points out one specific detail worth noticing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go:&lt;/strong&gt; It suggests one outdoor mission with a time estimate. You can choose whether you have 5, 15, or 30 minutes, and the mission is tailored to the time you've available.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal isn't to turn nature into another endless AI conversation. It's to give you enough curiosity and direction to step outside, look more carefully, and discover something for yourself.&lt;/p&gt;

&lt;p&gt;The name is only there to make the mission specific. The mission is the product, and the screen is meant to be the shortest part of the experience.&lt;/p&gt;

&lt;p&gt;Here is a real answer from my first test with a photo:&lt;/p&gt;

&lt;p&gt;Example: Identifying a hibiscus flower&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%2Fmos05v8tass8w7e3d45r.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%2Fmos05v8tass8w7e3d45r.png" alt="Hibiscus Flower" width="800" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Likely Hibiscus flower&lt;/strong&gt; (Flower)&lt;br&gt;
This is a vibrant red hibiscus flower with large, delicate petals. It features a long, prominent central stamen topped with yellow pollen.&lt;br&gt;
&lt;strong&gt;Look closer:&lt;/strong&gt; Look at the very tip of the long pink tube to see the small, rounded stigma&lt;br&gt;
&lt;strong&gt;Mission:&lt;/strong&gt; Walk around your garden or a nearby park to find a plant with a different color of flower. Observe how its shape compares to this hibiscus.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I kept it small on purpose: no accounts, no history, no map, no chat window. You can add a short note ("Found near my society, in a park…") and a time, and that's all the setup there is. I built it with everyday nature in Indian neighbourhoods in mind, which is why the prompt's own example is a Peepal tree.&lt;/p&gt;

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

&lt;p&gt;🌿 &lt;strong&gt;Try NatureSnap + Go:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://nature-snap-go.vercel.app/" rel="noopener noreferrer"&gt;nature-snap-go.vercel.app&lt;/a&gt; (no sign-up; tap one of the four example photos if you don't have one handy)&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;



&lt;p&gt;&lt;strong&gt;GitHub repository:&lt;/strong&gt; &lt;a href="https://github.com/72umesh/NatureSnap-Go" rel="noopener noreferrer"&gt;https://github.com/72umesh/NatureSnap-Go&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The repository includes the frontend, API handlers, Gemma integration, prompts, safety checks, Sentry instrumentation, and automated tests.&lt;/p&gt;

&lt;p&gt;MIT licensed. It has automated tests for the reply parser, the safety check, the API endpoints and the Sentry trace link.&lt;/p&gt;
&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;



&lt;p&gt;This was my first project integrating an AI API into a complete application, and I wanted to learn more than simply sending a prompt and displaying the response.&lt;/p&gt;

&lt;p&gt;The main stack is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React + Vite&lt;/strong&gt; for the interface&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS&lt;/strong&gt; for styling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 4 (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;)&lt;/strong&gt; through the Gemini API for image understanding and mission generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt; for server-side validation, model requests, response parsing, and safety checks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sentry&lt;/strong&gt; for tracing, error monitoring, and connecting user reports to the relevant AI request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vercel&lt;/strong&gt; for deployment&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The flow
&lt;/h3&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%2Ffopjp25o3xipf0ns1hz9.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%2Ffopjp25o3xipf0ns1hz9.png" alt="Flow chart" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The browser shrinks the photo to a 1024px JPEG before sending it, which keeps uploads fast and well under Vercel's 4.5 MB request limit. A small Node endpoint validates the upload, rate-limits requests, keeps the API key off the browser, and returns clean JSON to a React + Vite + Tailwind front end. It's deployed on Vercel. There's no database.&lt;/p&gt;
&lt;h3&gt;
  
  
  One prompt, three jobs
&lt;/h3&gt;

&lt;p&gt;The photo and the note go to &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; through the Gemini API in a single multimodal request. One system prompt gives the model three connected jobs: understand the photo, help the user observe it, and get them outside. It replies in a fixed labelled format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TITLE: [short name, e.g. "Likely Peepal tree"]
CATEGORY: [Plant, Tree, Flower, Bird, Insect, Fungus or Other]
CONFIDENCE: [exactly one word: High, Medium or Low]
WHAT I SEE: [2-3 short sentences]
LOOK CLOSER: [one thing to observe, 1 sentence]
MISSION: [exactly ONE activity, 1-3 sentences]
TIME: [rough estimate, e.g. "~5 minutes"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I used labelled lines instead of relying on a structured-output mode. A tolerant parser reads them, copes with stray markdown, and fills sensible defaults if a field is missing, so a slightly messy reply doesn't break the screen.&lt;/p&gt;

&lt;p&gt;The prompt choices that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Honest uncertainty.&lt;/strong&gt; If Gemma isn't sure it must start the title with "Likely" and say so in the confidence label. A confident wrong name is worse than a hedged right one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One mission, not a list.&lt;/strong&gt; Lists get skimmed. One instruction gets done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fit the time.&lt;/strong&gt; If you tapped "15 min", the mission has to fit 15 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The note is context only.&lt;/strong&gt; What you type is wrapped as a note and the model is told never to follow instructions inside it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A non-nature photo gets a kind answer&lt;/strong&gt; with Low confidence and a mission to go and find something to photograph.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Safety, enforced twice
&lt;/h3&gt;

&lt;p&gt;The prompt tells Gemma never to suggest touching, eating, picking, collecting or approaching anything unfamiliar. But prompts can fail, and I'm sending people outdoors, so a second check runs on every reply on the server. If the mission still suggests touching or picking something, it's swapped for a safe one and logged:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RISKY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b(&lt;/span&gt;&lt;span class="sr"&gt;touch&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;ing&lt;/span&gt;&lt;span class="se"&gt;)?&lt;/span&gt;&lt;span class="sr"&gt;|pluck&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;ing&lt;/span&gt;&lt;span class="se"&gt;)?&lt;/span&gt;&lt;span class="sr"&gt;|taste|eat&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;ing&lt;/span&gt;&lt;span class="se"&gt;)?&lt;/span&gt;&lt;span class="sr"&gt;|squeeze|handle|collect&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;ing&lt;/span&gt;&lt;span class="se"&gt;)?&lt;/span&gt;&lt;span class="sr"&gt;|catch&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;ing&lt;/span&gt;&lt;span class="se"&gt;)?&lt;/span&gt;&lt;span class="sr"&gt;|feed&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;ing&lt;/span&gt;&lt;span class="se"&gt;)?&lt;/span&gt;&lt;span class="sr"&gt;|pick&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;ing&lt;/span&gt;&lt;span class="se"&gt;)?\s&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;up|it|them|some|any|fallen|a&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;leaf|flower|berry|fruit|twig|stone&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;|leaves|flowers&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;|berries&lt;/span&gt;&lt;span class="se"&gt;))\b&lt;/span&gt;&lt;span class="sr"&gt;/gi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;NEGATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b(&lt;/span&gt;&lt;span class="sr"&gt;don'&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;t|do not|never|avoid|without|not|no need to|instead of&lt;/span&gt;&lt;span class="se"&gt;)\b&lt;/span&gt;&lt;span class="sr"&gt;/i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// "Don't touch it" passes. "Pick some leaves and taste one" does not.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My first version flagged "Pick a quiet spot and watch the bird" because it saw the word &lt;em&gt;pick&lt;/em&gt;. I narrowed the rule to picking up or collecting specific things and added tests for both the harmful and the harmless sentences.&lt;/p&gt;

&lt;p&gt;Every screen also carries a small reminder that identification is a best guess, not an expert's answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I added Sentry
&lt;/h3&gt;

&lt;p&gt;I didn't want AI failures to disappear behind a generic error message. I wanted to understand what happened when a model request failed, how it performed, and what to investigate when a user reported a bad answer.&lt;/p&gt;

&lt;p&gt;I integrated Sentry tracing around the API and model call. The traces include information such as the model, request status, retry count, and token usage when the provider returns it. Estimated cost can also be recorded when pricing configuration is supplied.&lt;/p&gt;

&lt;p&gt;I also added a &lt;strong&gt;Report this answer&lt;/strong&gt; feature.&lt;/p&gt;

&lt;p&gt;A user can report an answer for reasons such as an incorrect identification, an unsafe suggestion, or a mission that doesn't really get them outdoors. The report carries the relevant answer metadata and Sentry trace context, allowing the report to be associated with the original request rather than becoming an isolated complaint.&lt;/p&gt;

&lt;p&gt;The report doesn't need to attach the original photo or the full conversation to provide that connection.&lt;/p&gt;

&lt;p&gt;For me, this was an important lesson: building with AI isn't only about generating a good answer. It's also about making failures observable and giving yourself a way to investigate them.&lt;/p&gt;

&lt;p&gt;I added automated tests for API validation, response parsing, safety handling, report processing, and Sentry trace correlation. I then ran the test suite and tested the deployed site.&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%2F6t5g6wcskhn05409wkl7.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%2F6t5g6wcskhn05409wkl7.png" alt="Tests" width="800" height="503"&gt;&lt;/a&gt;&lt;br&gt;
The second-photo follow-up experience is still unfinished, so it isn't part of the completed core flow I'm presenting here. I'd like to return to it later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sentry in action:&lt;/strong&gt; User reports for an inaccurate identification and a mission that didn't encourage outdoor exploration appear alongside an application error. This gives me a starting point for investigating issues instead of relying only on user feedback.&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%2F66vbt4xcx2ol55roldt1.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%2F66vbt4xcx2ol55roldt1.png" alt="Sentry" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What Went Wrong
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Three tests failed because I missed an outdated handler.&lt;/strong&gt; After merging a larger update, three tests failed because &lt;code&gt;handler.js&lt;/code&gt; hadn't been updated with the latest changes. The model name, safety check, and Sentry trace link were missing from the old file. The tests helped me catch the inconsistency before shipping the wrong version.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;I didn't notice a lost connection.&lt;/strong&gt; During development, the connection dropped in between, but I didn't realise it at the time. The same thing happened while pushing changes to Git. It taught me not to assume that a command or update has completed successfully just because I started it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;My deployed app didn't work because I missed an environment variable.&lt;/strong&gt; The live Vercel deployment initially failed because I hadn't configured the required environment variable there. I added it and redeployed the app, which fixed the issue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;My safety check was too broad at first.&lt;/strong&gt; The initial rule flagged “Pick a quiet spot and watch the bird” as unsafe because it matched the word &lt;em&gt;pick&lt;/em&gt;. I narrowed the rule to focus on potentially harmful actions and added tests for both unsafe and harmless sentences.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I want to be precise, because "open" gets claimed loosely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What open weights gave me:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A swappable model.&lt;/strong&gt; One environment variable (&lt;code&gt;GEMINI_MODEL&lt;/code&gt;) moves the app from &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; to &lt;code&gt;gemma-4-31b-it&lt;/code&gt;. The prompt, parser, safety check and UI don't change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guardrails that don't depend on the model.&lt;/strong&gt; Because I can swap models, I can't assume any one of them behaves. The safety check and the confidence handling live in my code, so they stay if the model changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Behaviour I control.&lt;/strong&gt; What the app does lives in a prompt in my repo, not in someone else's app settings. When a mission was too vague or too risky, I changed the prompt and the check myself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A project anyone can run.&lt;/strong&gt; The repo is MIT licensed. Bring your own API key, run &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;npm run dev&lt;/code&gt;.
&lt;strong&gt;What it is not:&lt;/strong&gt; this version calls the &lt;em&gt;hosted&lt;/em&gt; Gemma through the Gemini API, so it needs internet, and your photo goes to Google's servers. That's a real trade-off for something you use on a walk, and a truly offline version would be better for the theme. My laptop has 8 GB of RAM and already struggles with VS Code and a browser open together, so running a vision model locally wasn't realistic for me. The repo includes an optional local provider (&lt;code&gt;LLM_PROVIDER=ollama&lt;/code&gt;) that I have &lt;strong&gt;not&lt;/strong&gt; run on real hardware, so I'm not claiming an offline version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I haven't benchmarked Gemma against a closed model, so I can't say it was better on accuracy. What I can say is that building on an open model let me swap it, wrap it in my own guardrails, and open-source the whole thing. I built and tested the app using a free-tier Gemini API key.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma 4 does the multimodal work, reading the photo and the note together in one request through the Gemini API (Google's hosted serving). The model is swappable with one setting, and my own safety check sits around it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best Use of Sentry Agent Tracing:&lt;/strong&gt; every Gemma call is traced with its model, input and output tokens and duration. Errors are captured, and a user can report a bad answer in one tap and have it joined to the exact trace. This is a single-call app rather than a full agent, and I say so above.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Open &lt;a href="https://nature-snap-go.vercel.app/" rel="noopener noreferrer"&gt;nature-snap-go.vercel.app&lt;/a&gt; on your phone, snap the first plant, bug or bird you walk past, and then actually go and do the mission.&lt;/p&gt;

&lt;p&gt;I'd love to hear what you photographed, and whether the confidence label was right. Tell me in the comments what you'd want it to say.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
    </item>
  </channel>
</rss>
