← Back to Posts

Telegram Artwork Visualizer Bot: Art in Any Room


“Can you solve this with AI somehow?”

My partner paints. But she doesn’t have a studio. No clean walls, no good lighting. When she finishes a painting, buyers can’t imagine how it would look in their home.

47 commits and one frustrating evening later, I had a working Telegram bot.

Bot interface showing room presets
Bot interface showing room presets

The First 4 Hours

I started on December 28th, around 8pm. The idea was simple: upload artwork, pick a room, generate a visualization. I used Claude Code for everything. Described what I wanted, Claude wrote the code.

By midnight, I had a working prototype. Cloudflare Workers, Telegram bot, image generation. It actually worked. I went to bed thinking this would be a quick weekend project.

Then Everything Broke

The next day, I wanted to improve the image quality. I was using Imagen 3 from Google’s Vertex AI. The results looked off. Not terrible, but not what I expected. The artwork didn’t blend naturally into the rooms.

I spent the next 3-4 hours debugging. Tweaking prompts. Adjusting parameters. I was convinced something was wrong with my implementation. Maybe the image format? The resolution? The prompt structure?

At some point I genuinely thought: this isn’t going to work.

Then I realized I was using the wrong API entirely. I needed Gemini 3 Pro Image, not Imagen 3. Different model, different endpoint, completely different results.

Switched to Gemini. Still didn’t work. Had to dig through Google Cloud Console to enable something I’d missed. One config change later, everything clicked. The images looked exactly how I wanted them.

And here’s the thing: the switch to Gemini accidentally unlocked a feature I hadn’t planned. Custom background upload. Users can now send their own room photo instead of using presets. That wouldn’t have been possible with Imagen.

The Next Problem

The bot worked. But sometimes it didn’t respond. Users would send an artwork, wait, and nothing would happen. Looking at the logs: timeout errors. 524s everywhere.

The problem: Grammy, a bot framework I was using, has a 30-second CPU limit. Gemini needs up to 60 seconds for image generation. The math doesn’t work.

I thought I’d have to find a different approach entirely. Maybe queue the requests somewhere, process them async, add complexity.

But then I found Durable Objects.

The Elegant Fix

Cloudflare Durable Objects have a 5-minute CPU limit instead of 30 seconds. The architecture change was surprisingly clean: Worker receives the request in under 50ms, fires it to a Durable Object, returns immediately. The Durable Object handles the slow Gemini call, stores the session in SQLite, sends the Telegram response when done.

1055 lines added, 710 removed. Grammy gone. Five handler files deleted. The migration took about 2 hours, split into 5 phases. Each phase deployed and tested before the next.

This was honestly the most interesting part of the project. I expected it to be a nightmare. It wasn’t.

Final result: artwork visualized in a living room
Final result: artwork visualized in a living room

What I Learned

I should have tested the architecture limits earlier. Grammy’s 30s limit wasn’t visible during local testing. Only hit it with real API calls.

Same with SQLite storage limits. Cloudflare’s SQLite has a 128KB limit per value. I was storing images as base64. Exploded immediately. Had to switch to Telegram file_ids instead.

The API choice had downstream effects I didn’t expect. Choosing the wrong one cost me 3-4 hours. Choosing the right one gave me a feature I hadn’t planned.

And phased migrations work. Breaking the Durable Objects migration into 5 steps instead of one big rewrite meant I could catch problems early.

What’s Next

The bot works. My partner uses it. Currently whitelist-only. Will I make it public? Maybe. First I want to test if the quality holds up for different art styles.


Code isn’t public, but if you have questions: Twitter/X