Files
inna_ai6m3/Joke Bot Upgrade_ SQLite Database Integration _ Beginner's Guide.html
2026-01-20 07:12:52 +00:00

1525 lines
67 KiB
HTML

<!DOCTYPE html>
<!-- saved from url=(0069)file:///Users/home/Downloads/deepseek_html_20260116_9092c1%20(3).html -->
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Joke Bot Upgrade: SQLite Database Integration | Beginner's Guide</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
color: #1a1a1a;
line-height: 1.4;
height: 100vh;
overflow: hidden;
background: linear-gradient(rgba(255, 255, 255, 0.98), rgba(255, 255, 255, 0.99));
}
.presentation-container {
max-width: 900px;
height: 100vh;
margin: 0 auto;
display: flex;
flex-direction: column;
padding: 0 20px;
}
.slide {
display: none;
flex: 1;
padding: 40px 30px;
background: transparent;
overflow-y: auto;
max-height: calc(100vh - 100px);
}
.active {
display: block;
animation: fadeIn 0.5s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
/* Title Slide */
.title-slide {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
height: 100%;
}
.thesis-title {
font-weight: 800;
font-size: 2.8rem;
color: #2c3e50;
margin-bottom: 10px;
line-height: 1.1;
}
.thesis-subtitle {
font-size: 1.3rem;
color: #3498db;
margin-bottom: 40px;
font-weight: 500;
}
/* Typography */
h1 {
font-weight: 700;
font-size: 2.2rem;
color: #2c3e50;
margin-bottom: 25px;
line-height: 1.1;
}
h2 {
font-weight: 600;
font-size: 1.8rem;
color: #2c3e50;
margin-bottom: 25px;
}
h3 {
font-weight: 600;
font-size: 1.2rem;
color: #3498db;
margin-bottom: 15px;
margin-top: 25px;
}
p {
font-size: 1rem;
color: #4a5568;
margin-bottom: 15px;
}
.lead {
font-size: 1.1rem;
color: #2c3e50;
font-weight: 500;
margin-bottom: 20px;
}
/* Code Blocks */
.code-block {
background: #1e1e1e;
color: #d4d4d4;
padding: 25px;
border-radius: 8px;
margin: 20px 0;
font-family: 'Courier New', Consolas, Monaco, monospace;
font-size: 0.9rem;
line-height: 1.5;
overflow-x: auto;
white-space: pre;
}
.code-comment { color: #6a9955; }
.code-keyword { color: #569cd6; }
.code-function { color: #dcdcaa; }
.code-string { color: #ce9178; }
.code-builtin { color: #4ec9b0; }
.code-number { color: #b5cea8; }
/* Feature Boxes */
.feature-box {
background: #f8fafc;
padding: 25px;
border-radius: 10px;
margin: 25px 0;
border-left: 4px solid #3498db;
}
.feature-item {
display: flex;
align-items: flex-start;
margin-bottom: 15px;
}
.feature-number {
background: #3498db;
color: white;
width: 28px;
height: 28px;
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 15px;
flex-shrink: 0;
font-weight: bold;
font-size: 0.9rem;
}
/* Points System */
.points-system {
background: #fff3cd;
padding: 25px;
border-radius: 10px;
margin: 25px 0;
border: 2px solid #ffc107;
}
.points-header {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.points-emoji {
font-size: 2.5rem;
margin-right: 15px;
}
.points-title {
color: #856404;
font-weight: 700;
font-size: 1.4rem;
}
.points-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-top: 20px;
}
.point-card {
background: white;
padding: 15px;
border-radius: 8px;
border-left: 4px solid #28a745;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.point-emoji {
font-size: 1.8rem;
margin-bottom: 10px;
}
.point-value {
background: #28a745;
color: white;
padding: 2px 8px;
border-radius: 12px;
font-size: 0.9rem;
font-weight: bold;
margin-right: 5px;
}
/* Database Concepts */
.database-concept {
background: #fff;
padding: 20px;
border-radius: 8px;
margin: 15px 0;
border: 2px solid #e0e6ed;
}
.concept-title {
color: #2c3e50;
font-weight: 600;
margin-bottom: 10px;
display: block;
}
/* Setup Box */
.setup-box {
background: #e8f4f8;
padding: 20px;
border-radius: 8px;
margin: 15px 0;
border-left: 4px solid #3498db;
}
.setup-step {
margin-bottom: 15px;
padding-left: 10px;
}
.setup-step:last-child {
margin-bottom: 0;
}
.step-number {
background: #3498db;
color: white;
width: 24px;
height: 24px;
border-radius: 12px;
display: inline-flex;
align-items: center;
justify-content: center;
margin-right: 10px;
font-weight: bold;
font-size: 0.9rem;
}
/* Terminal */
.terminal {
background: #2c3e50;
color: #ecf0f1;
padding: 15px;
border-radius: 6px;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
margin: 15px 0;
overflow-x: auto;
}
.terminal-command {
color: #3498db;
}
.terminal-comment {
color: #7f8c8d;
}
/* Navigation */
.navigation {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
background: rgba(255, 255, 255, 0.95);
border-top: 1px solid #e2e8f0;
height: 70px;
flex-shrink: 0;
}
.nav-btn {
padding: 10px 25px;
background: #3498db;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 0.95rem;
font-weight: 500;
transition: all 0.3s ease;
}
.nav-btn:hover:not(:disabled) {
background: #2980b9;
}
.nav-btn:disabled {
background: #cbd5e0;
cursor: not-allowed;
}
.slide-counter {
font-weight: 600;
color: #4a5568;
font-size: 0.95rem;
}
/* Learning Outcomes */
.outcomes-box {
background: #d4edda;
padding: 25px;
border-radius: 10px;
margin: 25px 0;
border: 2px solid #c3e6cb;
}
.outcome-item {
display: flex;
align-items: flex-start;
margin-bottom: 15px;
}
.outcome-check {
color: #155724;
font-size: 1.2rem;
margin-right: 15px;
flex-shrink: 0;
}
/* Responsive */
@media (max-width: 768px) {
.slide {
padding: 30px 20px;
}
.thesis-title {
font-size: 2.2rem;
}
h1 {
font-size: 1.8rem;
}
h2 {
font-size: 1.5rem;
}
.code-block {
padding: 20px;
font-size: 0.85rem;
}
.points-grid {
grid-template-columns: 1fr;
}
}
</style>
<link href="./Joke Bot Upgrade_ SQLite Database Integration _ Beginner&#39;s Guide_files/css2" rel="stylesheet">
</head>
<body>
<div class="presentation-container">
<!-- Slide 1: Title -->
<div class="slide active" id="slide1">
<div class="title-slide">
<div>
<h1 class="thesis-title">Joke Bot Upgrade</h1>
<p class="thesis-subtitle">From Simple Lists to SQLite Database with User Interaction</p>
</div>
<div class="author-info" style="margin-top: 50px; padding-top: 30px; border-top: 2px solid #e0e6ed; width: 100%; max-width: 600px;">
<p><strong>Goal:</strong> Upgrade joke bot with database, user submissions, and ratings</p>
<p><strong>Prerequisites:</strong> Basic Python knowledge, our existing joke bot</p>
<p><strong>Time:</strong> 60 minutes to complete upgrade</p>
<p><strong>Tools:</strong> Python IDLE, Command Line/PowerShell</p>
</div>
</div>
</div>
<!-- Slide 2: Classroom Points System -->
<div class="slide" id="slide2">
<h1>How You Earn Points in Class! 🌟</h1>
<div class="points-system">
<div class="points-header">
<div class="points-emoji">🏆</div>
<div>
<h2 class="points-title">EARN UP TO 5 POINTS EACH DAY!</h2>
<p>Track your progress and earn rewards for active participation</p>
</div>
</div>
<div class="points-grid">
<div class="point-card">
<div class="point-emoji"></div>
<h4><span class="point-value">+2</span> You Came to Class!</h4>
<p>Great job! Just by being in class, you get 2 points. Yay!</p>
</div>
<div class="point-card">
<div class="point-emoji">👂</div>
<h4><span class="point-value">+1</span> You Listened Quietly!</h4>
<p>You didn't talk when the teacher was talking. Good listening!</p>
</div>
<div class="point-card">
<div class="point-emoji">✏️</div>
<h4><span class="point-value">+1</span> You Tried Your Work!</h4>
<p>You didn't finish everything? That's OK! If you tried, you still get a point.</p>
</div>
<div class="point-card">
<div class="point-emoji">🎉</div>
<h4><span class="point-value">+1</span> You Finished ALL Your Work!</h4>
<p>Wow! You did every single part — even the last task! You get a big high-five!</p>
</div>
</div>
<div style="margin-top: 20px; padding: 15px; background: #d1ecf1; border-radius: 6px;">
<h4 style="color: #0c5460; margin-bottom: 10px;">📊 Points Legend:</h4>
<p><strong>H</strong> = You were here! Points depend on what you did.</p>
<p><strong></strong> = You were absent → 0 points</p>
</div>
</div>
<div class="database-concept">
<span class="concept-title">Today's Goal:</span>
<p>Complete ALL steps of the joke bot upgrade to earn the full 5 points! 🎯</p>
<p>Follow along, ask questions, and help your classmates to maximize your learning!</p>
</div>
</div>
<!-- Slide 3: Learning Outcomes -->
<div class="slide" id="slide3">
<h1>Learning Outcomes</h1>
<p class="lead">By the end of this session, you will be able to:</p>
<div class="outcomes-box">
<div class="outcome-item">
<div class="outcome-check"></div>
<div>
<h3>1. Understand SQLite Database Basics</h3>
<p>Explain what SQLite is and why it's perfect for small Python projects</p>
</div>
</div>
<div class="outcome-item">
<div class="outcome-check"></div>
<div>
<h3>2. Design Database Tables</h3>
<p>Create tables with proper columns, data types, and relationships</p>
</div>
</div>
<div class="outcome-item">
<div class="outcome-check"></div>
<div>
<h3>3. Implement CRUD Operations</h3>
<p>Write Python code to Create, Read, Update, and Delete database records</p>
</div>
</div>
<div class="outcome-item">
<div class="outcome-check"></div>
<div>
<h3>4. Integrate Database with Telegram Bot</h3>
<p>Connect your existing joke bot to a persistent database</p>
</div>
</div>
<div class="outcome-item">
<div class="outcome-check"></div>
<div>
<h3>5. Add User Interaction Features</h3>
<p>Implement joke submission, rating system, and statistics</p>
</div>
</div>
<div class="outcome-item">
<div class="outcome-check"></div>
<div>
<h3>6. Use Virtual Environments</h3>
<p>Set up and manage Python dependencies using venv</p>
</div>
</div>
</div>
<div class="feature-box">
<h3>Why These Skills Matter:</h3>
<div class="feature-item">
<div class="feature-number">💼</div>
<div><strong>Industry Standard:</strong> Databases are used in 99% of real-world applications</div>
</div>
<div class="feature-item">
<div class="feature-number">🚀</div>
<div><strong>Career Boost:</strong> Database skills are highly sought after by employers</div>
</div>
<div class="feature-item">
<div class="feature-number">🧠</div>
<div><strong>Problem Solving:</strong> Learn to structure and manage complex data</div>
</div>
<div class="feature-item">
<div class="feature-number">📱</div>
<div><strong>App Development:</strong> Build apps that remember user data between sessions</div>
</div>
</div>
</div>
<!-- Slide 4: Why Databases Matter -->
<div class="slide" id="slide4">
<h1>Why Databases Matter</h1>
<p class="lead">Moving beyond simple lists to persistent storage</p>
<div class="database-concept">
<span class="concept-title">The Problem with Lists:</span>
<p>Our current joke bot stores jokes in a Python list:</p>
<div class="code-block" style="margin: 10px 0; padding: 15px;">
JOKE_LIST = [
"Why did the robot go to school? To recharge his brain! 🔋",
"Knock knock!\nWho's there?\nLettuce!\nLettuce who?\nLettuce in!",
"Why don't eggs tell jokes? They'd crack each other up! 🥚"
]</div>
<p><strong>Problems:</strong></p>
<p>• Jokes are lost when bot restarts</p>
<p>• No way for users to add jokes</p>
<p>• Can't track ratings or popularity</p>
<p>• Hard to search or organize jokes</p>
</div>
<div class="feature-box">
<h3>Database Advantages:</h3>
<div class="feature-item">
<div class="feature-number">💾</div>
<div><strong>Persistence:</strong> Data survives bot restarts and crashes</div>
</div>
<div class="feature-item">
<div class="feature-number">👥</div>
<div><strong>User Contributions:</strong> Community can add content</div>
</div>
<div class="feature-item">
<div class="feature-number">📊</div>
<div><strong>Analytics:</strong> Track what jokes are popular</div>
</div>
<div class="feature-item">
<div class="feature-number">🔍</div>
<div><strong>Searchability:</strong> Find jokes by keywords or ratings</div>
</div>
<div class="feature-item">
<div class="feature-number"></div>
<div><strong>Scalability:</strong> Handle thousands of jokes efficiently</div>
</div>
</div>
<div class="setup-box">
<h3>Real-World Examples:</h3>
<p><strong>Reddit:</strong> Database stores posts, votes, comments, user profiles</p>
<p><strong>YouTube:</strong> Database stores videos, views, likes, subscriptions</p>
<p><strong>Banking Apps:</strong> Database stores accounts, transactions, balances</p>
<p><strong>Games:</strong> Database stores player scores, achievements, progress</p>
</div>
</div>
<!-- Slide 5: Setup - Check Python Installation -->
<div class="slide" id="slide5">
<h2>Step-by-Step Setup Guide</h2>
<p class="lead">Before We Start - Check Your Python Installation</p>
<div class="setup-box">
<div class="setup-step">
<span class="step-number">1</span>
<strong>Open Command Prompt or PowerShell:</strong>
<p>Press <code>Windows + R</code>, type <code>cmd</code> or <code>powershell</code>, press Enter</p>
</div>
<div class="setup-step">
<span class="step-number">2</span>
<strong>Check Python Version:</strong>
<p>Type the following command and press Enter:</p>
</div>
</div>
<div class="terminal">
<span class="terminal-command">python --version</span><br>
<span class="terminal-comment"># Should show: Python 3.x.x</span><br><br>
<span class="terminal-comment"># If that doesn't work, try:</span><br>
<span class="terminal-command">python3 --version</span><br>
<span class="terminal-comment"># Or on some systems:</span><br>
<span class="terminal-command">py --version</span>
</div>
<div class="database-concept">
<span class="concept-title">Troubleshooting:</span>
<p><strong>If Python is not installed:</strong></p>
<p>1. Go to <a href="https://www.python.org/downloads/" target="_blank">python.org/downloads</a></p>
<p>2. Download Python 3.9 or later</p>
<p>3. Run installer (CHECK "Add Python to PATH" option!)</p>
<p>4. Restart your computer, then try again</p>
</div>
<div class="feature-box">
<h3>Verify Installation:</h3>
<p>Open Python IDLE to test:</p>
<div class="terminal">
<span class="terminal-command">python</span><br>
<span class="terminal-comment"># You should see Python interactive shell:</span><br>
<span class="terminal-command">Python 3.9.0 (tags/v3.9.0:9cf6752, Oct 5 2020, 15:34:40) ...</span><br>
<span class="terminal-command">Type "help", "copyright", "credits" or "license" for more information.</span><br>
<span class="terminal-command">&gt;&gt;&gt; print("Hello, World!")</span><br>
<span class="terminal-command">Hello, World!</span><br>
<span class="terminal-command">&gt;&gt;&gt; exit()</span><br>
<span class="terminal-comment"># Type exit() to leave Python shell</span>
</div>
</div>
</div>
<!-- Slide 6: Create Project Folder -->
<div class="slide" id="slide6">
<h2>Create Your Project Folder</h2>
<p class="lead">Organize your files properly from the start</p>
<div class="setup-box">
<div class="setup-step">
<span class="step-number">1</span>
<strong>Open PowerShell or Command Prompt:</strong>
<p>Make sure you're not in the Python shell (should see <code>C:\&gt;</code> or <code>PS C:\&gt;</code>)</p>
</div>
<div class="setup-step">
<span class="step-number">2</span>
<strong>Navigate to Desktop or Documents:</strong>
<p>Let's create a folder on your Desktop for easy access:</p>
</div>
</div>
<div class="terminal">
<span class="terminal-comment"># Go to Desktop (Windows)</span><br>
<span class="terminal-command">cd Desktop</span><br><br>
<span class="terminal-comment"># Create a new folder for your joke bot</span><br>
<span class="terminal-command">mkdir joke_bot_upgrade</span><br><br>
<span class="terminal-comment"># Go into your new folder</span><br>
<span class="terminal-command">cd joke_bot_upgrade</span><br><br>
<span class="terminal-comment"># Verify you're in the right place</span><br>
<span class="terminal-command">pwd</span><br>
<span class="terminal-comment"># Should show: C:\Users\YourName\Desktop\joke_bot_upgrade</span><br>
<span class="terminal-comment"># Or use 'dir' to see files (should be empty)</span><br>
<span class="terminal-command">dir</span>
</div>
<div class="database-concept">
<span class="concept-title">Folder Structure:</span>
<div class="code-block" style="margin: 10px 0; padding: 15px; background: #2c3e50; color: white; font-size: 0.9rem;">
joke_bot_upgrade/
├── app.py # Main bot file
├── database.py # SQLite database class
├── joke_bot.db # Database file (auto-created)
├── requirements.txt # Python dependencies
└── venv/ # Virtual environment (we'll create this)</div>
<p><strong>Best Practice:</strong> Keep all related files in one folder for easy management!</p>
</div>
</div>
<!-- Slide 7: Set Up Virtual Environment -->
<div class="slide" id="slide7">
<h2>Set Up Virtual Environment (venv)</h2>
<p class="lead">Isolate project dependencies for clean development</p>
<div class="setup-box">
<div class="setup-step">
<span class="step-number">1</span>
<strong>Why Virtual Environment?</strong>
<p>• Keeps project dependencies separate</p>
<p>• Avoids version conflicts between projects</p>
<p>• Makes sharing and deployment easier</p>
</div>
<div class="setup-step">
<span class="step-number">2</span>
<strong>Create Virtual Environment:</strong>
<p>Make sure you're in your <code>joke_bot_upgrade</code> folder, then run:</p>
</div>
</div>
<div class="terminal">
<span class="terminal-comment"># Create virtual environment named 'venv'</span><br>
<span class="terminal-command">python -m venv venv</span><br><br>
<span class="terminal-comment"># Check if venv folder was created</span><br>
<span class="terminal-command">dir</span><br>
<span class="terminal-comment"># You should see a 'venv' folder in the list</span>
</div>
<div class="database-concept">
<span class="concept-title">What Happened?</span>
<p>The <code>venv</code> command created a complete Python installation in the <code>venv</code> folder:</p>
<p>• Python interpreter copy</p>
<p>• pip (package installer)</p>
<p>• Standard library</p>
<p>• Empty site-packages for our libraries</p>
</div>
<div class="feature-box">
<h3>Activate Virtual Environment:</h3>
<p><strong>Windows PowerShell:</strong></p>
<div class="terminal">
<span class="terminal-command">venv\Scripts\Activate.ps1</span><br>
<span class="terminal-comment"># If you get an error about execution policy, run this first:</span><br>
<span class="terminal-command">Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser</span><br>
<span class="terminal-command">venv\Scripts\Activate.ps1</span>
</div>
<p><strong>Windows Command Prompt:</strong></p>
<div class="terminal">
<span class="terminal-command">venv\Scripts\activate.bat</span>
</div>
<p><strong>Mac/Linux Terminal:</strong></p>
<div class="terminal">
<span class="terminal-command">source venv/bin/activate</span>
</div>
<p><strong>Success Indicator:</strong> You should see <code>(venv)</code> at the start of your command line!</p>
</div>
</div>
<!-- Slide 8: Install Required Libraries -->
<div class="slide" id="slide8">
<h2>Install Required Libraries</h2>
<p class="lead">Get the Python packages we need for our upgraded bot</p>
<div class="setup-box">
<div class="setup-step">
<span class="step-number">1</span>
<strong>First, activate your venv:</strong>
<p>Make sure you see <code>(venv)</code> before the prompt</p>
</div>
<div class="setup-step">
<span class="step-number">2</span>
<strong>Install python-telegram-bot:</strong>
<p>This is the main library for creating Telegram bots</p>
</div>
</div>
<div class="terminal">
<span class="terminal-comment"># Install the Telegram bot library (version 20.3)</span><br>
<span class="terminal-command">pip install python-telegram-bot==20.3</span><br><br>
<span class="terminal-comment"># Verify installation</span><br>
<span class="terminal-command">pip show python-telegram-bot</span><br>
<span class="terminal-comment"># Should show version 20.3</span>
</div>
<div class="database-concept">
<span class="concept-title">What We're Installing:</span>
<p><strong>python-telegram-bot:</strong> Official library for Telegram Bot API</p>
<p><strong>Version 20.3:</strong> Specific version that matches our code examples</p>
<p><strong>Note:</strong> SQLite comes built-in with Python - no need to install!</p>
</div>
<div class="feature-box">
<h3>Create Requirements File:</h3>
<p>Save the list of dependencies for future use:</p>
<div class="terminal">
<span class="terminal-command">pip freeze &gt; requirements.txt</span><br><br>
<span class="terminal-comment"># View the requirements file</span><br>
<span class="terminal-command">type requirements.txt</span><br>
<span class="terminal-comment"># (Mac/Linux: use 'cat requirements.txt' instead of 'type')</span>
</div>
<p><strong>requirements.txt contents:</strong></p>
<div class="code-block" style="margin: 10px 0; padding: 15px; font-size: 0.8rem;">
python-telegram-bot==20.3</div>
<p><strong>Why this matters:</strong> Anyone can install exact same versions with <code>pip install -r requirements.txt</code></p>
</div>
<div class="setup-box">
<div class="setup-step">
<span class="step-number">3</span>
<strong>Test Your Setup:</strong>
<p>Open Python IDLE or use Python shell to test imports:</p>
</div>
</div>
<div class="terminal">
<span class="terminal-comment"># Open Python interactive shell</span><br>
<span class="terminal-command">python</span><br><br>
<span class="terminal-comment"># Try importing the libraries</span><br>
<span class="terminal-command">&gt;&gt;&gt; import sqlite3</span><br>
<span class="terminal-command">&gt;&gt;&gt; from telegram import Update</span><br>
<span class="terminal-command">&gt;&gt;&gt; from telegram.ext import Application</span><br>
<span class="terminal-command">&gt;&gt;&gt; print("All imports successful!")</span><br>
<span class="terminal-command">All imports successful!</span><br>
<span class="terminal-command">&gt;&gt;&gt; exit()</span>
</div>
</div>
<!-- Slide 9: Copy Existing Bot Code -->
<div class="slide" id="slide9">
<h2>Copy Existing Bot Code</h2>
<p class="lead">Start with our working joke bot and upgrade it</p>
<div class="setup-box">
<div class="setup-step">
<span class="step-number">1</span>
<strong>Create app.py file:</strong>
<p>In your <code>joke_bot_upgrade</code> folder, create a new file:</p>
</div>
</div>
<div class="terminal">
<span class="terminal-comment"># Using Python IDLE or any text editor:</span><br>
<span class="terminal-command">notepad app.py</span><br>
<span class="terminal-comment"># (Or use VS Code, Sublime Text, or Python's IDLE)</span>
</div>
<div class="database-concept">
<span class="concept-title">Our Starting Code:</span>
<p>Copy this code into <code>app.py</code> - this is our current working bot:</p>
<div class="code-block"><span class="code-keyword">from</span> telegram <span class="code-keyword">import</span> Update
<span class="code-keyword">from</span> telegram.ext <span class="code-keyword">import</span> Application, CommandHandler, ContextTypes
<span class="code-keyword">import</span> random
JOKE_LIST = [
<span class="code-string">"Why did the robot go to school? To recharge his brain! 🔋"</span>,
<span class="code-string">"Knock knock!\nWho's there?\nLettuce!\nLettuce who?\nLettuce in!"</span>,
<span class="code-string">"Why don't eggs tell jokes? They'd crack each other up! 🥚"</span>
]
<span class="code-keyword">async</span> <span class="code-keyword">def</span> <span class="code-function">start</span>(update: Update, context: ContextTypes.DEFAULT_TYPE):
<span class="code-keyword">await</span> update.message.reply_text(<span class="code-string">"Hi! Type /joke for a funny joke! 😄"</span>)
<span class="code-keyword">async</span> <span class="code-keyword">def</span> <span class="code-function">send_joke</span>(update: Update, context: ContextTypes.DEFAULT_TYPE):
joke = random.choice(JOKE_LIST)
<span class="code-keyword">await</span> update.message.reply_text(joke)
<span class="code-keyword">def</span> <span class="code-function">main</span>():
<span class="code-comment"># Using the provided bot token</span>
BOT_TOKEN = <span class="code-string">"YOUR_BOT_TOKEN_HERE"</span>
app = Application.builder().token(BOT_TOKEN).build()
app.add_handler(CommandHandler(<span class="code-string">"start"</span>, start))
app.add_handler(CommandHandler(<span class="code-string">"joke"</span>, send_joke))
print(<span class="code-string">"Bot is running... Press Ctrl+C to stop."</span>)
app.run_polling()
<span class="code-keyword">if</span> __name__ == <span class="code-string">"__main__"</span>:
main()</div>
</div>
<div class="feature-box">
<h3>Important: Get Your Bot Token</h3>
<div class="feature-item">
<div class="feature-number">1</div>
<div><strong>Open Telegram:</strong> Search for <code>@BotFather</code></div>
</div>
<div class="feature-item">
<div class="feature-number">2</div>
<div><strong>Create New Bot:</strong> Type <code>/newbot</code> and follow instructions</div>
</div>
<div class="feature-item">
<div class="feature-number">3</div>
<div><strong>Get Token:</strong> Copy the token (looks like: <code>1234567890:ABCdefGHIjklMNOpqrsTUVwxyz</code>)</div>
</div>
<div class="feature-item">
<div class="feature-number">4</div>
<div><strong>Replace in Code:</strong> Change <code>YOUR_BOT_TOKEN_HERE</code> with your actual token</div>
</div>
</div>
<div class="setup-box">
<div class="setup-step">
<span class="step-number">2</span>
<strong>Test Current Bot:</strong>
<p>Make sure the basic bot works before we upgrade it:</p>
</div>
</div>
<div class="terminal">
<span class="terminal-comment"># Make sure venv is activated and you're in the right folder</span><br>
<span class="terminal-command">(venv) C:\Users\YourName\Desktop\joke_bot_upgrade&gt; python app.py</span><br><br>
<span class="terminal-comment"># Should see:</span><br>
<span class="terminal-command">Bot is running... Press Ctrl+C to stop.</span><br><br>
<span class="terminal-comment"># Open Telegram, find your bot, type /start and /joke</span><br>
<span class="terminal-comment"># Press Ctrl+C to stop the bot when done testing</span>
</div>
</div>
<!-- Slide 10: What is SQLite? -->
<div class="slide" id="slide10">
<h1>What Is SQLite?</h1>
<p class="lead">Serverless, self-contained SQL database perfect for Telegram bots</p>
<div class="feature-box">
<h3>Why SQLite for Our Joke Bot?</h3>
<div class="feature-item">
<div class="feature-number">1</div>
<div><strong>No Server Needed:</strong> Database lives in a single file</div>
</div>
<div class="feature-item">
<div class="feature-number">2</div>
<div><strong>Zero Configuration:</strong> Just import and use</div>
</div>
<div class="feature-item">
<div class="feature-number">3</div>
<div><strong>Lightweight:</strong> Perfect for small to medium applications</div>
</div>
<div class="feature-item">
<div class="feature-number">4</div>
<div><strong>SQL Standard:</strong> Uses standard SQL commands</div>
</div>
<div class="feature-item">
<div class="feature-number">5</div>
<div><strong>Built-in Python:</strong> No extra installation needed</div>
</div>
</div>
<div class="database-concept">
<span class="concept-title">Think of it like this:</span>
<p>SQLite is like an Excel file that speaks SQL. It's a complete database in a single file that you can include with your application.</p>
<p>Perfect for Telegram bots, mobile apps, and desktop applications.</p>
</div>
<div class="code-block" style="margin-top: 20px; padding: 15px; background: #2c3e50;">
<span class="code-comment"># SQLite comes built-in with Python!</span>
<span class="code-keyword">import</span> sqlite3
<span class="code-comment"># Connect to database (creates if doesn't exist)</span>
conn = sqlite3.connect(<span class="code-string">'joke_bot.db'</span>)
cursor = conn.cursor()
<span class="code-comment"># Create a table</span>
cursor.execute(<span class="code-string">'''CREATE TABLE jokes (
id INTEGER PRIMARY KEY,
text TEXT NOT NULL,
added_by TEXT,
likes INTEGER DEFAULT 0,
dislikes INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)'''</span>)
conn.commit()
conn.close()</div>
</div>
<!-- Slide 11: Our Upgrade Goals -->
<div class="slide" id="slide11">
<h2>Our Upgrade Goals</h2>
<p class="lead">From static list to dynamic, user-powered joke database</p>
<div class="database-concept">
<span class="concept-title">Current Limitations:</span>
<p>1. Jokes are hardcoded in Python list</p>
<p>2. No way for users to add new jokes</p>
<p>3. No rating system to find the best jokes</p>
<p>4. Jokes are lost when bot restarts</p>
</div>
<h3>New Features We'll Add:</h3>
<div class="feature-box">
<div class="feature-item">
<div class="feature-number">1</div>
<div>
<strong>SQLite Database:</strong><br>
Store jokes permanently in a database file
</div>
</div>
<div class="feature-item">
<div class="feature-number">2</div>
<div>
<strong>User Submissions:</strong><br>
<code>/addjoke</code> command for users to submit jokes
</div>
</div>
<div class="feature-item">
<div class="feature-number">3</div>
<div>
<strong>Rating System:</strong><br>
<code>/like</code> and <code>/dislike</code> commands to rate jokes
</div>
</div>
<div class="feature-item">
<div class="feature-number">4</div>
<div>
<strong>Top Jokes:</strong><br>
<code>/top</code> command to show most popular jokes
</div>
</div>
<div class="feature-item">
<div class="feature-number">5</div>
<div>
<strong>Random with Weight:</strong><br>
Better jokes appear more often
</div>
</div>
</div>
</div>
<!-- Slide 12: Step 1 - Database Setup -->
<div class="slide" id="slide12">
<h2>Step 1: Database Setup (10 minutes)</h2>
<p class="lead">Create the SQLite database and connection functions</p>
<div class="code-block"><span class="code-comment"># Create a new file: database.py</span>
<span class="code-comment"># This will handle all database operations</span>
<span class="code-keyword">import</span> sqlite3
<span class="code-keyword">from</span> datetime <span class="code-keyword">import</span> datetime
<span class="code-keyword">class</span> <span class="code-builtin">JokeDatabase</span>:
<span class="code-keyword">def</span> <span class="code-function">__init__</span>(<span class="code-keyword">self</span>, db_name=<span class="code-string">'joke_bot.db'</span>):
<span class="code-keyword">self</span>.db_name = db_name
<span class="code-keyword">self</span>.init_database()
<span class="code-keyword">def</span> <span class="code-function">get_connection</span>(<span class="code-keyword">self</span>):
<span class="code-comment">"""Get a database connection"""</span>
conn = sqlite3.connect(<span class="code-keyword">self</span>.db_name)
conn.row_factory = sqlite3.Row <span class="code-comment"># Access columns by name</span>
<span class="code-keyword">return</span> conn
<span class="code-keyword">def</span> <span class="code-function">init_database</span>(<span class="code-keyword">self</span>):
<span class="code-comment">"""Initialize database tables"""</span>
conn = <span class="code-keyword">self</span>.get_connection()
cursor = conn.cursor()
<span class="code-comment"># Create jokes table</span>
cursor.execute(<span class="code-string">'''CREATE TABLE IF NOT EXISTS jokes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
joke_text TEXT NOT NULL,
user_id INTEGER,
username TEXT,
likes INTEGER DEFAULT 0,
dislikes INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)'''</span>)
<span class="code-comment"># Create ratings table to track user votes</span>
cursor.execute(<span class="code-string">'''CREATE TABLE IF NOT EXISTS ratings (
user_id INTEGER,
joke_id INTEGER,
vote INTEGER, <span class="code-comment">-- 1 for like, -1 for dislike</span>
PRIMARY KEY (user_id, joke_id),
FOREIGN KEY (joke_id) REFERENCES jokes(id)
)'''</span>)
conn.commit()
conn.close()
<span class="code-comment"># Add some default jokes if table is empty</span>
<span class="code-keyword">self</span>.add_default_jokes()
<span class="code-keyword">def</span> <span class="code-function">add_default_jokes</span>(<span class="code-keyword">self</span>):
<span class="code-comment">"""Add default jokes if database is empty"""</span>
conn = <span class="code-keyword">self</span>.get_connection()
cursor = conn.cursor()
cursor.execute(<span class="code-string">"SELECT COUNT(*) FROM jokes"</span>)
count = cursor.fetchone()[<span class="code-number">0</span>]
<span class="code-keyword">if</span> count == <span class="code-number">0</span>:
default_jokes = [
(<span class="code-string">"Why did the robot go to school? To recharge his brain! 🔋"</span>, <span class="code-number">0</span>, <span class="code-string">"System"</span>),
(<span class="code-string">"Knock knock!\nWho's there?\nLettuce!\nLettuce who?\nLettuce in!"</span>, <span class="code-number">0</span>, <span class="code-string">"System"</span>),
(<span class="code-string">"Why don't eggs tell jokes? They'd crack each other up! 🥚"</span>, <span class="code-number">0</span>, <span class="code-string">"System"</span>)
]
cursor.executemany(<span class="code-string">'''INSERT INTO jokes (joke_text, user_id, username)
VALUES (?, ?, ?)'''</span>, default_jokes)
conn.commit()
print(<span class="code-string">f"Added </span>{len(default_jokes)}<span class="code-string"> default jokes to database"</span>)
conn.close()</div>
<div class="feature-box">
<h3>Database Schema Explained:</h3>
<div class="feature-item">
<div class="feature-number">📝</div>
<div><strong>jokes table:</strong> Stores all jokes with ratings</div>
</div>
<div class="feature-item">
<div class="feature-number"></div>
<div><strong>ratings table:</strong> Tracks who voted for which joke</div>
</div>
<div class="feature-item">
<div class="feature-number">🆔</div>
<div><strong>Primary keys:</strong> Unique IDs for each record</div>
</div>
<div class="feature-item">
<div class="feature-number">🔗</div>
<div><strong>Foreign key:</strong> Links ratings to jokes</div>
</div>
</div>
</div>
<!-- Slide 13: Step 2 - Database CRUD Operations -->
<div class="slide" id="slide13">
<h2>Step 2: Database Operations (15 minutes)</h2>
<p class="lead">Add CRUD (Create, Read, Update, Delete) functions</p>
<div class="code-block"><span class="code-comment"># Add these methods to the JokeDatabase class</span>
<span class="code-keyword">def</span> <span class="code-function">add_joke</span>(<span class="code-keyword">self</span>, joke_text, user_id, username):
<span class="code-comment">"""Add a new joke to the database"""</span>
conn = <span class="code-keyword">self</span>.get_connection()
cursor = conn.cursor()
cursor.execute(<span class="code-string">'''INSERT INTO jokes (joke_text, user_id, username)
VALUES (?, ?, ?)'''</span>, (joke_text, user_id, username))
joke_id = cursor.lastrowid
conn.commit()
conn.close()
<span class="code-keyword">return</span> joke_id
<span class="code-keyword">def</span> <span class="code-function">get_random_joke</span>(<span class="code-keyword">self</span>):
<span class="code-comment">"""Get a random joke, weighted by rating"""</span>
conn = <span class="code-keyword">self</span>.get_connection()
cursor = conn.cursor()
<span class="code-comment"># Weighted random: jokes with higher likes appear more often</span>
cursor.execute(<span class="code-string">'''SELECT * FROM jokes
ORDER BY (likes - dislikes + 5) * RANDOM() DESC
LIMIT 1'''</span>)
joke = cursor.fetchone()
conn.close()
<span class="code-keyword">return</span> dict(joke) <span class="code-keyword">if</span> joke <span class="code-keyword">else</span> <span class="code-keyword">None</span>
<span class="code-keyword">def</span> <span class="code-function">get_joke_by_id</span>(<span class="code-keyword">self</span>, joke_id):
<span class="code-comment">"""Get a specific joke by ID"""</span>
conn = <span class="code-keyword">self</span>.get_connection()
cursor = conn.cursor()
cursor.execute(<span class="code-string">"SELECT * FROM jokes WHERE id = ?"</span>, (joke_id,))
joke = cursor.fetchone()
conn.close()
<span class="code-keyword">return</span> dict(joke) <span class="code-keyword">if</span> joke <span class="code-keyword">else</span> <span class="code-keyword">None</span>
<span class="code-keyword">def</span> <span class="code-function">get_top_jokes</span>(<span class="code-keyword">self</span>, limit=<span class="code-number">5</span>):
<span class="code-comment">"""Get top-rated jokes"""</span>
conn = <span class="code-keyword">self</span>.get_connection()
cursor = conn.cursor()
cursor.execute(<span class="code-string">'''SELECT * FROM jokes
ORDER BY (likes - dislikes) DESC, likes DESC
LIMIT ?'''</span>, (limit,))
jokes = [dict(row) <span class="code-keyword">for</span> row <span class="code-keyword">in</span> cursor.fetchall()]
conn.close()
<span class="code-keyword">return</span> jokes
<span class="code-keyword">def</span> <span class="code-function">get_total_jokes</span>(<span class="code-keyword">self</span>):
<span class="code-comment">"""Get total number of jokes"""</span>
conn = <span class="code-keyword">self</span>.get_connection()
cursor = conn.cursor()
cursor.execute(<span class="code-string">"SELECT COUNT(*) FROM jokes"</span>)
count = cursor.fetchone()[<span class="code-number">0</span>]
conn.close()
<span class="code-keyword">return</span> count</div>
<div class="feature-box">
<h3>SQL Functions Explained:</h3>
<div class="feature-item">
<div class="feature-number">📊</div>
<div><strong>Weighted Random:</strong> <code>(likes - dislikes + 5) * RANDOM()</code></div>
</div>
<div class="feature-item">
<div class="feature-number">⬆️</div>
<div><strong>Top Jokes:</strong> Sorted by net score (likes - dislikes)</div>
</div>
<div class="feature-item">
<div class="feature-number">💾</div>
<div><strong>Parameterized Queries:</strong> Safe from SQL injection</div>
</div>
<div class="feature-item">
<div class="feature-number">🔄</div>
<div><strong>Connection Management:</strong> Open/close connections properly</div>
</div>
</div>
</div>
<!-- Slide 14: Step 3 - Rating System -->
<div class="slide" id="slide14">
<h2>Step 3: Rating System (15 minutes)</h2>
<p class="lead">Implement like/dislike functionality with vote tracking</p>
<div class="code-block"><span class="code-comment"># Add rating methods to JokeDatabase class</span>
<span class="code-keyword">def</span> <span class="code-function">rate_joke</span>(<span class="code-keyword">self</span>, user_id, joke_id, vote):
<span class="code-comment">"""
Rate a joke (like or dislike)
vote: 1 for like, -1 for dislike, 0 to remove rating
"""</span>
conn = <span class="code-keyword">self</span>.get_connection()
cursor = conn.cursor()
<span class="code-comment"># Check if user already voted</span>
cursor.execute(<span class="code-string">'''SELECT vote FROM ratings
WHERE user_id = ? AND joke_id = ?'''</span>, (user_id, joke_id))
existing_vote = cursor.fetchone()
<span class="code-keyword">if</span> existing_vote:
old_vote = existing_vote[<span class="code-number">0</span>]
<span class="code-keyword">if</span> vote == <span class="code-number">0</span>:
<span class="code-comment"># Remove vote</span>
cursor.execute(<span class="code-string">'''DELETE FROM ratings
WHERE user_id = ? AND joke_id = ?'''</span>, (user_id, joke_id))
<span class="code-keyword"># Update joke counts</span>
<span class="code-keyword">if</span> old_vote == <span class="code-number">1</span>:
cursor.execute(<span class="code-string">'''UPDATE jokes SET likes = likes - 1
WHERE id = ?'''</span>, (joke_id,))
<span class="code-keyword">elif</span> old_vote == -<span class="code-number">1</span>:
cursor.execute(<span class="code-string">'''UPDATE jokes SET dislikes = dislikes - 1
WHERE id = ?'''</span>, (joke_id,))
<span class="code-keyword">elif</span> old_vote != vote:
<span class="code-keyword"># Change vote</span>
cursor.execute(<span class="code-string">'''UPDATE ratings SET vote = ?
WHERE user_id = ? AND joke_id = ?'''</span>, (vote, user_id, joke_id))
<span class="code-keyword"># Update joke counts (remove old, add new)</span>
<span class="code-keyword">if</span> old_vote == <span class="code-number">1</span> <span class="code-keyword">and</span> vote == -<span class="code-number">1</span>:
cursor.execute(<span class="code-string">'''UPDATE jokes
SET likes = likes - 1, dislikes = dislikes + 1
WHERE id = ?'''</span>, (joke_id,))
<span class="code-keyword">elif</span> old_vote == -<span class="code-number">1</span> <span class="code-keyword">and</span> vote == <span class="code-number">1</span>:
cursor.execute(<span class="code-string">'''UPDATE jokes
SET likes = likes + 1, dislikes = dislikes - 1
WHERE id = ?'''</span>, (joke_id,))
<span class="code-keyword">else</span>:
<span class="code-keyword">if</span> vote != <span class="code-number">0</span>:
<span class="code-keyword"># New vote</span>
cursor.execute(<span class="code-string">'''INSERT INTO ratings (user_id, joke_id, vote)
VALUES (?, ?, ?)'''</span>, (user_id, joke_id, vote))
<span class="code-keyword"># Update joke counts</span>
<span class="code-keyword">if</span> vote == <span class="code-number">1</span>:
cursor.execute(<span class="code-string">'''UPDATE jokes SET likes = likes + 1
WHERE id = ?'''</span>, (joke_id,))
<span class="code-keyword">elif</span> vote == -<span class="code-number">1</span>:
cursor.execute(<span class="code-string">'''UPDATE jokes SET dislikes = dislikes + 1
WHERE id = ?'''</span>, (joke_id,))
conn.commit()
<span class="code-keyword"># Get updated joke info</span>
cursor.execute(<span class="code-string">"SELECT likes, dislikes FROM jokes WHERE id = ?"</span>, (joke_id,))
result = cursor.fetchone()
conn.close()
<span class="code-keyword">return</span> {
<span class="code-string">'likes'</span>: result[<span class="code-number">0</span>] <span class="code-keyword">if</span> result <span class="code-keyword">else</span> <span class="code-number">0</span>,
<span class="code-string">'dislikes'</span>: result[<span class="code-number">1</span>] <span class="code-keyword">else</span> <span class="code-number">0</span>
}
<span class="code-keyword">def</span> <span class="code-function">get_user_vote</span>(<span class="code-keyword">self</span>, user_id, joke_id):
<span class="code-comment">"""Get user's vote for a specific joke"""</span>
conn = <span class="code-keyword">self</span>.get_connection()
cursor = conn.cursor()
cursor.execute(<span class="code-string">'''SELECT vote FROM ratings
WHERE user_id = ? AND joke_id = ?'''</span>, (user_id, joke_id))
result = cursor.fetchone()
conn.close()
<span class="code-keyword">return</span> result[<span class="code-number">0</span>] <span class="code-keyword">if</span> result <span class="code-keyword">else</span> <span class="code-number">0</span></div>
<div class="feature-box">
<h3>Rating Logic:</h3>
<div class="feature-item">
<div class="feature-number">1</div>
<div><strong>Prevent Double Voting:</strong> Users can only vote once per joke</div>
</div>
<div class="feature-item">
<div class="feature-number">2</div>
<div><strong>Change Votes:</strong> Users can change their mind</div>
</div>
<div class="feature-item">
<div class="feature-number">3</div>
<div><strong>Remove Votes:</strong> Users can remove their rating</div>
</div>
<div class="feature-item">
<div class="feature-number">4</div>
<div><strong>Real-time Updates:</strong> Counts update immediately</div>
</div>
</div>
</div>
<!-- Slide 15: Step 4 - Telegram Bot Integration -->
<div class="slide" id="slide15">
<h2>Step 4: Telegram Bot Integration (15 minutes)</h2>
<p class="lead">Update app.py to use the database</p>
<div class="code-block"><span class="code-comment"># Updated app.py with database integration</span>
<span class="code-keyword">from</span> telegram <span class="code-keyword">import</span> Update, InlineKeyboardMarkup, InlineKeyboardButton
<span class="code-keyword">from</span> telegram.ext <span class="code-keyword">import</span> Application, CommandHandler, ContextTypes, MessageHandler, filters, CallbackQueryHandler
<span class="code-keyword">from</span> database <span class="code-keyword">import</span> JokeDatabase
<span class="code-keyword">import</span> random
<span class="code-comment"># Initialize database</span>
db = JokeDatabase()
<span class="code-keyword">async</span> <span class="code-keyword">def</span> <span class="code-function">start</span>(update: Update, context: ContextTypes.DEFAULT_TYPE):
<span class="code-comment">"""Start command handler"""</span>
welcome_text = <span class="code-string">"""🤖 Welcome to Joke Bot 2.0! 🤖
Commands:
/joke - Get a random joke
/addjoke - Submit your own joke
/top - See top-rated jokes
/like - Like the last joke
/dislike - Dislike the last joke
/stats - Bot statistics
Now with database, user submissions, and ratings!"""</span>
<span class="code-keyword">await</span> update.message.reply_text(welcome_text)
<span class="code-keyword">async</span> <span class="code-keyword">def</span> <span class="code-function">send_joke</span>(update: Update, context: ContextTypes.DEFAULT_TYPE):
<span class="code-comment">"""Send a random joke from database"""</span>
joke = db.get_random_joke()
<span class="code-keyword">if</span> <span class="code-keyword">not</span> joke:
<span class="code-keyword">await</span> update.message.reply_text(<span class="code-string">"No jokes in database yet! Use /addjoke to add one."</span>)
<span class="code-keyword">return</span>
<span class="code-comment"># Store joke ID in context for rating</span>
context.user_data[<span class="code-string">'last_joke_id'</span>] = joke[<span class="code-string">'id'</span>]
<span class="code-comment"># Format joke with rating info</span>
rating_text = <span class="code-string">f"👍 {joke['likes']} 👎 {joke['dislikes']}"</span>
joke_text = <span class="code-string">f"{joke['joke_text']}\n\n{rating_text}"</span>
<span class="code-comment"># Add inline buttons for quick rating</span>
keyboard = [
[
InlineKeyboardButton(<span class="code-string">"👍 Like"</span>, callback_data=<span class="code-string">f"like_{joke['id']}"</span>),
InlineKeyboardButton(<span class="code-string">"👎 Dislike"</span>, callback_data=<span class="code-string">f"dislike_{joke['id']}"</span>)
]
]
reply_markup = InlineKeyboardMarkup(keyboard)
<span class="code-keyword">await</span> update.message.reply_text(joke_text, reply_markup=reply_markup)
<span class="code-keyword">async</span> <span class="code-keyword">def</span> <span class="code-function">add_joke_command</span>(update: Update, context: ContextTypes.DEFAULT_TYPE):
<span class="code-comment">"""Handle /addjoke command"""</span>
<span class="code-keyword">if</span> <span class="code-keyword">not</span> context.args:
<span class="code-keyword">await</span> update.message.reply_text(
<span class="code-string">"Please provide a joke after the command:\n"</span>
<span class="code-string">"Example: /addjoke Why did the chicken cross the road?"</span>
)
<span class="code-keyword">return</span>
joke_text = <span class="code-string">" "</span>.join(context.args)
user = update.effective_user
<span class="code-comment"># Add to database</span>
joke_id = db.add_joke(joke_text, user.id, user.username)
<span class="code-keyword">await</span> update.message.reply_text(
<span class="code-string">f"✅ Joke added successfully! (ID: {joke_id})\n"</span>
<span class="code-string">"Others can now rate it with /like and /dislike"</span>
)</div>
<div class="feature-box">
<h3>New Bot Features:</h3>
<div class="feature-item">
<div class="feature-number">🤖</div>
<div><strong>Inline Buttons:</strong> Quick like/dislike without commands</div>
</div>
<div class="feature-item">
<div class="feature-number">💾</div>
<div><strong>User Context:</strong> Remember last joke for rating</div>
</div>
<div class="feature-item">
<span class="feature-number">📊</span>
<div><strong>Real Stats:</strong> Display actual like/dislike counts</div>
</div>
<div class="feature-item">
<div class="feature-number">👤</div>
<div><strong>User Tracking:</strong> Record who submitted each joke</div>
</div>
</div>
</div>
<!-- Navigation -->
<div class="navigation">
<button class="nav-btn" id="prev-btn" onclick="prevSlide()" disabled="">← Back</button>
<div class="slide-counter">
<span id="current-slide">1</span> of <span id="total-slides">15</span>
</div>
<button class="nav-btn" id="next-btn" onclick="nextSlide()">Next →</button>
</div>
</div>
<script>
let currentSlide = 1;
const totalSlides = 15;
function showSlide(slideNumber) {
document.querySelectorAll('.slide').forEach(slide => {
slide.classList.remove('active');
});
document.getElementById(`slide${slideNumber}`).classList.add('active');
document.getElementById(`slide${slideNumber}`).scrollTop = 0;
document.getElementById('current-slide').textContent = slideNumber;
document.getElementById('prev-btn').disabled = slideNumber === 1;
document.getElementById('next-btn').disabled = slideNumber === totalSlides;
if (slideNumber === totalSlides) {
document.getElementById('next-btn').textContent = 'Finish';
} else {
document.getElementById('next-btn').textContent = 'Next →';
}
}
function nextSlide() {
if (currentSlide < totalSlides) {
currentSlide++;
showSlide(currentSlide);
}
}
function prevSlide() {
if (currentSlide > 1) {
currentSlide--;
showSlide(currentSlide);
}
}
// Initialize
showSlide(1);
// Keyboard navigation
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowRight' || e.key === ' ' || e.key === 'Enter') {
nextSlide();
} else if (e.key === 'ArrowLeft') {
prevSlide();
}
});
// Touch swipe for mobile
let touchStartY = 0;
let touchEndY = 0;
document.addEventListener('touchstart', (e) => {
touchStartY = e.changedTouches[0].screenY;
});
document.addEventListener('touchend', (e) => {
touchEndY = e.changedTouches[0].screenY;
const swipeThreshold = 100;
if (touchEndY < touchStartY - swipeThreshold) {
nextSlide();
}
if (touchEndY > touchStartY + swipeThreshold) {
prevSlide();
}
});
</script>
</body></html>