<?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: Paola Ruffo</title>
    <description>The latest articles on DEV Community by Paola Ruffo (@cobaltspiral).</description>
    <link>https://dev.to/cobaltspiral</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%2F4159627%2Fd0d41cfc-8230-4331-b755-894c9363e5fe.jpg</url>
      <title>DEV Community: Paola Ruffo</title>
      <link>https://dev.to/cobaltspiral</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cobaltspiral"/>
    <language>en</language>
    <item>
      <title>Want to touch grass but run out of options? Let Mochi the Explorer guide you to your next favourite spot!</title>
      <dc:creator>Paola Ruffo</dc:creator>
      <pubDate>Sun, 11 Oct 2026 17:50:03 +0000</pubDate>
      <link>https://dev.to/cobaltspiral/want-to-touch-grass-but-run-out-of-options-let-mochi-the-explorer-guide-you-to-your-next-favourite-243g</link>
      <guid>https://dev.to/cobaltspiral/want-to-touch-grass-but-run-out-of-options-let-mochi-the-explorer-guide-you-to-your-next-favourite-243g</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;a href="https://mochitheexplorer.onrender.com/" rel="noopener noreferrer"&gt;Mochi the Explorer&lt;/a&gt; is a cute wee pixel mascot who helps you rediscover the city or town you already live in.&lt;/p&gt;

&lt;p&gt;The inspiration came from two weeks spent trying to organise something new and fun with my friends in the city we've lived in for the past 10 years: none of us could come up with anything that felt even remotely exciting, and so off we went to our usual pub, defeated once again. &lt;/p&gt;

&lt;p&gt;Sounds familiar? Cue Mochi to the rescue! All you have to do is tell Mochi where you live, what mood you're in, how much time you have and what time of day you're planning to head out and she'll plan the perfect outing for you! Mochi the Explorer will suggest between one and six stops (depending on how much time you have) and then encourage you to 'Go touch grass!' by showing you the location(s) she suggested on OpenStreeMap.&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;DURATIONS&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;30min&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;radius_m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stops&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1-2hrs&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;radius_m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stops&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;half_day&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;radius_m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stops&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;full_day&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;radius_m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stops&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;multiple_days&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;radius_m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stops&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;You only need to spend a couple of minutes on screen before being ready to put your shoes on and leave for an adventure! The goal is to suggest spots that fit your mood, but that you are less likely to have heard of or been to. In fact, Mochi deliberately avoids big chains and the most obvious picks, favouring indie shops, cafes and unusual experiences instead (try the &lt;code&gt;unusual&lt;/code&gt; tag if you don't believe me 😉). The results change between requests, so even locals who feel they've seen it all will find something they haven't tried yet.&lt;/p&gt;

&lt;p&gt;Let Mochi find your next favourite spot in town! ✨&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%2F7x54jlf4eotn5gvxx3v3.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%2F7x54jlf4eotn5gvxx3v3.png" alt="Two screenshots side-by-side of Mochi's homepage and Mochi suggesting a spot to visit" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Mochi the Explorer is available here: &lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://mochitheexplorer.onrender.com/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;mochitheexplorer.onrender.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;You can also watch a 'lil demo here:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/_fleqSGD_4k" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A wee heads up: the backend runs on Render’s free tier and sleeps when idle, so the first request can take about a minute to wake up. But don't despair! Mochi will keep you entertained while you wait:&lt;/em&gt;&lt;/p&gt;

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

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

&lt;p&gt;The GitHub repo is available here: &lt;/p&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/cobaltspiral" rel="noopener noreferrer"&gt;
        cobaltspiral
      &lt;/a&gt; / &lt;a href="https://github.com/cobaltspiral/mochi-the-explorer" rel="noopener noreferrer"&gt;
        mochi-the-explorer
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🩷 Mochi the Explorer is a cute wee pixel mascot who helps you rediscover the city or town you already live in.
    &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;Mochi the Explorer 🩷&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;
    &lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/120667980/670849598-f1786128-673d-44dd-95f1-e02d9f0aca06.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTE3OTgxNzAsIm5iZiI6MTc5MTc5Nzg3MCwicGF0aCI6Ii8xMjA2Njc5ODAvNjcwODQ5NTk4LWYxNzg2MTI4LTY3M2QtNDRkZC05NWYxLWUwMmQ5ZjBhY2EwNi5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYxMDEyJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MTAxMlQwOTM3NTBaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1lZTI1ODg5OTc5NmM5YzQ3ZDIzMGM4MDVmNWE1N2QyOGU3OTU0ZmFjMGM1NTg2OTU5ZDc4YWE1ZTkzOWEwOGQxJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.k9sPDuY7ukaXbeRTiYDaUy3O7MXfw13xR_ZWRFP6xaU"&gt;&lt;img width="600" height="300" alt="mochi-banner" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F120667980%2F670849598-f1786128-673d-44dd-95f1-e02d9f0aca06.png%3Fjwt%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTE3OTgxNzAsIm5iZiI6MTc5MTc5Nzg3MCwicGF0aCI6Ii8xMjA2Njc5ODAvNjcwODQ5NTk4LWYxNzg2MTI4LTY3M2QtNDRkZC05NWYxLWUwMmQ5ZjBhY2EwNi5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYxMDEyJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MTAxMlQwOTM3NTBaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1lZTI1ODg5OTc5NmM5YzQ3ZDIzMGM4MDVmNWE1N2QyOGU3OTU0ZmFjMGM1NTg2OTU5ZDc4YWE1ZTkzOWEwOGQxJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.k9sPDuY7ukaXbeRTiYDaUy3O7MXfw13xR_ZWRFP6xaU" class="js-gh-image-fallback"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mochitheexplorer.onrender.com/" rel="nofollow noopener noreferrer"&gt;Mochi the Explorer&lt;/a&gt; is a cute wee pixel mascot who helps you rediscover the city or town you already live in.&lt;/p&gt;

&lt;p&gt;The inspiration came from two weeks spent trying to organise something new and fun with my friends in the city we've lived in for the past 10 years
none of us could come up with anything that felt even remotely exciting, and so off we went to our usual pub, defeated once again.&lt;/p&gt;
&lt;p&gt;Sounds familiar? Cue Mochi to the rescue! All you have to do is tell Mochi where you live, what mood you're in
how much time you have and what time of day you're planning to head out and she'll plan the perfect outing for you
Mochi the Explorer will suggest between one and six stops (depending on how much time you have)
and then encourage you to 'Go touch grass!' by showing…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/cobaltspiral/mochi-the-explorer" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&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%2F9hrck22jlgy7pgsyw87a.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%2F9hrck22jlgy7pgsyw87a.png" alt="Mochi's sprite in idle state" width="150" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The open pieces making up Mochi the Explorer are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://ai.google.dev/gemma/docs/core/model_card_4" rel="noopener noreferrer"&gt;Gemma 4&lt;/a&gt;, who picks and describes Mochi’s recommendations. The deployed demo uses &lt;a href="https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/maas/google/gemma-4-26b-a4b-it" rel="noopener noreferrer"&gt;gemma-4-26b-a4b-it&lt;/a&gt; on &lt;a href="https://ai.google.dev/gemini-api/docs/pricing" rel="noopener noreferrer"&gt;Google AI Studio’s free tier&lt;/a&gt;. While developing the project locally, I ran &lt;a href="https://ollama.com/library/gemma4:e2b" rel="noopener noreferrer"&gt;gemma4:e2b&lt;/a&gt; through &lt;a href="https://ai.google.dev/gemma/docs/integrations/ollama?utm_source=deepmind.google&amp;amp;utm_medium=referral&amp;amp;utm_campaign=gdm&amp;amp;utm_content" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; with the same code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The geographic data is from &lt;a href="https://www.openstreetmap.org/" rel="noopener noreferrer"&gt;OpenStreetMap&lt;/a&gt;. In particular, &lt;a href="https://nominatim.org/" rel="noopener noreferrer"&gt;Nominatim&lt;/a&gt; turns a place name into coordinates, while &lt;a href="https://wiki.openstreetmap.org/wiki/Overpass_API" rel="noopener noreferrer"&gt;Overpass&lt;/a&gt; finds real places (parks, galleries, cafes, bookshops...) around them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For the frontend, I used React + Vite, &lt;a href="https://nostalgic-css.github.io/NES.css/" rel="noopener noreferrer"&gt;NES.css&lt;/a&gt; for the pixel graphics, and &lt;a href="https://leafletjs.com/" rel="noopener noreferrer"&gt;Leaflet&lt;/a&gt; for map visualisation. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I used &lt;a href="https://docs.gumdropstudio.app/" rel="noopener noreferrer"&gt;Gumdrop Studio&lt;/a&gt; to design the sprite, Mochi.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Mochi is deployed on Render's free tier.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;The design&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;I designed a fixed pipeline rather than a free-roaming agent. This is primarily because (small) AI models are not always reliable at deciding which tools to call, so my Python code runs the steps in a fixed order: (1) find the geocode, (2) find relevant places, (3) ask Gemma to &lt;strong&gt;_choose _&lt;/strong&gt;the most suitable spot(s), &lt;strong&gt;_explain _&lt;/strong&gt; why it's a good choice, and give fun and cheerful tips to the user.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Making a small model trustworthy&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Gemma is not allowed to come up with place names by itself. Each relevant candidate gets an ID (P1, P2...), Gemma answers with IDs, and my code looks up the real name and coordinates. This way, there is no risk of inventing a place that doesn't actually exist because an unknown ID is simply dropped. Its picks are also checked in code: duplicate tags are removed so a three-stop trip isn’t three of the same category, and missing stops are topped up from the candidate list.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Making the results less obvious&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;OpenStreetMap doesn’t record popularity, so I ranked places in tiers this way: independent places first, well-documented landmarks next, and chains last. Within a tier the choice is random, and each stop in a multi-stop trip comes from a different &lt;a href="https://taginfo.openstreetmap.org/keyshttps://taginfo.openstreetmap.org/keys" rel="noopener noreferrer"&gt;OpenStreetMap tag&lt;/a&gt;. The search widens its radius only when it finds less than three spots per tag (e.g., in the case of a really small town or a tag that's too specific for that area).&lt;/p&gt;

&lt;h3&gt;
  
  
  Problems that kept me up at night and how I solved them
&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%2Flsl59sc38gavfnxkrqod.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%2Flsl59sc38gavfnxkrqod.png" alt="Mochi's sprite smiling" width="150" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Turning off thinking 💭&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Gemma 4 models I chose think by default. My first test took 13 to 16 seconds and returned over 1,600 characters of reasoning for a one-sentence answer. Ollama has a &lt;code&gt;think: false&lt;/code&gt; switch that worked while developing locally. However, on Google’s hosted API, the OpenAI-compatible route ignored every setting I tried, until I tried the native endpoint with a minimal thinking level (&lt;code&gt;"thinkingConfig": {"thinkingLevel": "MINIMAL"},&lt;/code&gt;), which cut the same test to 1.2 seconds.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Learning to be kind to the Overpass servers 🙏&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I learned the hard way that public Overpass servers can be flaky. I kept getting timeouts and empty results, so I added retries, mirror servers, a private Overpass endpoint and an in-memory cache to avoid overwhelming Overpass. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;My hometown was suddenly in the middle of nowhere 😱&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At some point, I decided to test Mochi with my hometown, which is a relatively big city in Italy with loads of cosy spots to choose from. To my surprise, Mochi kept widening the search and coming up with places in towns nearby, but nothing in my hometown. After checking the coordinates, I discovered that Salerno, Italy, geocoded to the province rather than the actual city, which means Nominatim was returning the centre of the province 60 km from the city rather than its actual centre. I fixed it by telling Mochi to choose the first result that is tagged as a real settlement in OpenStreetMap (&lt;code&gt;SETTLEMENT_TYPES = {"city", "town", "village", "municipality", "suburb", "hamlet", "borough"}&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gemma freestyling 🎤&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gemma’s final message to the user kept making false claims (e.g., “a trio of pubs” when there was one bookshop), so I stopped asking it for that sentence. Mochi’s closing message is now a template filled with the real first stop’s name. The model keeps the part it handles reliably, and code handles the rest:&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;MESSAGES_ONE_STOP&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;I found {phrase} for you: head to {name}! Put your phone away and enjoy it.&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;How about {name}? It&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s {phrase} waiting for you. Phone in your pocket, off you go!&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;Your next stop is {name}. Leave the screen behind and go and see it!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;MESSAGES_MANY_STOPS&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;I found {phrase} for you. Start with {name}! Put your phone away and enjoy it.&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;Here&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s {phrase} for today, starting at {name}. Phone in your pocket, off you go!&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;Time for {phrase}! Begin at {name}, then follow the map. Leave the screen behind!&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;ul&gt;
&lt;li&gt;&lt;strong&gt;No events (for now), soz 🫤&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first iteration of Mochi the Explorer included SerpApi’s Google results to suggest actual events happening in the area at the time specified by the user. However, structured events appeared too unreliable to be worth keeping, with listicles being suggested instead of actual events (e.g., "10 things to do in Edinburgh this weekend"), while other events suggested were completely invented. Given the time constraints, I decided it wasn't sensible to try and include events, but I might add this as a feature in Mochi the Explorer 2.0!&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%2F5eikfn42uie43iq0ship.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%2F5eikfn42uie43iq0ship.png" alt="Mochi's sprite talking" width="150" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I'm new to coding in general, but especially a newbie when it comes to open source AI models. This was the first time I consciously engaged with the open source world. Here's a few reasons why I think open innovation matters for my project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Open data I could rank myself.&lt;/strong&gt; A closed maps API sorts by popularity, which is exactly what I didn't want Mochi to suggest to a local who's likely already familiar with the most popular spots in town. With OpenStreetMap, I control the ranking, so I could push chains down, randomise within tiers and spread picks across categories. That’s the idea at the core of the project, and a closed API wouldn’t have allowed me to make it justice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Control over how the model behaves.&lt;/strong&gt; Being able to turn thinking off locally and validate the model’s output against my own data made a small model dependable enough to ship.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;It's free!!!&lt;/strong&gt; 💰 Using Ollama locally, OpenStreetMap, and Render and Google AI Studio free tiers means the whole app costs nothing to run (and to use!).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Trade-offs.&lt;/strong&gt; In the deployed demo, Google hosts the model, so the city, mood and time of day go to Google rather than staying on infrastructure I control. With this setup, total privacy can only be achieved for the local setup. It’s a trade-off I made so the demo could be public and free.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Swappable models.&lt;/strong&gt; The whole LLM layer consists of three environment variables and a small function. I developed against local Ollama, then deployed against Google’s hosted Gemma without touching the app. Bigger or smaller model, local or hosted, it’s all a matter of a config change.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Touching grass with Mochi
&lt;/h2&gt;

&lt;p&gt;After being inside the whole week to work on Mochi the Explorer, I decided it was only fair I got to enjoy the fruits of my labour, so I put my touching grass future in Mochi's hands. She suggested two stops for my full-day cosy outing in Edinburgh:&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%2Fe071oessbay1e6y6ccte.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%2Fe071oessbay1e6y6ccte.png" alt="Screenshot of Mochi suggesting a cosy outing in Edinburgh" width="762" height="814"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, not even Mochi could do anything against my ADHD, so I ended up leaving the house too late to make it to any of the places suggested in time. But alas, reader, do not despair! I ended up having an adventure regardless, courtesy of Mochi:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;on my way to the cafè Mochi suggested I met Nelly, a 7-month old puppy.&lt;/li&gt;
&lt;li&gt;I bought a whimsical, beautifully illustrated (and quite huge) book about star signs from a charity shop that I'm going to use for my collages (more touching grass, am I right?)&lt;/li&gt;
&lt;li&gt;I finally got a coffee from a cafè I'd never tried before (not a chain!!!) and enjoyed a two-hour walk with my dog in the autumn sun.&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%2Fhlgwwzkwzylkevhyqmuj.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%2Fhlgwwzkwzylkevhyqmuj.png" alt="photo of dog in the sun at the park" width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What can I say? Sometimes Mochi works in unexpected ways. &lt;/p&gt;

&lt;p&gt;Let her guide you to your next IRL adventure 🌟&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 Render&lt;/strong&gt;: Mochi is deployed entirely on Render: the FastAPI backend runs as a web service and the React frontend as a static site, both connected to the same GitHub repo and redeploying on every push. The whole app runs on Render's free tier, and the secrets (model key, private map endpoint) live in Render's environment variables, away from the code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma 4 is what makes Mochi work. It reads the candidate places and picks the ones that fit the person's mood, time and time of day, and writes the "why" and "tip" for each stop. I ran &lt;code&gt;gemma4:e2b&lt;/code&gt; locally through Ollama while building, and deployed with &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; on Google AI Studio. Making it usable took real work: I found that Gemma 4 thinks by default (13 to 16 seconds for a one-sentence answer), switched thinking off in Ollama, and found a minimal thinking level on Google's native endpoint that cut the same test to 1.2 seconds. I also built guardrails around it, which is why it answers with IDs, and my code turns them into real places, which means it can't invent one.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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