# 🏗️ Architecture Documentation - AI Quiz Bot System design, API specifications, and data structures. ## 📑 Table of Contents - [System Architecture](#system-architecture) - [API Specifications](#api-specifications) - [Data Structures](#data-structures) - [Request/Response Examples](#requestresponse-examples) - [Error Handling](#error-handling) - [Scalability Considerations](#scalability-considerations) ## 🏗️ System Architecture ### High-Level Overview ``` ┌─────────────────────────────────────────────────────────────┐ │ Telegram Users │ └──────────────────────────┬──────────────────────────────────┘ │ ↓ ┌─────────────────────────────────────────────────────────────┐ │ Telegram Bot API (python-telegram-bot) │ │ - Polling for messages │ │ - Sending polls and messages │ │ - File download capability │ └──────────────────────────┬──────────────────────────────────┘ │ ↓ ┌─────────────────────────────────────────────────────────────┐ │ AI Quiz Bot (bot.py) │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Message Handlers │ │ │ │ - handle_file() [Images/PDFs] │ │ │ │ - handle_text() [Text messages] │ │ │ │ - Commands (/start, /help) │ │ │ └────────────────┬─────────────────────────────────────┘ │ │ │ │ │ ┌────────────────┴─────────────────────────────────────┐ │ │ │ Processing Layer │ │ │ │ - extract_text_from_image() │ │ │ │ - extract_text_from_pdf() │ │ │ │ - parse_num_questions() │ │ │ └────────────────┬─────────────────────────────────────┘ │ │ │ │ │ ┌────────────────┴─────────────────────────────────────┐ │ │ │ Generation Layer │ │ │ │ - generate_quiz_questions() │ │ │ │ - Quiz JSON parsing │ │ │ └────────────────┬─────────────────────────────────────┘ │ │ │ │ │ ┌────────────────┴─────────────────────────────────────┐ │ │ │ Delivery Layer │ │ │ │ - send_quiz_poll() │ │ │ │ - Completion messages │ │ │ └────────────────┬─────────────────────────────────────┘ │ └──────────────────────────┬──────────────────────────────────┘ │ ┌──────────┴──────────┐ ↓ ↓ ┌──────────────────┐ ┌──────────────────┐ │ Ollama Cloud API │ │ External APIs │ │ (REST HTTP/HTTPS)│ │ Telegram API │ │ │ │ │ │ - /api/chat │ │ (https) │ │ Vision Model │ │ │ │ Chat Model │ │ │ └──────────────────┘ └──────────────────┘ ``` ### Component Layers #### 1. **Telegram Integration Layer** - Receives messages via polling - Handles file downloads - Sends messages and polls - Manages message edits #### 2. **Message Handler Layer** - Routes incoming messages to appropriate handlers - Validates message type (file vs text vs command) - Extracts metadata (chat ID, user ID, caption, etc.) - Shows loading messages #### 3. **Processing Layer** - Extracts text from images (Vision API) - Extracts text from PDFs (PyPDF2) - Parses user input (question count) - Handles errors and retries #### 4. **Generation Layer** - Sends text to Chat API - Manages prompts and system instructions - Parses JSON responses - Validates question format #### 5. **Delivery Layer** - Sends each question as a Telegram poll - Manages rate limiting (1-second delays) - Sends completion messages - Logs delivery success/failure ## 🔌 API Specifications ### Ollama Cloud API **Base URL**: `https://ollama.com` **Authentication**: Bearer Token (in Authorization header) #### Endpoint: POST /api/chat **Purpose**: Vision analysis, chat completion, JSON generation **Request Headers**: ``` Authorization: Bearer {OLLAMA_API_KEY} Content-Type: application/json ``` **Request Body**: ```json { "model": "ministral-3:8b", "messages": [ { "role": "user", "content": "Text or prompt", "images": ["base64_encoded_image"] // Optional } ], "stream": false, "format": "json" // Optional, ensures JSON output } ``` **Response**: ```json { "model": "ministral-3:8b", "created_at": "2026-02-01T10:00:00Z", "message": { "role": "assistant", "content": "Response text or JSON" }, "done": true, "total_duration": 1234567, "load_duration": 567, "prompt_eval_count": 50, "eval_count": 100, "eval_duration": 100000 } ``` **Parameters**: | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | model | string | Yes | Model name (e.g., "ministral-3:14b") | | messages | array | Yes | Array of message objects | | stream | boolean | No | Default: false (we don't use streaming) | | format | string | No | "json" to ensure JSON output | **Message Object**: ```json { "role": "user" | "assistant" | "system", "content": "Text content", "images": ["base64_string"] // Optional, only for vision models } ``` ### Telegram Bot API **Used Methods**: #### 1. send_poll ```python await bot.send_poll( chat_id=12345, question="Question text?", options=["A", "B", "C", "D"], type="quiz", correct_option_id=1, is_anonymous=False ) ``` #### 2. send_message ```python await bot.send_message( chat_id=12345, text="Message text", reply_to_message_id=67890 ) ``` #### 3. edit_message_text ```python await message.edit_text("Updated text") ``` #### 4. get_file ```python file = await bot.get_file(file_id) file_bytes = await file.download_as_bytearray() ``` ## 📊 Data Structures ### Question Object (JSON) ```json { "question": "What is the capital of France?", "options": ["London", "Berlin", "Paris", "Madrid"], "correct_option_id": 2 } ``` **Fields**: - `question` (string): Question text (max 300 chars in Telegram) - `options` (array): Array of option strings (max 10 options in Telegram) - `correct_option_id` (number): Index of correct option (0-based) ### Questions Array ```json [ { "question": "Question 1?", "options": ["A", "B", "C", "D"], "correct_option_id": 0 }, { "question": "Question 2?", "options": ["A", "B", "C", "D"], "correct_option_id": 1 } ] ``` ### Image Object **Format**: Base64-encoded JPEG/PNG/WebP **Usage in API**: ```json { "role": "user", "content": "Describe this image", "images": ["iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="] } ``` ## 📤 Request/Response Examples ### Example 1: Image Analysis **User Action**: Send image with caption "5" **Request to Ollama**: ```bash POST https://ollama.com/api/chat Authorization: Bearer 830f2fd6fedc491ba49c91a0709c94d9.4Z84I1pRSwd8iPDT1J4Tfu6c Content-Type: application/json { "model": "ministral-3:8b", "messages": [ { "role": "user", "content": "Just transcribe all the text in the image in details. Output only the text, nothing else.", "images": ["base64_encoded_image_here..."] } ], "stream": false } ``` **Response from Ollama**: ```json { "message": { "role": "assistant", "content": "The extracted text from the image goes here...\nThis is the text the bot analyzed." }, "done": true } ``` **Bot Processing**: 1. Receives extracted text 2. Parses caption: 5 questions 3. Calls quiz generation ### Example 2: Quiz Generation **Request to Ollama**: ```bash POST https://ollama.com/api/chat Authorization: Bearer 830f2fd6fedc491ba49c91a0709c94d9.4Z84I1pRSwd8iPDT1J4Tfu6c Content-Type: application/json { "model": "ministral-3:14b", "messages": [ { "role": "system", "content": "You are a strict Quiz Generator.\nRules:\n1. Output ONLY the questions and answers.\n2. Do NOT provide any conversational text..." }, { "role": "user", "content": "Based on the text I provide, generate 5 multiple-choice quiz questions.\n\nYou must output valid JSON only...\n\nText to analyze:\nThe extracted text goes here..." } ], "stream": false, "format": "json" } ``` **Response from Ollama**: ```json { "message": { "role": "assistant", "content": "[{\"question\":\"Q1?\",\"options\":[\"A\",\"B\",\"C\",\"D\"],\"correct_option_id\":0},{\"question\":\"Q2?\",\"options\":[\"A\",\"B\",\"C\",\"D\"],\"correct_option_id\":1}]" }, "done": true } ``` **Bot Processing**: 1. Receives JSON string 2. Cleans markdown if present 3. Parses JSON 4. Validates each question 5. Sends as Telegram polls ### Example 3: Send Quiz Poll to Telegram **Request to Telegram**: ```bash POST https://api.telegram.org/bot7319290683:AAFpfIEGCZGOky3OOB2V-xcn8rq8pc7TEUQ/sendPoll Content-Type: application/json { "chat_id": 123456789, "question": "What is the capital of France?", "options": ["London", "Berlin", "Paris", "Madrid"], "type": "quiz", "correct_option_id": 2, "is_anonymous": false } ``` **Response from Telegram**: ```json { "ok": true, "result": { "message_id": 12345, "chat": {"id": 123456789}, "poll": { "id": "poll123", "question": "What is the capital of France?", "options": [ {"text": "London", "voter_count": 0}, {"text": "Berlin", "voter_count": 0}, {"text": "Paris", "voter_count": 0}, {"text": "Madrid", "voter_count": 0} ], "type": "quiz", "total_voter_count": 0, "is_closed": false, "is_anonymous": false, "allows_multiple_answers": false, "correct_option_id": 2 } } } ``` ## 🛡️ Error Handling ### API Error Types | Error | HTTP Code | Cause | Bot Response | |-------|-----------|-------|-------------| | Invalid API Key | 401 | Wrong/expired OLLAMA_API_KEY | "حصل مشكلة" + retry | | Model Not Found | 404 | Invalid VISION_MODEL or CHAT_MODEL | "Model not found" error | | Rate Limited | 429 | Too many requests | Retry with backoff | | Timeout | 504 | API slow | "API timeout" message | | DNS Error | N/A | Wrong OLLAMA_HOST | Network error | ### Error Flow ``` Error Occurs ↓ Logger.error() called with details ↓ Exception raised/caught ↓ IF API Error: Notify user with friendly message ELSE IF Validation Error: Show specific error ELSE: Generic "حصل مشكلة" message ↓ Message edit/delete if needed ↓ Continue waiting for next user input ``` ### User-Facing Error Messages ```python # Network errors "❌ نوع ملف مش مدعوم!" # Processing errors "❌ مش قادر استخرج نص كافي" # Generation errors "❌ مش قادر اعمل اسئلة من النص ده" # Validation errors "❌ النص قصير شوية!" # Generic errors "❌ حصل مشكلة: {error_details}" ``` ## 📈 Scalability Considerations ### Current Limitations 1. **Sequential Processing** - Each question sent with 1-second delay - Multiple users processed sequentially - No concurrent request batching 2. **Memory Usage** - Entire image/PDF loaded into memory - Full text stored in variables - No streaming or chunking 3. **Rate Limiting** - No rate limiting per user - Telegram has built-in limits - Ollama API has unknown limits ### Scaling Improvements #### 1. Add Request Queuing ```python import asyncio from asyncio import Queue class BotQueue: def __init__(self, max_concurrent=3): self.queue = Queue() self.processing = set() async def process(self, user_id, request): await self.queue.put((user_id, request)) await self._process_queue() ``` #### 2. Add Redis Caching ```python import redis cache = redis.Redis(host='localhost', port=6379) async def generate_quiz_questions_cached(text, num_questions): cache_key = f"quiz:{hash(text)}:{num_questions}" cached = cache.get(cache_key) if cached: return json.loads(cached) # Generate new questions questions = await generate_quiz_questions(text, num_questions) cache.setex(cache_key, 3600, json.dumps(questions)) # 1 hour TTL return questions ``` #### 3. Add Database Logging ```python import sqlite3 def log_request(user_id, request_type, status): conn = sqlite3.connect('bot.db') c = conn.cursor() c.execute('''INSERT INTO requests (user_id, type, status, timestamp) VALUES (?, ?, ?, ?)''', (user_id, request_type, status, datetime.now())) conn.commit() ``` #### 4. Concurrent File Processing ```python # For multiple images/PDFs async def process_multiple_files(files): tasks = [extract_text_from_image(f) for f in files] results = await asyncio.gather(*tasks) return results ``` ### Performance Metrics **Current Performance**: - Image analysis: 5-15 seconds - PDF extraction: 1-5 seconds - Quiz generation: 10-30 seconds - Total time: 20-50 seconds **Bottlenecks**: 1. Ollama API response time (50-80%) 2. Image base64 encoding (5-10%) 3. Network latency (10-20%) ## 🔄 Deployment Architecture ### Development ``` Local PC ├── Python 3.9+ ├── bot.py ├── .env (with test credentials) └── Internet connection to Ollama Cloud ``` ### Production ``` Server/Cloud ├── Python 3.9+ ├── bot.py ├── .env (with production credentials) ├── Systemd/Docker service ├── Error logging └── Database backup ``` ### Docker Deployment ```dockerfile FROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY bot.py . COPY .env . CMD ["python", "bot.py"] ``` ```bash docker build -t aiquiz-bot . docker run -d --name aiquiz-bot aiquiz-bot ``` --- **Last Updated**: February 2026 **Architecture Version**: 1.0 **API Version**: Ollama Cloud API v1