This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass I've always been fascinated by the invisible layers of a place. You walk past a building every day and never wonder who lived there, what happened in that street, or why that monument exists. You take a photo, and all of that context stays invisible.
Frames of Truth is my attempt to fix that.
It's an Android app that takes a photo, reads its GPS coordinates from the EXIF metadata, and uses open-source AI models to tell you the story of the place where the photo was taken. Not the story of what's in the photo β the story of where you were standing when you took it.
Every smartphone photo carries hidden metadata: when it was taken, with what device, and β if geolocation was enabled β where. That last piece of information is a GPS coordinate. It tells you where the camera was, not necessarily what the camera was pointing at.
That distinction matters. If you point your phone at a distant hill and shoot from your backyard, the GPS gives your backyard. The photo has your perspective, not the hill's location.
Most apps ignore this. They geotag the photo with a generic address and move on. Frames of Truth doesn't. It treats the GPS coordinate as the start of an investigation.
Here's what happens when you load a photo:
If you want more, there's a second button that generates a deeper investigative report with six sections: Location, Surroundings, Wikipedia & Wikidata, Recent news (via GDELT), Photo metadata, and an Investigative hypothesis. The UI is in 7 languages: Italian, English, French, German, Spanish, Portuguese, Dutch.
For anyone who walks past places every day and never wonders what's behind them. For travelers who want context without opening ten tabs. For people who love going outside and want a reason to explore their own neighborhood. The app is the opposite of doomscrolling. You have to go outside to use it. You have to walk somewhere, point your camera at something, and come back with a real photo of a real place. The screen is the shortest part of the experience. The place is the point.
APK Download: Latest release on GitHub Install it on any Android device (7.0+). On first launch, open the βοΈ menu and enter your own API keys (Groq, Geoapify β both have free tiers).
.txt import feature
The full source code is available on GitHub under the MIT license:
Repository: github.com/vincenzodesanctis/frames-of-truth
| Layer | Technology |
|---|---|
| Mobile | Android (Kotlin) with Chaquopy for Python integration |
| Backend | Python (Flask) as a local HTTP server |
| Frontend | WebView with HTML/CSS/JS |
| AI Models | Open-weight via Groq (Qwen 3.8, GPT-OSS) and OpenRouter (Llama 3.3) |
| Geocoding | OpenStreetMap (Photon, Nominatim, Overpass, Wikipedia, Wikidata) |
| EXIF/HEIC | MetadataExtractor (Drew Noakes) |
The entire AI pipeline is built on open-weight models:
The choice of open-weight models wasn't an afterthought β it was the design constraint. I wanted to be able to swap providers without rewriting the app, and to avoid being locked into any single vendor.
I used Chaquopy to run Python 3.8 directly on the phone. Flask serves a local HTTP server on 127.0.0.1:5000, and a WebView loads the UI from there. It's a bit unusual, but it means I can reuse all my Python logic β geocoding, POI discovery, Wikipedia lookups, LLM calls β inside an Android app without rewriting anything in Kotlin.
HEIC support: Modern Android phones and iPhones save photos as .heic files by default. Python's PIL library doesn't read HEIC natively. My solution: detect HEIC files on the Kotlin side (reading the magic bytes ftyp), extract the EXIF metadata before converting, then convert the image to JPEG for the vision model. This way I preserve GPS coordinates even though the file format changes.
GPS redaction on Android 10+: Starting with Android 10, the OS redacts EXIF GPS data from any file read through a content URI β unless the app requests the ACCESS_MEDIA_LOCATION permission. Without it, every photo comes back with lat: null. With it, the coordinates come through intact. This one took me days to figure out, and required using MediaStore.setRequireOriginal() on the URI.
User-configurable API keys: Instead of hardcoding my keys, I built an in-app settings menu with a modal that lets users enter their own keys or import them from a .txt file. The keys are saved in SharedPreferences and pushed to the Python layer via a JavaScript Interface bridge. They never leave the device.
The challenge mentions "an open-weight model that works with no signal." Frames of Truth currently requires an internet connection for AI inference β but the architecture is designed to be portable to on-device models.
Here's how:
The reason I built it this way is that open-weight models are moving fast. Today they need a GPU in the cloud. Tomorrow they'll run on your phone. Frames of Truth is ready for either world.
Building this app on open-weight models wasn't just a cost-saving decision. It changed how I think about software.
No vendor lock-in. If Groq changes its pricing tomorrow or shuts down its free tier, I can swap to OpenRouter, Together AI, or a self-hosted model. The app code doesn't change. Only one API call changes.
Portability. Because the AI pipeline is provider-agnostic, the app can eventually run a small local model on the phone itself. Closed APIs make this impossible β you can't run GPT-4 on a phone, but you can run Llama 3.2 or Gemma 2.
Transparency. Anyone can read the pipeline end-to-end. They can see exactly which model processes the photo, what prompt is sent, and how the response is structured. There's no black box.
Community-driven improvement. The whole project relies on open data and open infrastructure: OpenStreetMap for geocoding, Wikipedia and Wikidata for context, GDELT for news. Every one of these is maintained by a global community of volunteers.
Cost control for indie developers. A solo developer can't afford to pay per-token for a closed API on a hobby project. Free tiers on Groq and OpenRouter make this kind of experiment possible.
If I had built this on a closed vision API, I would have been locked into: With open-weight models, I keep control. That's the whole point of open innovation.
I did not use DevRelay for this project, so there's no agent session to embed. The whole project was built iteratively by hand, testing each layer on a real Android device and debugging via Logcat.
Building this app taught me that open-source AI isn't just a cost-saving alternative to closed models. It's a different way of building software.
When I can see the model, swap the provider, and read the pipeline end-to-end, I feel like I'm actually in control of the product. I don't wake up one day to find that a service I depend on has changed its terms, or started charging 10x more, or shut down its free tier.
For an indie project like this, that kind of control is everything. The best part of building Frames of Truth was that it made me want to go outside and test it. Every time I took a photo, I learned something new about a place I thought I already knew.
That's what "Touch Grass" should mean: not abandoning technology, but using it to reconnect with the world. Open-source AI, done right, is a bridge β not a wall.
If you try the app, let me know what your neighborhood looks like through its eyes. π Built with β€οΈ for the Hacktoberfest Open-Source AI Challenge 2026.