From 03c66a50a41e8087234d2999674643fc79a6c95e Mon Sep 17 00:00:00 2001 From: root Date: Fri, 16 Jan 2026 09:56:17 +0300 Subject: [PATCH] Added walkthrough guide --- .DS_Store | Bin 0 -> 6148 bytes ...tabase Integration _ Beginner's Guide.html | 1556 +++++++++++++++++ .../css2 | 315 ++++ jokes-bot-v3.0/.DS_Store | Bin 0 -> 6148 bytes jokes-bot-v3.0/README.md | 45 + jokes-bot-v3.0/app.py | 29 + jokes-bot-v3.0/requirements.txt | 1 + 7 files changed, 1946 insertions(+) create mode 100644 .DS_Store create mode 100644 Joke Bot Upgrade_ SQLite Database Integration _ Beginner's Guide.html create mode 100644 Joke Bot Upgrade_ SQLite Database Integration _ Beginner's Guide_files/css2 create mode 100644 jokes-bot-v3.0/.DS_Store create mode 100644 jokes-bot-v3.0/README.md create mode 100644 jokes-bot-v3.0/app.py create mode 100644 jokes-bot-v3.0/requirements.txt diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d375a572a6475f4c21113dc3c1e7a1b506229444 GIT binary patch literal 6148 zcmeHK&rcIU6n+Dhwji*SQjut~NfQ$j1S&){9xSECpe7}>)*?UZZaXb2+nr{2OF<;* zS&#k!-n@JB;>C;p1A6uD$-5qWvojU2TJ>U#*_X_GZ{NK4X6M_TeLDa^QjKx~KmmXd zHjaUQ?0z78oVO0?krqBkyc`Z(038^(h`#s?_ze8(4Dh`>1P^e}ZUcp*`*#OsVG3sS zrc>8Vrla3Wy>1$gJ2Ug1^z;T!^aX?A;6QLAyTzJWS92RqO0(DaRgN)JZ|j<#H)yk{ zL>HOmYKBE^FTf~MbXmV^SY_5sv4&N4yx6Q52!})AqB6d}f92w&nwU)-Ose~dL}GqY zotvLKI0%Qv;?q}GirZ$*VvhyM1iwL^3`%Un6I8mcvFwyg9q*YZ=;~NO&);%1N;{G@ z^19912W3R^77F(doE#h)Rz@PD(a2aN7K=qsjmJ(;Oq?kyqqho*YQd$uZq|56i%R4>*A-gcJT&F@>gW?aGMTMA3Q&Vb@D!fG3wQ-@;T?R0FQkt|$vHAjE|UdvliVhENS+kP2H7M<5#Q5( zf6lfi5lFTWyS^4?HIXf`TKz~|SN|GIr{$gsJ-_t%d>?zW@T)m$to+9@^{tNkI&zD= zW^)M*2=sfO0iOY%fo}}(?}LhsV^U&Ep!ey(&N~7i2GHyY>ijIhV^oPri7kORf;Lti zpZ|{s`By#zJ_G+110;~nrc<~iSz9|6$7`*M?LIax+^;3j3&Bp7V^86wcpRH2IHqz1 XF)6Vn5G^SFkAO#m-}wyuRR+ESX^#P~ literal 0 HcmV?d00001 diff --git a/Joke Bot Upgrade_ SQLite Database Integration _ Beginner's Guide.html b/Joke Bot Upgrade_ SQLite Database Integration _ Beginner's Guide.html new file mode 100644 index 0000000..c29734a --- /dev/null +++ b/Joke Bot Upgrade_ SQLite Database Integration _ Beginner's Guide.html @@ -0,0 +1,1556 @@ + + + + + + Joke Bot Upgrade: SQLite Database Integration | Beginner's Guide + + + + +
+ +
+
+
+

Joke Bot Upgrade

+

From Simple Lists to SQLite Database with User Interaction

+
+ +
+

Goal: Upgrade joke bot with database, user submissions, and ratings

+

Prerequisites: Basic Python knowledge, our existing joke bot

+

Time: 60 minutes to complete upgrade

+
+
+
+ + +
+

What Is SQLite?

+

Serverless, self-contained SQL database perfect for Telegram bots

+ +
+

Why SQLite for Our Joke Bot?

+
+
1
+
No Server Needed: Database lives in a single file
+
+ +
+
2
+
Zero Configuration: Just import and use
+
+ +
+
3
+
Lightweight: Perfect for small to medium applications
+
+ +
+
4
+
SQL Standard: Uses standard SQL commands
+
+ +
+
5
+
Built-in Python: No extra installation needed
+
+
+ +
+ Think of it like this: +

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.

+

Perfect for Telegram bots, mobile apps, and desktop applications.

+
+ +
+# SQLite comes built-in with Python! +import sqlite3 + +# Connect to database (creates if doesn't exist) +conn = sqlite3.connect('joke_bot.db') +cursor = conn.cursor() + +# Create a table +cursor.execute('''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 + )''') + +conn.commit() +conn.close()
+
+ + +
+

Our Upgrade Goals

+

From static list to dynamic, user-powered joke database

+ +
+ Current Limitations: +

1. Jokes are hardcoded in Python list

+

2. No way for users to add new jokes

+

3. No rating system to find the best jokes

+

4. Jokes are lost when bot restarts

+
+ +

New Features We'll Add:

+
+
+
1
+
+ SQLite Database:
+ Store jokes permanently in a database file +
+
+ +
+
2
+
+ User Submissions:
+ /addjoke command for users to submit jokes +
+
+ +
+
3
+
+ Rating System:
+ /like and /dislike commands to rate jokes +
+
+ +
+
4
+
+ Top Jokes:
+ /top command to show most popular jokes +
+
+ +
+
5
+
+ Random with Weight:
+ Better jokes appear more often +
+
+
+
+ + +
+

Step 1: Database Setup (10 minutes)

+

Create the SQLite database and connection functions

+ +
# Create a new file: database.py +# This will handle all database operations + +import sqlite3 +from datetime import datetime + +class JokeDatabase: + def __init__(self, db_name='joke_bot.db'): + self.db_name = db_name + self.init_database() + + def get_connection(self): + """Get a database connection""" + conn = sqlite3.connect(self.db_name) + conn.row_factory = sqlite3.Row # Access columns by name + return conn + + def init_database(self): + """Initialize database tables""" + conn = self.get_connection() + cursor = conn.cursor() + + # Create jokes table + cursor.execute('''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 + )''') + + # Create ratings table to track user votes + cursor.execute('''CREATE TABLE IF NOT EXISTS ratings ( + user_id INTEGER, + joke_id INTEGER, + vote INTEGER, -- 1 for like, -1 for dislike + PRIMARY KEY (user_id, joke_id), + FOREIGN KEY (joke_id) REFERENCES jokes(id) + )''') + + conn.commit() + conn.close() + + # Add some default jokes if table is empty + self.add_default_jokes() + + def add_default_jokes(self): + """Add default jokes if database is empty""" + conn = self.get_connection() + cursor = conn.cursor() + + cursor.execute("SELECT COUNT(*) FROM jokes") + count = cursor.fetchone()[0] + + if count == 0: + default_jokes = [ + ("Why did the robot go to school? To recharge his brain! šŸ”‹", 0, "System"), + ("Knock knock!\nWho's there?\nLettuce!\nLettuce who?\nLettuce in!", 0, "System"), + ("Why don't eggs tell jokes? They'd crack each other up! 🄚", 0, "System") + ] + + cursor.executemany('''INSERT INTO jokes (joke_text, user_id, username) + VALUES (?, ?, ?)''', default_jokes) + + conn.commit() + print(f"Added {len(default_jokes)} default jokes to database") + + conn.close()
+ +
+

Database Schema Explained:

+
+
šŸ“
+
jokes table: Stores all jokes with ratings
+
+
+
⭐
+
ratings table: Tracks who voted for which joke
+
+
+
šŸ†”
+
Primary keys: Unique IDs for each record
+
+
+
šŸ”—
+
Foreign key: Links ratings to jokes
+
+
+
+ + +
+

Step 2: Database Operations (15 minutes)

+

Add CRUD (Create, Read, Update, Delete) functions

+ +
# Add these methods to the JokeDatabase class + +def add_joke(self, joke_text, user_id, username): + """Add a new joke to the database""" + conn = self.get_connection() + cursor = conn.cursor() + + cursor.execute('''INSERT INTO jokes (joke_text, user_id, username) + VALUES (?, ?, ?)''', (joke_text, user_id, username)) + + joke_id = cursor.lastrowid + conn.commit() + conn.close() + + return joke_id + +def get_random_joke(self): + """Get a random joke, weighted by rating""" + conn = self.get_connection() + cursor = conn.cursor() + + # Weighted random: jokes with higher likes appear more often + cursor.execute('''SELECT * FROM jokes + ORDER BY (likes - dislikes + 5) * RANDOM() DESC + LIMIT 1''') + + joke = cursor.fetchone() + conn.close() + + return dict(joke) if joke else None + +def get_joke_by_id(self, joke_id): + """Get a specific joke by ID""" + conn = self.get_connection() + cursor = conn.cursor() + + cursor.execute("SELECT * FROM jokes WHERE id = ?", (joke_id,)) + joke = cursor.fetchone() + conn.close() + + return dict(joke) if joke else None + +def get_top_jokes(self, limit=5): + """Get top-rated jokes""" + conn = self.get_connection() + cursor = conn.cursor() + + cursor.execute('''SELECT * FROM jokes + ORDER BY (likes - dislikes) DESC, likes DESC + LIMIT ?''', (limit,)) + + jokes = [dict(row) for row in cursor.fetchall()] + conn.close() + + return jokes + +def get_total_jokes(self): + """Get total number of jokes""" + conn = self.get_connection() + cursor = conn.cursor() + + cursor.execute("SELECT COUNT(*) FROM jokes") + count = cursor.fetchone()[0] + conn.close() + + return count
+ +
+

SQL Functions Explained:

+
+
šŸ“Š
+
Weighted Random: (likes - dislikes + 5) * RANDOM()
+
+
+
ā¬†ļø
+
Top Jokes: Sorted by net score (likes - dislikes)
+
+
+
šŸ’¾
+
Parameterized Queries: Safe from SQL injection
+
+
+
šŸ”„
+
Connection Management: Open/close connections properly
+
+
+
+ + +
+

Step 3: Rating System (15 minutes)

+

Implement like/dislike functionality with vote tracking

+ +
# Add rating methods to JokeDatabase class + +def rate_joke(self, user_id, joke_id, vote): + """ + Rate a joke (like or dislike) + vote: 1 for like, -1 for dislike, 0 to remove rating + """ + conn = self.get_connection() + cursor = conn.cursor() + + # Check if user already voted + cursor.execute('''SELECT vote FROM ratings + WHERE user_id = ? AND joke_id = ?''', (user_id, joke_id)) + + existing_vote = cursor.fetchone() + + if existing_vote: + old_vote = existing_vote[0] + + if vote == 0: + # Remove vote + cursor.execute('''DELETE FROM ratings + WHERE user_id = ? AND joke_id = ?''', (user_id, joke_id)) + + # Update joke counts + if old_vote == 1: + cursor.execute('''UPDATE jokes SET likes = likes - 1 + WHERE id = ?''', (joke_id,)) + elif old_vote == -1: + cursor.execute('''UPDATE jokes SET dislikes = dislikes - 1 + WHERE id = ?''', (joke_id,)) + elif old_vote != vote: + # Change vote + cursor.execute('''UPDATE ratings SET vote = ? + WHERE user_id = ? AND joke_id = ?''', (vote, user_id, joke_id)) + + # Update joke counts (remove old, add new) + if old_vote == 1 and vote == -1: + cursor.execute('''UPDATE jokes + SET likes = likes - 1, dislikes = dislikes + 1 + WHERE id = ?''', (joke_id,)) + elif old_vote == -1 and vote == 1: + cursor.execute('''UPDATE jokes + SET likes = likes + 1, dislikes = dislikes - 1 + WHERE id = ?''', (joke_id,)) + else: + if vote != 0: + # New vote + cursor.execute('''INSERT INTO ratings (user_id, joke_id, vote) + VALUES (?, ?, ?)''', (user_id, joke_id, vote)) + + # Update joke counts + if vote == 1: + cursor.execute('''UPDATE jokes SET likes = likes + 1 + WHERE id = ?''', (joke_id,)) + elif vote == -1: + cursor.execute('''UPDATE jokes SET dislikes = dislikes + 1 + WHERE id = ?''', (joke_id,)) + + conn.commit() + + # Get updated joke info + cursor.execute("SELECT likes, dislikes FROM jokes WHERE id = ?", (joke_id,)) + result = cursor.fetchone() + conn.close() + + return { + 'likes': result[0] if result else 0, + 'dislikes': result[1] if result else 0 + } + +def get_user_vote(self, user_id, joke_id): + """Get user's vote for a specific joke""" + conn = self.get_connection() + cursor = conn.cursor() + + cursor.execute('''SELECT vote FROM ratings + WHERE user_id = ? AND joke_id = ?''', (user_id, joke_id)) + + result = cursor.fetchone() + conn.close() + + return result[0] if result else 0
+ +
+

Rating Logic:

+
+
1
+
Prevent Double Voting: Users can only vote once per joke
+
+
+
2
+
Change Votes: Users can change their mind
+
+
+
3
+
Remove Votes: Users can remove their rating
+
+
+
4
+
Real-time Updates: Counts update immediately
+
+
+
+ + +
+

Step 4: Telegram Bot Integration (15 minutes)

+

Update app.py to use the database

+ +
# Updated app.py with database integration + +from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton +from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters, CallbackQueryHandler +from database import JokeDatabase +import random + +# Initialize database +db = JokeDatabase() + +async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Start command handler""" + welcome_text = """šŸ¤– 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!""" + + await update.message.reply_text(welcome_text) + +async def send_joke(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Send a random joke from database""" + joke = db.get_random_joke() + + if not joke: + await update.message.reply_text("No jokes in database yet! Use /addjoke to add one.") + return + + # Store joke ID in context for rating + context.user_data['last_joke_id'] = joke['id'] + + # Format joke with rating info + rating_text = f"šŸ‘ {joke['likes']} šŸ‘Ž {joke['dislikes']}" + joke_text = f"{joke['joke_text']}\n\n{rating_text}" + + # Add inline buttons for quick rating + keyboard = [ + [ + InlineKeyboardButton("šŸ‘ Like", callback_data=f"like_{joke['id']}"), + InlineKeyboardButton("šŸ‘Ž Dislike", callback_data=f"dislike_{joke['id']}") + ] + ] + reply_markup = InlineKeyboardMarkup(keyboard) + + await update.message.reply_text(joke_text, reply_markup=reply_markup) + +async def add_joke_command(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Handle /addjoke command""" + if not context.args: + await update.message.reply_text( + "Please provide a joke after the command:\n" + "Example: /addjoke Why did the chicken cross the road?" + ) + return + + joke_text = " ".join(context.args) + user = update.effective_user + + # Add to database + joke_id = db.add_joke(joke_text, user.id, user.username) + + await update.message.reply_text( + f"āœ… Joke added successfully! (ID: {joke_id})\n" + "Others can now rate it with /like and /dislike" + )
+ +
+

New Bot Features:

+
+
šŸ¤–
+
Inline Buttons: Quick like/dislike without commands
+
+
+
šŸ’¾
+
User Context: Remember last joke for rating
+
+
+ šŸ“Š
+
Real Stats: Display actual like/dislike counts
+
+
+
šŸ‘¤
+
User Tracking: Record who submitted each joke
+
+
+
+ + +
+

Step 5: Rating Commands (10 minutes)

+

Add like/dislike commands and callback handlers

+ +
async def like_joke(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Handle /like command""" + user_id = update.effective_user.id + + # Get last joke from context or arguments + if context.args and context.args[0].isdigit(): + joke_id = int(context.args[0]) + elif 'last_joke_id' in context.user_data: + joke_id = context.user_data['last_joke_id'] + else: + await update.message.reply_text( + "Please view a joke first with /joke, or specify a joke ID: /like 123" + ) + return + + # Rate the joke + result = db.rate_joke(user_id, joke_id, 1) + joke = db.get_joke_by_id(joke_id) + + if joke: + await update.message.reply_text( + f"šŸ‘ Liked joke #{joke_id}!\n" + f"Current rating: {result['likes']} šŸ‘ {result['dislikes']} šŸ‘Ž" + ) + else: + await update.message.reply_text("Joke not found!") + +async def dislike_joke(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Handle /dislike command""" + user_id = update.effective_user.id + + if context.args and context.args[0].isdigit(): + joke_id = int(context.args[0]) + elif 'last_joke_id' in context.user_data: + joke_id = context.user_data['last_joke_id'] + else: + await update.message.reply_text( + "Please view a joke first with /joke, or specify a joke ID: /dislike 123" + ) + return + + result = db.rate_joke(user_id, joke_id, -1) + joke = db.get_joke_by_id(joke_id) + + if joke: + await update.message.reply_text( + f"šŸ‘Ž Disliked joke #{joke_id}!\n" + f"Current rating: {result['likes']} šŸ‘ {result['dislikes']} šŸ‘Ž" + ) + else: + await update.message.reply_text("Joke not found!") + +async def button_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Handle inline button clicks""" + query = update.callback_query + await query.answer() + + data = query.data + user_id = query.from_user.id + + if data.startswith('like_'): + joke_id = int(data.split('_')[1]) + result = db.rate_joke(user_id, joke_id, 1) + await query.edit_message_text( + text=query.message.text.split('\n\n')[0] + + f"\n\nšŸ‘ {result['likes']} šŸ‘Ž {result['dislikes']}", + reply_markup=query.message.reply_markup + ) + elif data.startswith('dislike_'): + joke_id = int(data.split('_')[1]) + result = db.rate_joke(user_id, joke_id, -1) + await query.edit_message_text( + text=query.message.text.split('\n\n')[0] + + f"\n\nšŸ‘ {result['likes']} šŸ‘Ž {result['dislikes']}", + reply_markup=query.message.reply_markup + )
+ +
+

Rating Features:

+
+
1
+
Multiple Methods: Command or inline button
+
+
+
2
+
Flexible Targeting: By ID or last viewed joke
+
+
+
3
+
Real-time Updates: Buttons update instantly
+
+
+
4
+
Feedback: Users see their vote was counted
+
+
+
+ + +
+

Step 6: Additional Features (10 minutes)

+

Add statistics, top jokes, and admin commands

+ +
async def top_jokes(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Show top-rated jokes""" + limit = 5 + if context.args and context.args[0].isdigit(): + limit = min(int(context.args[0]), 20) # Max 20 jokes + + jokes = db.get_top_jokes(limit) + + if not jokes: + await update.message.reply_text("No jokes in database yet!") + return + + response = f"šŸ† TOP {len(jokes)} JOKES šŸ†\n\n" + + for i, joke in enumerate(jokes, 1): + score = joke['likes'] - joke['dislikes'] + response += f"{i}. ID {joke['id']}: Score {score} (šŸ‘{joke['likes']} šŸ‘Ž{joke['dislikes']})\n" + response += f" \"{joke['joke_text'][:50]}...\"\n\n" + + await update.message.reply_text(response) + +async def bot_stats(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Show bot statistics""" + total_jokes = db.get_total_jokes() + + # Get total likes/dislikes + conn = db.get_connection() + cursor = conn.cursor() + cursor.execute("SELECT SUM(likes), SUM(dislikes) FROM jokes") + result = cursor.fetchone() + total_likes = result[0] or 0 + total_dislikes = result[1] or 0 + conn.close() + + stats_text = f"""šŸ“Š JOKE BOT STATISTICS šŸ“Š + +Total Jokes: {total_jokes} +Total Ratings: {total_likes + total_dislikes} +šŸ‘ Total Likes: {total_likes} +šŸ‘Ž Total Dislikes: {total_dislikes} +šŸ“ˆ Approval Rate: {(total_likes/(total_likes+total_dislikes)*100 if (total_likes+total_dislikes) > 0 else 0):.1f}% + +Commands Today: +/joke - Get random joke +/addjoke - Submit your joke +/top - See top jokes +/stats - View these stats""" + + await update.message.reply_text(stats_text) + +async def my_jokes(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Show user's submitted jokes""" + user_id = update.effective_user.id + + conn = db.get_connection() + cursor = conn.cursor() + cursor.execute('''SELECT id, joke_text, likes, dislikes + FROM jokes WHERE user_id = ? + ORDER BY created_at DESC LIMIT 10''', (user_id,)) + + user_jokes = [dict(row) for row in cursor.fetchall()] + conn.close() + + if not user_jokes: + await update.message.reply_text("You haven't submitted any jokes yet! Use /addjoke") + return + + response = f"šŸ“ YOUR JOKES ({len(user_jokes)} total)\n\n" + + for joke in user_jokes: + score = joke['likes'] - joke['dislikes'] + response += f"ID {joke['id']}: Score {score} (šŸ‘{joke['likes']} šŸ‘Ž{joke['dislikes']})\n" + response += f" \"{joke['joke_text'][:60]}...\"\n\n" + + await update.message.reply_text(response)
+ +
+

Enhanced Features:

+
+
šŸ“Š
+
Statistics: Track bot usage and engagement
+
+
+
šŸ†
+
Leaderboard: Top jokes ranking system
+
+
+
šŸ‘¤
+
Personal Stats: Users see their own contributions
+
+
+
šŸ“ˆ
+
Analytics: Approval rate and engagement metrics
+
+
+
+ + +
+

Step 7: Complete Main Function (5 minutes)

+

Put it all together and run the upgraded bot

+ +
def main(): + # Using the provided bot token + BOT_TOKEN = "YOUR_BOT_TOKEN_HERE" + + # Create application + app = Application.builder().token(BOT_TOKEN).build() + + # Add command handlers + app.add_handler(CommandHandler("start", start)) + app.add_handler(CommandHandler("joke", send_joke)) + app.add_handler(CommandHandler("addjoke", add_joke_command)) + app.add_handler(CommandHandler("like", like_joke)) + app.add_handler(CommandHandler("dislike", dislike_joke)) + app.add_handler(CommandHandler("top", top_jokes)) + app.add_handler(CommandHandler("stats", bot_stats)) + app.add_handler(CommandHandler("myjokes", my_jokes)) + + # Add callback handler for inline buttons + app.add_handler(CallbackQueryHandler(button_callback)) + + print("šŸ¤– Joke Bot 2.0 is running...") + print("šŸ“Š Database initialized: joke_bot.db") + print("šŸŽÆ Features: User submissions, ratings, leaderboard") + print("Press Ctrl+C to stop.\n") + + app.run_polling() + +if __name__ == "__main__": + main()
+ +
+

Project Structure:

+
+joke_bot_2.0/ +ā”œā”€ā”€ app.py # Main bot file (updated) +ā”œā”€ā”€ database.py # SQLite database class +ā”œā”€ā”€ joke_bot.db # SQLite database (auto-created) +ā”œā”€ā”€ requirements.txt # python-telegram-bot==20.3 +└── README.md # Setup instructions
+ +
+
1
+
Install: pip install python-telegram-bot==20.3
+
+ +
+
2
+
Run: python app.py
+
+ +
+
3
+
Test: Open Telegram, find your bot, type /start
+
+ +
+
4
+
Deploy: Can run on Raspberry Pi, VPS, or cloud
+
+
+
+ + +
+

Database Administration Tools

+

Tools to view and manage your SQLite database

+ +
# admin_tools.py - Database management utilities + +import sqlite3 +import pandas as pd +from datetime import datetime + +class JokeAdmin: + def __init__(self, db_name='joke_bot.db'): + self.db_name = db_name + + def export_to_csv(self, filename='jokes_export.csv'): + """Export all jokes to CSV""" + conn = sqlite3.connect(self.db_name) + df = pd.read_sql_query("SELECT * FROM jokes", conn) + df.to_csv(filename, index=False, encoding='utf-8') + conn.close() + print(f"Exported {len(df)} jokes to {filename}") + + def show_stats(self): + """Show detailed statistics""" + conn = sqlite3.connect(self.db_name) + cursor = conn.cursor() + + # Basic counts + cursor.execute("SELECT COUNT(*) FROM jokes") + total_jokes = cursor.fetchone()[0] + + cursor.execute("SELECT COUNT(DISTINCT user_id) FROM jokes WHERE user_id != 0") + unique_users = cursor.fetchone()[0] + + cursor.execute("SELECT SUM(likes), SUM(dislikes) FROM jokes") + likes, dislikes = cursor.fetchone() + + # Top contributors + cursor.execute('''SELECT username, COUNT(*) as joke_count + FROM jokes WHERE user_id != 0 + GROUP BY user_id ORDER BY joke_count DESC LIMIT 5''') + top_contributors = cursor.fetchall() + + conn.close() + + print(f"""šŸ“Š DATABASE STATISTICS šŸ“Š + +Total Jokes: {total_jokes} +Unique Contributors: {unique_users} +Total Likes: {likes or 0} +Total Dislikes: {dislikes or 0} + +šŸ† Top Contributors:""") + + for username, count in top_contributors: + print(f" {username}: {count} jokes") + + def backup_database(self): + """Create a backup of the database""" + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') + backup_name = f"backup_joke_bot_{timestamp}.db" + + import shutil + shutil.copy2(self.db_name, backup_name) + print(f"Backup created: {backup_name}") + +# Usage example +if __name__ == "__main__": + admin = JokeAdmin() + admin.show_stats() + admin.export_to_csv() + admin.backup_database()
+ +
+

Admin Features:

+
+
šŸ’¾
+
Backups: Automatic database backups
+
+
+
šŸ“Š
+
Analytics: Detailed usage statistics
+
+
+
šŸ“¤
+
Export: CSV export for analysis
+
+
+
šŸ‘‘
+
Leaderboards: Top contributors recognition
+
+
+ +
+ SQLite Browser Tool: +

Download DB Browser for SQLite (free) to visually explore your database:

+

• View tables and data

+

• Run SQL queries

+

• Export/import data

+

• Available for Windows, Mac, Linux

+
+
+ + +
+

Advanced Features (Optional)

+

Take your joke bot to the next level

+ +
# advanced_features.py - Optional enhancements + +# 1. Joke Categories +def add_categories(): + """Add category support to jokes""" + conn = sqlite3.connect('joke_bot.db') + cursor = conn.cursor() + + # Add category column + try: + cursor.execute("ALTER TABLE jokes ADD COLUMN category TEXT DEFAULT 'general'") + except sqlite3.OperationalError: + pass # Column already exists + + # Create categories table + cursor.execute('''CREATE TABLE IF NOT EXISTS categories ( + id INTEGER PRIMARY KEY, + name TEXT UNIQUE, + description TEXT + )''') + + # Insert default categories + categories = [ + ('programming', 'Programming and tech jokes'), + ('dad', 'Classic dad jokes'), + ('animal', 'Animal jokes'), + ('school', 'School and education jokes') + ] + + cursor.executemany('''INSERT OR IGNORE INTO categories (name, description) + VALUES (?, ?)''', categories) + + conn.commit() + conn.close() + +# 2. Daily Joke Notification +async def send_daily_joke(context: ContextTypes.DEFAULT_TYPE): + """Send daily joke to subscribed users""" + joke = db.get_random_joke() + if joke: + # Get subscribed users from database + conn = db.get_connection() + cursor = conn.cursor() + cursor.execute("SELECT user_id FROM subscribers WHERE active = 1") + users = cursor.fetchall() + conn.close() + + for user_id in users: + try: + await context.bot.send_message( + chat_id=user_id[0], + text=f"šŸ“… Daily Joke!\n\n{joke['joke_text']}" + ) + except Exception as e: + print(f"Failed to send to user {user_id}: {e}") + +# 3. Joke Search Function +def search_jokes(search_term, limit=10): + """Search jokes by keyword""" + conn = sqlite3.connect('joke_bot.db') + cursor = conn.cursor() + + cursor.execute('''SELECT * FROM jokes + WHERE joke_text LIKE ? + ORDER BY (likes - dislikes) DESC + LIMIT ?''', (f'%{search_term}%', limit)) + + jokes = [dict(row) for row in cursor.fetchall()] + conn.close() + return jokes
+ +
+

Optional Enhancements:

+
+
šŸ·ļø
+
Categories: Organize jokes by type
+
+
+
šŸ””
+
Notifications: Daily joke subscriptions
+
+
+
šŸ”
+
Search: Find jokes by keyword
+
+
+
šŸ¤–
+
AI Integration: Generate jokes with GPT API
+
+
+
🌐
+
Web Dashboard: View stats in browser
+
+
+
+ + +
+

Testing Your Upgraded Bot

+

Comprehensive testing guide

+ +
+ Test Commands Sequence: +

1. /start - See welcome message with all commands

+

2. /joke - Get random joke with rating buttons

+

3. Click šŸ‘ and šŸ‘Ž buttons - Test inline rating

+

4. /addjoke Why did the Python cross the road? To get to the other side!

+

5. /joke again - See if new joke appears

+

6. /like and /dislike - Test command rating

+

7. /top 3 - See top jokes leaderboard

+

8. /stats - Check bot statistics

+

9. /myjokes - View your submissions

+
+ +
+

Expected Results:

+
+
āœ…
+
Database File: joke_bot.db created automatically
+
+
+
āœ…
+
Default Jokes: 3 jokes pre-loaded
+
+
+
āœ…
+
Rating Persistence: Votes saved between restarts
+
+
+
āœ…
+
User Tracking: Your username saved with submissions
+
+
+
āœ…
+
Weighted Random: Better jokes appear more often
+
+
+ +
+# Quick database check +import sqlite3 +conn = sqlite3.connect('joke_bot.db') +cursor = conn.cursor() +cursor.execute("SELECT name FROM sqlite_master WHERE type='table'") +tables = cursor.fetchall() +print("Tables:", tables) +cursor.execute("SELECT COUNT(*) FROM jokes") +count = cursor.fetchone()[0] +print(f"Total jokes: {count}") +conn.close()
+
+ + +
+

Deployment Options

+

Where to run your upgraded joke bot 24/7

+ +
+

Free Options:

+
+
šŸ–„ļø
+
+ Raspberry Pi:
+ • Always-on at home
+ • Low power consumption
+ • Full control +
+
+ +
+
ā˜ļø
+
+ PythonAnywhere:
+ • Free tier available
+ • Web-based IDE
+ • Scheduled tasks +
+
+ +
+
šŸš€
+
+ Replit:
+ • Free cloud IDE
+ • Always-on option
+ • Easy sharing +
+
+
+ +
+

Paid Options:

+
+
šŸ’»
+
+ VPS (DigitalOcean, Linode):
+ • $5/month
+ • Full root access
+ • Scalable +
+
+ +
+
⚔
+
+ Heroku:
+ • Easy deployment
+ • Add-ons available
+ • Good free tier (with limits) +
+
+ +
+
🐳
+
+ Docker:
+ • Containerized deployment
+ • Runs anywhere
+ • Easy updates +
+
+
+ +
+ Deployment Checklist: +

1. Test locally first

+

2. Backup your database

+

3. Set up proper logging

+

4. Configure automatic restarts (using systemd or supervisor)

+

5. Set up regular database backups

+

6. Monitor bot activity

+
+
+ + +
+

Complete Project Review

+

What you've accomplished in 60 minutes

+ +
+ šŸŽ‰ CONGRATULATIONS! šŸŽ‰ +

You've successfully upgraded your simple joke bot to a full-featured application with:

+
+ +
+

Core Upgrades:

+
+
āœ…
+
SQLite Database: Persistent storage for jokes
+
+
+
āœ…
+
User Submissions: Community-driven content
+
+
+
āœ…
+
Rating System: Like/dislike with tracking
+
+
+
āœ…
+
Inline Buttons: Better user experience
+
+
+
āœ…
+
Statistics: Track bot usage and engagement
+
+
+
āœ…
+
Leaderboard: Top jokes ranking
+
+
+ +
+

Technical Skills Learned:

+
+
šŸ
+
Python: Advanced Python programming
+
+
+
šŸ—„ļø
+
SQLite: Database design and queries
+
+
+
šŸ¤–
+
Telegram Bot API: Advanced bot features
+
+
+
šŸ“Š
+
Data Modeling: Table design and relationships
+
+
+
šŸ”§
+
Software Architecture: Modular, maintainable code
+
+
+ +
+ Next Steps: +

1. Add joke categories (/programming, /dadjokes)

+

2. Implement daily joke notifications

+

3. Create a web dashboard for statistics

+

4. Add joke search functionality

+

5. Implement user profiles and achievements

+

6. Add multi-language support

+
+ +
+

Your Joke Bot is Now Production-Ready! šŸš€

+

Share it with friends, deploy it online, and watch your joke collection grow!

+
+
+ + + + + + + + \ No newline at end of file diff --git a/Joke Bot Upgrade_ SQLite Database Integration _ Beginner's Guide_files/css2 b/Joke Bot Upgrade_ SQLite Database Integration _ Beginner's Guide_files/css2 new file mode 100644 index 0000000..b7d63d9 --- /dev/null +++ b/Joke Bot Upgrade_ SQLite Database Integration _ Beginner's Guide_files/css2 @@ -0,0 +1,315 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7W0Q5nw.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7W0Q5nw.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7W0Q5nw.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7W0Q5nw.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7W0Q5nw.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/jokes-bot-v3.0/.DS_Store b/jokes-bot-v3.0/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7595df5eb08ea51a7927277b57dd384b9b3e94d5 GIT binary patch literal 6148 zcmeHKF;2r!47DLcB$ke_{VQ}}|5RZHsRsa+B9LgCE_BYuJ-7@PVC52=fM@#yiJ~$x zz_aB4@@>ET`+ooBp+67|u7U>E404lF(b0PQ#44c9(P0FwoPxnLKF2uy^<*e5x_%-~~Q0wJbycGkz6=P$q__$Y>>>Bx8unTlL;!X$hN5FKU JQGwr3-~;r)E7t%3 literal 0 HcmV?d00001 diff --git a/jokes-bot-v3.0/README.md b/jokes-bot-v3.0/README.md new file mode 100644 index 0000000..ed329ec --- /dev/null +++ b/jokes-bot-v3.0/README.md @@ -0,0 +1,45 @@ +# Telegram Joke Bot + +A simple Telegram bot that tells jokes when you send it the `/joke` command. + +## Setup Instructions + +1. **Install required packages** + ```bash + pip install -r requirements.txt + ``` + +2. **Get a bot token** + - Talk to [@BotFather](https://t.me/BotFather) on Telegram + - Create a new bot with `/newbot` + - Copy the token provided by BotFather + +3. **Set your bot token** + You can set your bot token in two ways: + + Option A: Set as environment variable + ```bash + export BOT_TOKEN="your_token_here" + ``` + + Option B: Replace "YOUR_BOT_TOKEN_HERE" in jokes.py with your actual token + +4. **Run the bot** + ```bash + python jokes.py + ``` + +## Bot Commands + +- `/start` - Start the bot and get welcome message +- `/joke` - Get a random joke +- `/help` - Show help message + +## Features + +- Sends random jokes from a predefined list +- Easy to add more jokes to the collection +- Simple and lightweight implementation + + + diff --git a/jokes-bot-v3.0/app.py b/jokes-bot-v3.0/app.py new file mode 100644 index 0000000..fb6f820 --- /dev/null +++ b/jokes-bot-v3.0/app.py @@ -0,0 +1,29 @@ +from telegram import Update +from telegram.ext import Application, CommandHandler, ContextTypes +import random + +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! 🄚" +] + +async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): + await update.message.reply_text("Hi! Type /joke for a funny joke! šŸ˜„") + +async def send_joke(update: Update, context: ContextTypes.DEFAULT_TYPE): + joke = random.choice(JOKE_LIST) + await update.message.reply_text(joke) + +def main(): + # Using the provided bot token + BOT_TOKEN = "" + + app = Application.builder().token(BOT_TOKEN).build() + app.add_handler(CommandHandler("start", start)) + app.add_handler(CommandHandler("joke", send_joke)) + print("Bot is running... Press Ctrl+C to stop.") + app.run_polling() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/jokes-bot-v3.0/requirements.txt b/jokes-bot-v3.0/requirements.txt new file mode 100644 index 0000000..11a50f9 --- /dev/null +++ b/jokes-bot-v3.0/requirements.txt @@ -0,0 +1 @@ +python-telegram-bot \ No newline at end of file