<?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: Jahongir Tajiboyev</title>
    <description>The latest articles on DEV Community by Jahongir Tajiboyev (@jahongir_tajiboyev_b806d0).</description>
    <link>https://dev.to/jahongir_tajiboyev_b806d0</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%2F4084417%2F352ca810-3507-4909-a18a-32dcc7213d00.png</url>
      <title>DEV Community: Jahongir Tajiboyev</title>
      <link>https://dev.to/jahongir_tajiboyev_b806d0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jahongir_tajiboyev_b806d0"/>
    <language>en</language>
    <item>
      <title>How I built an Open Budget Uzbekistan Telegram bot with AI captcha solving</title>
      <dc:creator>Jahongir Tajiboyev</dc:creator>
      <pubDate>Wed, 19 Aug 2026 06:38:34 +0000</pubDate>
      <link>https://dev.to/jahongir_tajiboyev_b806d0/how-i-built-an-open-budget-uzbekistan-telegram-bot-with-ai-captcha-solving-4l3m</link>
      <guid>https://dev.to/jahongir_tajiboyev_b806d0/how-i-built-an-open-budget-uzbekistan-telegram-bot-with-ai-captcha-solving-4l3m</guid>
      <description>&lt;p&gt;Open Budget Uzbekistan is a government platform where citizens vote &lt;br&gt;
for public initiative projects (parks, roads, lighting, etc.) in &lt;br&gt;
their districts. Each year, thousands of projects compete for budget &lt;br&gt;
funding based on public votes.&lt;/p&gt;

&lt;p&gt;I built a Telegram bot that automates the voting process and rewards &lt;br&gt;
participants with UZS (Uzbek Som) for each vote they submit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;The Open Budget portal requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SMS verification for every vote&lt;/li&gt;
&lt;li&gt;CAPTCHA solving on each submission&lt;/li&gt;
&lt;li&gt;Manual interaction with the website&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes bulk or assisted voting extremely tedious. Our bot solves &lt;br&gt;
all of this automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Python 3.11&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aiogram 3.x&lt;/strong&gt; — async Telegram bot framework&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;aiosqlite&lt;/strong&gt; — async SQLite with WAL mode&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;aiohttp&lt;/strong&gt; — async HTTP client for API calls
User → Telegram Bot → Our API Gateway → Open Budget API ↓ Gemini AI (CAPTCHA) ↓ SQLite DB (rewards)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. AI-Powered CAPTCHA Solving
&lt;/h3&gt;

&lt;p&gt;We use Google Gemini Vision API to automatically read and solve &lt;br&gt;
image CAPTCHAs from the Open Budget portal:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
python
async def solve_captcha(image_bytes: bytes) -&amp;gt; str:
    model = genai.GenerativeModel("gemini-1.5-flash")
    response = await model.generate_content_async([
        "Read the CAPTCHA text from this image. "
        "Return only the text, nothing else.",
        {"mime_type": "image/png", "data": image_bytes}
    ])
    return response.text.strip()
2. Reward System
Every user who votes receives UZS rewards directly to their Uzcard/Humo bank cards. Admins configure reward amounts via the built-in admin panel.

3. Admin Panel
Bot owners get a full control panel via /admin:

Connect API key
Set target project ID
Configure reward per vote
Approve/reject withdrawal requests
Broadcast messages to all users
Download TXT reports
4. Persistent Storage on Railway
One challenge was Railway's ephemeral filesystem. We solved it with Railway Volumes and an environment variable:

python


DB_PATH = os.getenv("DATABASE_PATH", "client_bot.db")
async def get_db_conn():
    db_dir = os.path.dirname(DB_PATH)
    if db_dir:
        os.makedirs(db_dir, exist_ok=True)
    return await aiosqlite.connect(DB_PATH)
Set DATABASE_PATH=/data/client_bot.db and mount a Volume — data persists across deployments!

Open Source
The full source code is available on GitHub:

openbudget-uz-bot

Includes:

Complete bot source code
INSTALL.md — step-by-step setup guide
API.md — API endpoint documentation
.env.example — configuration template
MIT License
Demo
Bot: @Budjetuz2026_bot
API Keys: @Budjetuz2026_Bot

Lessons Learned
Gemini timeouts — ISP throttling in Uzbekistan causes slow responses. Set timeout to 8+ seconds.
Railway volumes — Always mount a volume for SQLite, otherwise data resets on every deploy.
Async SQLite — Use aiosqlite with WAL mode for concurrent reads without blocking.
- **Google Gemini AI** — for automatic CAPTCHA solving
- **Railway.app** — cloud deployment with persistent volumes

## Architecture Overview
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>python</category>
      <category>telegram</category>
      <category>opensource</category>
      <category>api</category>
    </item>
  </channel>
</rss>
