DEV Community

ninefyi
ninefyi

Posted on

tripkit: Gemma writes the caption, but it guessed the wrong country

Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle Submission 💸

This is a submission for the Hacktoberfest Open-Source AI Challenge: Week 2, "Side Hustle"

What I Built

tripkit is a small web page. You give it a photo, and optionally the place and a short note. It gives back a title, the place, a one-sentence caption and at least three hashtags, in Thai by default, ready to paste into your own social account. A local Gemma 3 12B does the writing, so the photo stays on the laptop.

The theme asks for something someone would pay for. I will say this up front: I do not know that anyone would. It is free to use, I did not ask anyone for a price, and nobody but me has tried it. My guess for a future payer is someone who posts places for income, such as a travel page admin or a homestay owner, but that is a guess and I have not asked one.

What I can report is the part I tested: what the model gets right and wrong when you ask it to caption a photo.

Demo

The page with a public photo: the AI guess is wrong, the typed place and the post kit are below

This is the page with a public photo of the Santichaiprakarn Throne Hall in Bangkok. I typed the place and the note "ตอนเย็น" ("in the evening"), and the result is below them. I also pressed the guess button first: it said พระที่นั่งอรุณราชโอรส, a different building, with a warning that it may be wrong, and it did not put that into the Place box. (Photo by Dominic Nelson, CC BY-SA 4.0, via Wikimedia Commons, resized; the screenshot is shared under the same license.)

The one photo I evaluated is a group photo taken at an event, with about fourteen people in it. I am not showing it, because I do not have their consent. This is what the page returned for it, with the Place left empty and a note naming the event, "ถ่ายรูปหมู่ที่งาน Microsoft AI Tour" ("group photo at the Microsoft AI Tour"). My coding assistant wrote that note from the sign in the photo, and I left it unchanged:

Field Result
Title ทีม Microsoft AI Tour
Place (empty, with a warning "no Place given")
Caption รวมตัวถ่ายรูปหมู่ที่งาน Microsoft AI Tour!
Hashtags #MicrosoftAITour #ถ่ายรูปหมู่ #AI

I marked it "post as is". Most of it is that note handed back. What the photo added was the word "ทีม" (team), which is the model's assumption about those people, and the tag #AI is generic.

The page also has a button, "not sure where this is? let the AI guess". For this photo it answered Impact Arena, Muang Thong Thani, a venue in Thailand, and labelled its confidence "high". The photo was taken at Singapore Expo.

Code

https://github.com/ninefyi/hf26challenge-week2 (MIT). The page (app.py), the generator (tripkit/generate.py), the rules a result must meet (tripkit/validate.py), the evaluation script (eval.py) and 29 unit tests. The model runs through Ollama, which is not part of the repo.

How I Built It

1. The first design was wrong. I had one caption box, and I asked Gemma to copy the place name out of it. I wrote a check that the place must appear word for word in the caption, to stop it inventing places. On six public photos from Wikimedia Commons the model returned the whole caption as the place: "พระที่นั่งสันติไชยปราการ กรุงเทพ ตอนเย็น" ("... Bangkok, in the evening"), and for two photos whose caption named no place at all it returned the description as if it were a place name. The check passed every time, because a sentence is always inside itself. Only one of six was correct.

2. Two fields. Now there is a Place box and a Note box. The Place on the result is whatever you typed, passed through unchanged, and it is empty with a warning if you typed nothing. The model never writes it. An invented place name can no longer reach the result, by construction and not by hope.

3. The guess is a suggestion, not an answer. I still wanted help for photos where you do not remember the place, so there is a separate button. It shows the guess marked "AI guess, may be wrong". It never fills the Place box by itself and never reaches the title, caption or hashtags until you press "use this". On the same six public photos the guess was clearly right once, wrong with the label "high" three times, in the right area once (it said Maya Bay for a photo of Phi Phi Lay; the bay is on that island, but I did not check that the photo shows it), and declined once. The Singapore Expo guess above is a fourth wrong "high". So the page does not show the model's confidence at all. In my runs it was "high" whether the guess was right or wrong.

4. Smaller things Gemma did. Four of six titles came back in English although I asked for Thai. After I told it to write everything in the language I chose, one of six still did. Once it ended a caption with "ค่ะ", a particle that assumes the speaker is a woman. The prompt now forbids it. Every result is checked for at least three hashtags, each starting with #, and a caption on a single line of at most 120 characters, with up to two retries. No result needed a retry in any of my runs.

5. Photos are cleaned before the model sees them. Each image is rotated, shrunk to 1024 pixels and re-encoded without EXIF, so GPS data never reaches the model or my evaluation log. (Gradio keeps its own temporary copy of the uploaded original, so this is not a guarantee that the file is never stored on the machine.)

6. Time. On a 16 GB M1 Pro, a result takes about 14 seconds and a guess 8 to 19 seconds more. My one-photo run took 33 seconds in total, and the six-photo run averaged 27 seconds per photo.

What I did not do, and what that means. I planned an evaluation of 20 of my own photos, judged by a first user, with a bar I wrote down before running anything: at least 70% accepted without edits and zero invented places. I then cut it to one photo, judged by me, because I wanted to submit early. With one photo the rate can only be 0% or 100%, so the bar was not tested, and my script reports it as "NOT TESTED" rather than "met". I also did not try a Thai-specific model. The one I looked at, iApp's OpenThai 2.0 (27B), has a 17 GB file in the smallest form its page lists, which does not fit this machine's 16 GB. A search for "thai" on Ollama's site turned up no Thai-focused model, and I did not import one myself.

Why Open Innovation Matters

Trip photos have faces in them, and often GPS coordinates. Running Gemma on my own machine means none of that goes to a server I do not control, and a result costs nothing, which is the only way a free tool can exist. Being able to read and change what the model is allowed to do mattered too: the Place box, the EXIF stripping, the hashtag rules and the "never show confidence" decision are all things I could decide because nothing was hidden behind an API.

Where closed might have done better: place recognition. A hosted model with more landmark knowledge may well have known Singapore Expo. I did not test one, so I cannot say.

My Agent Session

I built this with Claude Code. It wrote a large share of the code and the first drafts of this post, so the post is marked as AI-assisted. I made the product decisions: two fields, the guess as a suggestion, a free tool, and cutting the evaluation to one photo. I am not embedding the session transcript.

My First User

Me. I was the Traveller and the judge for the one photo. I did not ask for a price, so I have no answer to "would they pay", and nothing to report about what a user would ask for next.

Prize Categories

  • Best Use of Gemma: Gemma 3 12B does the image reading and the writing, locally, and the post reports where it fails.

Top comments (0)