This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass
What I Built
Here's a small question I've been thinking about: how many interesting things do we walk past every day without really noticing them?
A bird sitting on a tree. A flash of blue across a park. A bird with a call we've heard a hundred times but never identified.
We see these things, maybe get curious for a few seconds, and then move on.
Sometimes, we want to learn more, but identifying an unfamiliar bird isn't always easy. You might not know where to start, and searching through pictures of similar-looking species can be frustrating.
That's where BirdLens comes in💟
BirdLens is a web application that helps people explore birdlife through AI-assisted identification, a personal field journal, and small outdoor discovery challenges.
The idea is simple: upload a photograph of a bird, explore the AI's possible identification, and save the moment in your field journal.
It's not meant to turn birdwatching into another activity where you spend an hour staring at your phone. I want the technology to help you become curious about what's around you, then give you a reason to look away from the screen and observe a little more.
That felt like a natural fit for this week's Touch Grass theme.
Meet BirdLens
You can try the live application here:
🌿 Live demo: https://birdlens-7vm7.onrender.com/
💻 Source code: https://github.com/kumudasrip/BirdLens
I wanted the experience to feel approachable rather than like a complicated machine-learning demo. You shouldn't need to understand image classification to get started.
The interface follows a simple flow: upload a photo, explore the results, and save your discovery.
1. Give a bird a name
The main feature is AI-assisted bird identification.
Upload a bird photograph, and BirdLens sends it to a hosted image-classification model. The application displays possible species matches along with their model scores.
For example, while testing BirdLens with a peacock photograph, the model returned Peacock with a 96.9% model score.
Seeing the result appear in my own application was a particularly satisfying moment. It wasn't just a model running in a separate demo anymore. I had connected the inference process to my own frontend and backend, and the result was appearing in the interface I had built.
Of course, a high model score doesn't guarantee that an identification is correct. The predictions are suggestions, not definitive answers.
2. Keep a little field journal
I also wanted somewhere for discoveries to go after identification.
That's why BirdLens has a personal field journal. Each entry can include a bird name, photograph, date, optional location, and personal notes.
Maybe you spotted a bird in a nearby park. Maybe you noticed its colour, watched it searching for food, or simply liked the way it looked.
You can record those details and build a small collection of sightings over time.
The journal also displays the total number of sightings and the number of different species recorded. Saved entries appear in a responsive card layout, making it easier to revisit them later.
The journal uses browser local storage, so there's no account creation or database setup involved. Your saved sightings remain in that browser on that device rather than syncing automatically to an online account.
3. Make going outside the point
BirdLens also includes Nature Quests: short, beginner-friendly prompts that encourage you to pay closer attention to your surroundings.
They might encourage you to notice bird behaviour, look for different colours, or observe what is happening around you.
These quests currently use predefined prompts rather than AI-generated challenges. I wanted to start with something lightweight that supports the project's main idea: getting outside and noticing things you might otherwise overlook.
The goal isn't to collect the most sightings or spend the longest time using an app. It's to find a small reason to explore.
How I Built It
I built BirdLens using a straightforward web stack:
- HTML, CSS, JavaScript and Bootstrap 5 for the frontend.
- Python and Flask for the backend.
- Hugging Face Spaces and Gradio Client for hosted model inference.
- Browser local storage for the field journal.
- Render for deploying the application.
The architecture is intentionally simple.
When someone uploads a photograph, the frontend sends it to a Flask API endpoint. The backend forwards the image to my Hugging Face Space, which runs the bird-classification model. The resulting predictions are returned to the frontend and displayed to the user.
The journal works separately from the AI identification flow. Once the user has a bird name, they can save the sighting locally, including when the AI service is temporarily unavailable.
This separation became especially useful while I was building and debugging the project.
Choosing the AI model
BirdLens currently uses the prithivMLmods/Bird-Species-Classifier-526 image-classification model, accessed through my Hugging Face Space.
I chose this approach because an image-classification model is a natural fit for the problem. The input is a photograph, and the output is a ranked set of possible species.
The model is available through an open-weight ecosystem, which gives the project a more flexible starting point than building around a single proprietary vision API.
I also wanted to keep the inference integration behind a small backend API. That makes the frontend simpler and gives me a place to handle authentication, errors, and future changes to the model provider.
The current implementation uses hosted inference. It does not run the model directly on the user's device, and it depends on the availability and usage limits of the Hugging Face Space.
The Part That Didn't Work Immediately
Getting the model to make predictions was only part of the challenge. Getting the entire application to work reliably was another story.
One issue appeared when I started testing the integration through my website.
The Hugging Face Space could identify a bird when I used its own interface, but requests from BirdLens sometimes failed with a ZeroGPU usage-limit error.
At first, it was confusing. The model worked, the image was valid, and the frontend appeared to be doing its job. Yet the application couldn't consistently get a result.
The important lesson was to stop treating every failure as a frontend problem.
I checked the Flask terminal logs and traced the request through the application. That helped me distinguish a request reaching the backend from a request successfully completing inference.
I then configured Hugging Face authentication through an environment variable instead of placing a token in the frontend. After that change, I was able to test multiple bird photographs successfully.
That wasn't the end of the deployment work, either. The local application and the Render deployment behaved differently because the hosted environment had its own configuration and dependency requirements. Checking the deployment logs helped me identify and fix a Gradio Client configuration error.
Eventually, the complete flow worked on the live application: upload a photograph, receive predictions, edit the bird name, and save the sighting.
This was a useful reminder that a successful model demo and a working application are two different things. The integration, error handling, authentication, and deployment all matter.
Taking BirdLens Outside: From a Nature Quest to a Real Sighting 🌿
I didn't want BirdLens to be just another AI demo that I built, tested in my browser, and left online.
One of its main features is Nature Quests, so I decided to use the app the way I had imagined someone using it in real life: start with a small challenge, head outside, and see what I discover.
I opened BirdLens on my phone and generated today's quest:
Listen carefully for two minutes. Can you distinguish different bird calls?
That gave me a reason to pause and pay attention to the birds around me. While observing them, I noticed one that caught my attention because of its unusually long, curved beak. It looked unfamiliar to me, and I wanted to know more about it.
So I took a photograph and opened BirdLens on my phone.
I uploaded the image, and the classifier returned Tropical Kingbird as its top prediction, with a model score of 24.7%. Other suggestions included Malagasy White Eye and Malachite Kingfisher, with much lower scores.
The result was interesting, but the relatively low top score also reminded me not to treat the prediction as a confirmed identification. I hadn't independently verified the species, so I kept the result as a suggestion rather than a definitive answer.
I then saved the sighting in my BirdLens field journal, adding a note about what had caught my attention:
“Its beak was so long and it looked very new to me.”
That small observation was the reason I wanted to identify the bird in the first place. The AI gave me a starting point, while the field journal let me preserve the moment and my own thoughts about it.
My outdoor experiment
- Nature Quest: Listen carefully for two minutes and try to distinguish different bird calls.
- Observation: A bird with a long, curved beak that I hadn't noticed before.
- BirdLens prediction: Tropical Kingbird — 24.7% model score.
- Field journal: One sighting saved, with my observation recorded in the notes.
What I liked most was how the experience connected the different parts of BirdLens. A simple quest encouraged me to observe my surroundings, that observation made me curious about a bird, and the AI gave me somewhere to start exploring.
The prediction itself wasn't conclusive, and that's an important part of the experience too. AI can help us investigate what we see, but it shouldn't replace careful observation or independent verification.
BirdLens wasn't just something I built to identify birds. I finally used it for the reason I built it: to turn a little curiosity outdoors into a discovery worth remembering.
Why Open Innovation Matters Here
This is one of the most interesting parts of building BirdLens for me.
An AI-powered bird identifier could be built around a proprietary vision API. That might be a perfectly reasonable engineering choice, but it would also tie the application to that provider's model access, API behaviour, pricing, and available features.
Using an open-weight model gives me another option.
I can explore how the classifier behaves, evaluate its results on different bird photographs, and investigate alternative models as the project develops. The model is not simply an opaque feature that I have no choice but to accept as-is.
It also makes experimentation more accessible. I can build the application around a model that is already available, test its capabilities, and decide where it works well and where it needs improvement.
There is an important distinction, though: open-weight does not automatically mean offline, free forever, or completely private.
BirdLens currently sends photographs to a hosted inference service. Its availability depends on that service's usage limits, and the current implementation does not provide local inference.
I see this as a starting point rather than a limitation I should hide. A future version could investigate local inference, alternative compatible models, or other deployment options. Those changes would need to be evaluated for model quality, hardware requirements, latency, and cost.
For this version, the main benefit is having a working AI integration built around a model I can investigate and potentially replace, rather than committing the entire application to one closed AI API.
What I Learned
Building BirdLens reminded me that a project doesn't become complete just because its main feature works once.
I learned how the pieces of an AI-powered web application fit together: the frontend handles the user's interaction, the backend manages requests, the inference service runs the model, and the application needs to handle failures at every boundary.
I also learned the importance of reading logs rather than guessing. The ZeroGPU issue and the deployment configuration error were different problems, even though both initially appeared to the user as a failed identification.
On the product side, I found myself thinking about what should happen when AI is unavailable. Rather than blocking the entire experience, BirdLens lets users enter a bird name themselves and still save the sighting. That keeps the field journal useful even when the model cannot provide an answer.
And perhaps most importantly, I had to think about how the application should encourage people to use it.
The purpose isn't to keep someone browsing bird cards indefinitely. It's to help them become curious about the birds around them and make that curiosity a reason to spend more time outdoors.
What's Next?
BirdLens is working as a deployed application, but there is still room to improve it.
Some things I'd like to explore next include:
- Expanding the educational information available for identified species.
- Testing the classifier across more bird species, photographs, and lighting conditions.
- Improving identification reliability and communicating uncertainty clearly.
- Exploring alternative inference options and their trade-offs.
- Making the experience more accessible.
I'd especially like to evaluate how useful the predictions are with photographs taken in everyday outdoor conditions, rather than relying only on a few successful test images.
Try BirdLens
🌿 Live demo: https://birdlens-7vm7.onrender.com/
💻 GitHub repository: https://github.com/kumudasrip/BirdLens
If you try it, I'd love to know which bird you tested it with and how well the predictions matched what you expected. Feedback about the identification experience, journal, or outdoor challenges would be especially useful.
BirdLens is a small project, but I like the idea behind it: technology can help us pay more attention to the world rather than simply giving us another reason to stay online.
Sometimes, the most interesting discovery is waiting just outside.
Look closer. Discover more. 🌿










Top comments (3)
Please try BirdLens and share your suggestions:
Live Demo
🤩🤩
tr.ee/dev-to