1525 lines
67 KiB
HTML
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'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">>>> print("Hello, World!")</span><br>
|
|
<span class="terminal-command">Hello, World!</span><br>
|
|
<span class="terminal-command">>>> 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:\></code> or <code>PS C:\></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 > 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">>>> import sqlite3</span><br>
|
|
<span class="terminal-command">>>> from telegram import Update</span><br>
|
|
<span class="terminal-command">>>> from telegram.ext import Application</span><br>
|
|
<span class="terminal-command">>>> print("All imports successful!")</span><br>
|
|
<span class="terminal-command">All imports successful!</span><br>
|
|
<span class="terminal-command">>>> 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> 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> |