1023 lines
38 KiB
HTML
1023 lines
38 KiB
HTML
<!DOCTYPE html>
|
|
<!-- saved from url=(0063)file:///Users/home/Downloads/deepseek_html_20260202_d29063.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>Telegram Joke Bot Development</title>
|
|
<style>
|
|
/* === MINIMALIST PROFESSIONAL STYLES === */
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
color: #1a1a1a;
|
|
line-height: 1.5;
|
|
height: 100vh;
|
|
overflow: hidden;
|
|
background: #ffffff;
|
|
}
|
|
|
|
.presentation-container {
|
|
max-width: 900px;
|
|
height: 100vh;
|
|
margin: 0 auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 0;
|
|
}
|
|
|
|
.slide {
|
|
display: none;
|
|
flex: 1;
|
|
padding: 40px;
|
|
background: white;
|
|
overflow-y: auto;
|
|
max-height: calc(100vh - 70px);
|
|
}
|
|
|
|
.active {
|
|
display: block;
|
|
animation: fadeIn 0.3s ease;
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; }
|
|
to { opacity: 1; }
|
|
}
|
|
|
|
/* === TITLE SLIDE STYLES === */
|
|
.title-slide {
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
text-align: center;
|
|
height: 100%;
|
|
padding: 40px;
|
|
}
|
|
|
|
.title-slide-content {
|
|
max-width: 700px;
|
|
}
|
|
|
|
.thesis-title {
|
|
font-weight: 700;
|
|
font-size: 2.4rem;
|
|
color: #2c3e50;
|
|
margin-bottom: 15px;
|
|
line-height: 1.1;
|
|
}
|
|
|
|
.thesis-subtitle {
|
|
font-size: 1.2rem;
|
|
color: #5d6d7e;
|
|
margin-bottom: 40px;
|
|
font-weight: 400;
|
|
}
|
|
|
|
.author-info {
|
|
margin-top: 50px;
|
|
padding-top: 30px;
|
|
border-top: 1px solid #e0e0e0;
|
|
width: 100%;
|
|
max-width: 600px;
|
|
}
|
|
|
|
.institution {
|
|
font-size: 1rem;
|
|
color: #7f8c8d;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.team-info {
|
|
font-size: 0.95rem;
|
|
color: #34495e;
|
|
margin: 10px 0;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.date {
|
|
font-size: 0.9rem;
|
|
color: #95a5a6;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
/* === OPTIMIZED TYPOGRAPHY === */
|
|
h1 {
|
|
font-weight: 600;
|
|
font-size: 2rem;
|
|
color: #2c3e50;
|
|
margin-bottom: 20px;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
h2 {
|
|
font-weight: 600;
|
|
font-size: 1.6rem;
|
|
color: #34495e;
|
|
margin-bottom: 20px;
|
|
padding-bottom: 15px;
|
|
border-bottom: 2px solid #ecf0f1;
|
|
}
|
|
|
|
h3 {
|
|
font-weight: 600;
|
|
font-size: 1.1rem;
|
|
color: #2c3e50;
|
|
margin-bottom: 12px;
|
|
margin-top: 25px;
|
|
}
|
|
|
|
p {
|
|
font-size: 1rem;
|
|
color: #4a5568;
|
|
margin-bottom: 15px;
|
|
max-width: 800px;
|
|
}
|
|
|
|
.lead {
|
|
font-size: 1.1rem;
|
|
color: #5d6d7e;
|
|
font-weight: 500;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
/* === CLEAN LAYOUT COMPONENTS === */
|
|
.section {
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.info-block {
|
|
background: #f8f9fa;
|
|
padding: 20px;
|
|
margin-bottom: 25px;
|
|
border-left: 4px solid #3498db;
|
|
}
|
|
|
|
/* === CLEAN LISTS === */
|
|
.simple-list {
|
|
margin: 20px 0;
|
|
list-style: none;
|
|
padding-left: 0;
|
|
}
|
|
|
|
.simple-list li {
|
|
padding: 8px 0;
|
|
padding-left: 24px;
|
|
position: relative;
|
|
font-size: 0.95rem;
|
|
color: #4a5568;
|
|
}
|
|
|
|
.simple-list li:before {
|
|
content: "•";
|
|
position: absolute;
|
|
left: 0;
|
|
color: #3498db;
|
|
font-weight: bold;
|
|
font-size: 1.2rem;
|
|
}
|
|
|
|
/* === CLEAN COMPONENTS === */
|
|
.feature-group {
|
|
margin: 25px 0;
|
|
}
|
|
|
|
.feature-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
margin-bottom: 15px;
|
|
padding-bottom: 15px;
|
|
border-bottom: 1px solid #ecf0f1;
|
|
}
|
|
|
|
.feature-item:last-child {
|
|
border-bottom: none;
|
|
margin-bottom: 0;
|
|
padding-bottom: 0;
|
|
}
|
|
|
|
.feature-icon {
|
|
background: #3498db;
|
|
color: white;
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 15px;
|
|
font-weight: 600;
|
|
flex-shrink: 0;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.feature-content {
|
|
flex: 1;
|
|
color: #4a5568;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
/* === CLEAN NAVIGATION === */
|
|
.navigation {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 15px 40px;
|
|
height: 70px;
|
|
flex-shrink: 0;
|
|
border-top: 1px solid #e0e0e0;
|
|
background: white;
|
|
}
|
|
|
|
.nav-btn {
|
|
padding: 8px 24px;
|
|
background: #2c3e50;
|
|
color: white;
|
|
border: none;
|
|
cursor: pointer;
|
|
font-size: 0.9rem;
|
|
font-weight: 500;
|
|
transition: background-color 0.2s;
|
|
}
|
|
|
|
.nav-btn:hover:not(:disabled) {
|
|
background: #1a252f;
|
|
}
|
|
|
|
.nav-btn:disabled {
|
|
background: #bdc3c7;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.slide-counter {
|
|
font-weight: 500;
|
|
color: #7f8c8d;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* === HIGHLIGHT BOX === */
|
|
.highlight {
|
|
background: #f8f9fa;
|
|
padding: 20px;
|
|
margin: 25px 0;
|
|
border-left: 4px solid #3498db;
|
|
}
|
|
|
|
/* === DEVELOPMENT TIMELINE === */
|
|
.timeline {
|
|
margin: 30px 0;
|
|
position: relative;
|
|
}
|
|
|
|
.timeline-item {
|
|
display: flex;
|
|
margin-bottom: 25px;
|
|
position: relative;
|
|
}
|
|
|
|
.timeline-marker {
|
|
background: #3498db;
|
|
color: white;
|
|
width: 40px;
|
|
height: 40px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 20px;
|
|
flex-shrink: 0;
|
|
font-weight: bold;
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
.timeline-content {
|
|
flex: 1;
|
|
background: #f8f9fa;
|
|
padding: 15px;
|
|
border-left: 3px solid #3498db;
|
|
}
|
|
|
|
/* === CODE BLOCK === */
|
|
.code-block {
|
|
background: #f8f9fa;
|
|
color: #2c3e50;
|
|
padding: 20px;
|
|
margin: 25px 0;
|
|
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
|
|
font-size: 13px;
|
|
line-height: 1.5;
|
|
overflow-x: auto;
|
|
border-left: 4px solid #3498db;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
.code-comment {
|
|
color: #7f8c8d;
|
|
}
|
|
|
|
.code-keyword {
|
|
color: #2980b9;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.code-string {
|
|
color: #27ae60;
|
|
}
|
|
|
|
.code-function {
|
|
color: #8e44ad;
|
|
}
|
|
|
|
/* === TERMINAL DEMO === */
|
|
.terminal {
|
|
background: #1a1a1a;
|
|
color: #f0f0f0;
|
|
padding: 20px;
|
|
margin: 25px 0;
|
|
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
|
|
font-size: 13px;
|
|
line-height: 1.5;
|
|
overflow-x: auto;
|
|
border-radius: 0;
|
|
}
|
|
|
|
.terminal-line {
|
|
margin-bottom: 10px;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
.terminal-prompt {
|
|
color: #3498db;
|
|
}
|
|
|
|
.terminal-success {
|
|
color: #2ecc71;
|
|
}
|
|
|
|
.terminal-emoji {
|
|
margin-right: 5px;
|
|
}
|
|
|
|
.terminal-title {
|
|
color: #ecf0f1;
|
|
margin-bottom: 15px;
|
|
font-size: 0.95rem;
|
|
padding-bottom: 10px;
|
|
border-bottom: 1px solid #34495e;
|
|
}
|
|
|
|
/* === TECH STACK === */
|
|
.tech-stack {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
margin: 20px 0;
|
|
}
|
|
|
|
.tech-tag {
|
|
background: #ecf0f1;
|
|
padding: 6px 14px;
|
|
font-size: 0.85rem;
|
|
color: #2c3e50;
|
|
border: 1px solid #d5dbdb;
|
|
}
|
|
|
|
/* === BENEFITS GRID === */
|
|
.benefits-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
gap: 20px;
|
|
margin: 25px 0;
|
|
}
|
|
|
|
.benefit-card {
|
|
background: white;
|
|
padding: 20px;
|
|
border: 1px solid #e0e0e0;
|
|
}
|
|
|
|
.benefit-icon {
|
|
font-size: 2rem;
|
|
margin-bottom: 15px;
|
|
color: #3498db;
|
|
}
|
|
|
|
.benefit-title {
|
|
font-weight: 600;
|
|
color: #2c3e50;
|
|
margin-bottom: 10px;
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
/* === FUTURE APPLICATIONS === */
|
|
.future-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
gap: 20px;
|
|
margin: 25px 0;
|
|
}
|
|
|
|
.future-card {
|
|
background: white;
|
|
padding: 20px;
|
|
border: 1px solid #e0e0e0;
|
|
}
|
|
|
|
.future-icon {
|
|
font-size: 2rem;
|
|
margin-bottom: 15px;
|
|
color: #3498db;
|
|
}
|
|
|
|
.future-title {
|
|
font-weight: 600;
|
|
color: #2c3e50;
|
|
margin-bottom: 10px;
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
/* === RESPONSIVE DESIGN === */
|
|
@media (max-width: 768px) {
|
|
.presentation-container {
|
|
padding: 0;
|
|
}
|
|
|
|
.slide {
|
|
padding: 30px;
|
|
max-height: calc(100vh - 70px);
|
|
}
|
|
|
|
.navigation {
|
|
padding: 15px 30px;
|
|
}
|
|
|
|
.thesis-title {
|
|
font-size: 2rem;
|
|
}
|
|
|
|
.thesis-subtitle {
|
|
font-size: 1.1rem;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 1.7rem;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
h2 {
|
|
font-size: 1.4rem;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
h3 {
|
|
font-size: 1rem;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.nav-btn {
|
|
padding: 6px 16px;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.future-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="presentation-container">
|
|
<!-- Slide 1: Title Slide -->
|
|
<div class="slide" id="slide1">
|
|
<div class="title-slide">
|
|
<div class="title-slide-content">
|
|
<h1 class="thesis-title">Telegram Joke Bot Development</h1>
|
|
<p class="thesis-subtitle">From Hardcoded Jokes to Community-Driven Platform</p>
|
|
|
|
<div class="author-info">
|
|
<div class="institution">
|
|
Technolyceum Programming Project
|
|
</div>
|
|
|
|
<div class="team-info">
|
|
Student Developers: Дашунин Дмитрий, Ерохин Даниил, Овганова Инна, Полковников Артём, Лазарев Дмитрий
|
|
</div>
|
|
|
|
<div class="team-info">
|
|
Supervisor: Bob Santos
|
|
</div>
|
|
|
|
<div class="date">
|
|
Academic Year 2025-2026
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Slide 2: Development Timeline -->
|
|
<div class="slide" id="slide2">
|
|
<h1>Development Journey</h1>
|
|
|
|
<div class="highlight">
|
|
<h3>Objective</h3>
|
|
<p>Progressively develop a Telegram bot from basic joke delivery to a community-driven platform with AI integration.</p>
|
|
</div>
|
|
|
|
<div class="timeline">
|
|
<div class="timeline-item">
|
|
<div class="timeline-marker">1</div>
|
|
<div class="timeline-content">
|
|
<strong>Phase 1: Hardcoded Jokes</strong><br>
|
|
Initial Telegram bot with static joke list for API testing
|
|
</div>
|
|
</div>
|
|
|
|
<div class="timeline-item">
|
|
<div class="timeline-marker">2</div>
|
|
<div class="timeline-content">
|
|
<strong>Phase 2: AI-Generated Jokes</strong><br>
|
|
Integration with Yandex AI API for dynamic joke generation
|
|
</div>
|
|
</div>
|
|
|
|
<div class="timeline-item">
|
|
<div class="timeline-marker">3</div>
|
|
<div class="timeline-content">
|
|
<strong>Phase 3: User-Generated Content</strong><br>
|
|
Database integration with voting and approval system
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Slide 3: Phase 1 - Hardcoded Jokes -->
|
|
<div class="slide" id="slide3">
|
|
<h1>Phase 1: Hardcoded Jokes</h1>
|
|
<p class="lead">Initial implementation testing Telegram Bot API with static content.</p>
|
|
|
|
<div class="code-block">
|
|
<span class="code-comment"># app.py — Teacher-Only Telegram Joke Bot</span>
|
|
<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> ApplicationBuilder, CommandHandler, ContextTypes
|
|
<span class="code-keyword">import</span> random
|
|
|
|
<span class="code-comment"># 🔑 REPLACE WITH REAL TOKEN FROM @BotFather</span>
|
|
BOT_TOKEN = <span class="code-string">"7864875699:AAEWf6ff1DYNzPvW6Dbn7D2W5aavg9KPhgY"</span>
|
|
|
|
<span class="code-comment"># --- COPY STUDENT JOKES HERE BEFORE CLASS ---</span>
|
|
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?\\nBoo!\\nBoo who?\\nDon't cry! 😂"</span>,
|
|
<span class="code-string">"Why don't eggs tell jokes? They'd crack each other up! 🥚"</span>,
|
|
<span class="code-string">"What do you call a penguin in the desert? Lost! 🐧"</span>,
|
|
<span class="code-comment"># Add student jokes here</span>
|
|
]
|
|
|
|
<span class="code-keyword">async 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! I'm your Joke Bot!\\nType /joke for a funny joke in English! 😄"</span>)
|
|
|
|
<span class="code-keyword">async 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>():
|
|
print(<span class="code-string">"🚀 Starting Joke Bot..."</span>)
|
|
app = ApplicationBuilder().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 class="info-block">
|
|
<h3>Initial Implementation Features</h3>
|
|
<ul class="simple-list">
|
|
<li>Basic Telegram Bot API integration</li>
|
|
<li>Static list of pre-approved jokes</li>
|
|
<li>/start and /joke command handlers</li>
|
|
<li>Random joke selection from hardcoded list</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Slide 4: Phase 2 - AI Integration -->
|
|
<div class="slide" id="slide4">
|
|
<h1>Phase 2: AI-Generated Jokes</h1>
|
|
<p class="lead">Integration with Yandex AI API for dynamic content generation.</p>
|
|
|
|
<div class="code-block">
|
|
<span class="code-keyword">import</span> os
|
|
<span class="code-keyword">import</span> random
|
|
<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, MessageHandler, filters
|
|
<span class="code-keyword">import</span> requests
|
|
<span class="code-keyword">from</span> dotenv <span class="code-keyword">import</span> load_dotenv
|
|
|
|
<span class="code-comment"># Load environment variables</span>
|
|
load_dotenv()
|
|
|
|
YANDEX_API_URL = <span class="code-string">'https://llm.api.cloud.yandex.net/foundationModels/v1/completion'</span>
|
|
YANDEX_FOLDER_ID = os.getenv(<span class="code-string">'YANDEX_FOLDER_ID'</span>)
|
|
YANDEX_API_KEY = os.getenv(<span class="code-string">'YANDEX_API_KEY'</span>)
|
|
|
|
<span class="code-comment"># Store conversation history per user</span>
|
|
user_histories = {}
|
|
|
|
<span class="code-keyword">async def</span> <span class="code-function">start</span>(update: Update, context):
|
|
<span class="code-comment"># Check if Yandex credentials are configured</span>
|
|
<span class="code-keyword">if</span> <span class="code-keyword">not</span> YANDEX_API_KEY <span class="code-keyword">or</span> YANDEX_API_KEY == <span class="code-string">'your_yandex_api_key_here'</span> <span class="code-keyword">or</span> \\
|
|
<span class="code-keyword">not</span> YANDEX_FOLDER_ID <span class="code-keyword">or</span> YANDEX_FOLDER_ID == <span class="code-string">'your_yandex_folder_id_here'</span>:
|
|
<span class="code-keyword">await</span> update.message.reply_text(
|
|
<span class="code-string">"⚠️ Bot not properly configured!\\n\\n"</span>
|
|
<span class="code-string">"Please set up your Yandex Cloud credentials in the .env file:\\n"</span>
|
|
<span class="code-string">"- YANDEX_API_KEY\\n"</span>
|
|
<span class="code-string">"- YANDEX_FOLDER_ID\\n\\n"</span>
|
|
<span class="code-string">"Check the README for setup instructions."</span>
|
|
)
|
|
<span class="code-keyword">return</span>
|
|
|
|
<span class="code-keyword">await</span> update.message.reply_text(<span class="code-string">"Hi! I'm a joke bot powered by Yandex AI. Send me any message and I'll respond with a joke! 😄"</span>)
|
|
|
|
<span class="code-keyword">async def</span> <span class="code-function">handle_message</span>(update: Update, context):
|
|
<span class="code-comment">"""Handle incoming messages and respond using Yandex AI"""</span>
|
|
user_id = update.effective_user.id
|
|
user_message = update.message.text
|
|
|
|
<span class="code-comment"># Initialize user history if not exists</span>
|
|
<span class="code-keyword">if</span> user_id <span class="code-keyword">not</span> <span class="code-keyword">in</span> user_histories:
|
|
user_histories[user_id] = [
|
|
{
|
|
<span class="code-string">"role"</span>: <span class="code-string">"system"</span>,
|
|
<span class="code-string">"text"</span>: <span class="code-string">"You are a funny chatbot that responds with jokes. Keep responses concise and family-friendly."</span>
|
|
}
|
|
]
|
|
|
|
<span class="code-comment"># Add user message to history</span>
|
|
user_histories[user_id].append({
|
|
<span class="code-string">"role"</span>: <span class="code-string">"user"</span>,
|
|
<span class="code-string">"text"</span>: user_message
|
|
})
|
|
|
|
<span class="code-keyword">try</span>:
|
|
headers = {
|
|
<span class="code-string">"Authorization"</span>: <span class="code-string">f"Api-Key {YANDEX_API_KEY}"</span>,
|
|
<span class="code-string">"Content-Type"</span>: <span class="code-string">"application/json"</span>
|
|
}
|
|
|
|
data = {
|
|
<span class="code-string">"modelUri"</span>: <span class="code-string">f"gpt://{YANDEX_FOLDER_ID}/yandexgpt-lite"</span>,
|
|
<span class="code-string">"completionOptions"</span>: {
|
|
<span class="code-string">"stream"</span>: <span class="code-keyword">False</span>,
|
|
<span class="code-string">"temperature"</span>: 0.8,
|
|
<span class="code-string">"maxTokens"</span>: 100
|
|
},
|
|
<span class="code-string">"messages"</span>: user_histories[user_id]
|
|
}
|
|
|
|
response = requests.post(YANDEX_API_URL, headers=headers, json=data, timeout=10)
|
|
response.raise_for_status()
|
|
|
|
ai_response = response.json()[<span class="code-string">"result"</span>][<span class="code-string">"alternatives"</span>][0][<span class="code-string">"message"</span>][<span class="code-string">"text"</span>]
|
|
|
|
<span class="code-comment"># Add AI response to history</span>
|
|
user_histories[user_id].append({
|
|
<span class="code-string">"role"</span>: <span class="code-string">"assistant"</span>,
|
|
<span class="code-string">"text"</span>: ai_response
|
|
})
|
|
|
|
<span class="code-keyword">await</span> update.message.reply_text(ai_response)
|
|
|
|
<span class="code-keyword">except</span> Exception <span class="code-keyword">as</span> e:
|
|
<span class="code-keyword">await</span> update.message.reply_text(<span class="code-string">f"❌ Failed to generate response: {str(e)}"</span>)
|
|
|
|
<span class="code-keyword">def</span> <span class="code-function">main</span>():
|
|
<span class="code-comment">"""Start the bot."""</span>
|
|
BOT_TOKEN = os.getenv(<span class="code-string">"BOT_TOKEN"</span>, <span class="code-string">"7864875699:AAEWf6ff1DYNzPvW6Dbn7D2W5aavg9KPhgY"</span>)
|
|
|
|
app = Application.builder().token(BOT_TOKEN).build()
|
|
app.add_handler(CommandHandler(<span class="code-string">"start"</span>, start))
|
|
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
|
|
|
|
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>
|
|
|
|
<!-- Slide 5: Phase 3 - User-Generated Content -->
|
|
<div class="slide" id="slide5">
|
|
<h1>Phase 3: User-Generated Content</h1>
|
|
<p class="lead">Final implementation with database, voting, and approval system.</p>
|
|
|
|
<div class="code-block">
|
|
<span class="code-keyword">import</span> sqlite3
|
|
<span class="code-keyword">import</span> random
|
|
<span class="code-keyword">from</span> datetime <span class="code-keyword">import</span> datetime
|
|
|
|
<span class="code-comment"># Calculate average user sentiment for a joke</span>
|
|
<span class="code-keyword">def</span> <span class="code-function">get_user_sentiment_for_joke</span>(db, joke_id):
|
|
cursor = db.execute(<span class="code-string">'''</span>
|
|
<span class="code-string"> SELECT </span>
|
|
<span class="code-string"> CASE </span>
|
|
<span class="code-string"> WHEN AVG(CASE WHEN user_sentiment = 'up' THEN 1 </span>
|
|
<span class="code-string"> WHEN user_sentiment = 'down' THEN -1 </span>
|
|
<span class="code-string"> ELSE 0 END) > 0.1 THEN '👍 Up'</span>
|
|
<span class="code-string"> WHEN AVG(CASE WHEN user_sentiment = 'up' THEN 1 </span>
|
|
<span class="code-string"> WHEN user_sentiment = 'down' THEN -1 </span>
|
|
<span class="code-string"> ELSE 0 END) < -0.1 THEN '👎 Down'</span>
|
|
<span class="code-string"> ELSE '😐 Neutral'</span>
|
|
<span class="code-string"> END as avg_sentiment,</span>
|
|
<span class="code-string"> COUNT(*) as total_votes</span>
|
|
<span class="code-string"> FROM user_sentiments </span>
|
|
<span class="code-string"> WHERE joke_id = ?</span>
|
|
<span class="code-string"> '''</span>, (joke_id,))
|
|
|
|
result = cursor.fetchone()
|
|
avg_sentiment, total_votes = result <span class="code-keyword">if</span> result <span class="code-keyword">else</span> (<span class="code-string">'😐 Neutral'</span>, 0)
|
|
<span class="code-keyword">return</span> avg_sentiment, total_votes
|
|
|
|
<span class="code-comment"># Record user sentiment for a joke</span>
|
|
<span class="code-keyword">def</span> <span class="code-function">add_user_sentiment</span>(db, joke_id, user_choice):
|
|
<span class="code-keyword">try</span>:
|
|
db.execute(<span class="code-string">'''</span>
|
|
<span class="code-string"> INSERT INTO user_sentiments (joke_id, user_sentiment) </span>
|
|
<span class="code-string"> VALUES (?, ?)</span>
|
|
<span class="code-string"> '''</span>, (joke_id, user_choice))
|
|
db.commit()
|
|
<span class="code-keyword">return</span> <span class="code-keyword">True</span>
|
|
<span class="code-keyword">except</span> Exception <span class="code-keyword">as</span> e:
|
|
print(<span class="code-string">f"❌ Error saving sentiment: {e}"</span>)
|
|
<span class="code-keyword">return</span> <span class="code-keyword">False</span></div>
|
|
|
|
<div class="info-block">
|
|
<h3>Final System Features</h3>
|
|
<ul class="simple-list">
|
|
<li>SQLite database for joke storage</li>
|
|
<li>User-generated content with administrative approval</li>
|
|
<li>Community voting system (👍, 👎, 😐)</li>
|
|
<li>Sentiment analysis and rating calculation</li>
|
|
<li>Command-line interface for joke management</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Slide 6: System Demonstration -->
|
|
<div class="slide" id="slide6">
|
|
<h1>System Demonstration</h1>
|
|
|
|
<div class="terminal">
|
|
<div class="terminal-title">Final System - Joke Retrieval</div>
|
|
<div class="terminal-line"><span class="terminal-prompt">$</span> python joke_bot.py</div>
|
|
<div class="terminal-line"></div>
|
|
<div class="terminal-line">🤖 JOKE BOT</div>
|
|
<div class="terminal-line">==============================</div>
|
|
<div class="terminal-line">1. Get random joke</div>
|
|
<div class="terminal-line">2. Add new joke</div>
|
|
<div class="terminal-line">3. Quit</div>
|
|
<div class="terminal-line"></div>
|
|
<div class="terminal-line">Your choice: <span class="terminal-success">1</span></div>
|
|
<div class="terminal-line"></div>
|
|
<div class="terminal-line"><span class="terminal-emoji">🤣</span> Why don't scientists trust atoms?</div>
|
|
<div class="terminal-line">Because they make up everything!</div>
|
|
<div class="terminal-line"></div>
|
|
<div class="terminal-line"><span class="terminal-emoji">👤</span> Contributor: ScienceFan42</div>
|
|
<div class="terminal-line"><span class="terminal-emoji">👥</span> Community Rating: 👍 Up (24 votes)</div>
|
|
<div class="terminal-line"></div>
|
|
<div class="terminal-line"><span class="terminal-emoji">🎯</span> Rate this joke: 👍 (U)p, 👎 (D)own, or (N)eutral?</div>
|
|
<div class="terminal-line">Your choice (u/d/n): <span class="terminal-success">u</span></div>
|
|
<div class="terminal-line"><span class="terminal-success">✅ Your rating (👍 Up) recorded!</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Slide 7: Technology Stack -->
|
|
<div class="slide" id="slide7">
|
|
<h1>Technology Stack</h1>
|
|
|
|
<div class="tech-stack">
|
|
<div class="tech-tag">Python 3.9+</div>
|
|
<div class="tech-tag">Telegram Bot API</div>
|
|
<div class="tech-tag">SQLite Database</div>
|
|
<div class="tech-tag">Yandex AI API</div>
|
|
<div class="tech-tag">Command-Line Interface</div>
|
|
<div class="tech-tag">Modular Architecture</div>
|
|
</div>
|
|
|
|
<div class="timeline">
|
|
<div class="timeline-item">
|
|
<div class="timeline-marker">📱</div>
|
|
<div class="timeline-content">
|
|
<strong>Telegram Platform</strong><br>
|
|
Bot API for user interaction and message handling
|
|
</div>
|
|
</div>
|
|
|
|
<div class="timeline-item">
|
|
<div class="timeline-marker">🤖</div>
|
|
<div class="timeline-content">
|
|
<strong>AI Integration</strong><br>
|
|
Yandex GPT for dynamic content generation during Phase 2
|
|
</div>
|
|
</div>
|
|
|
|
<div class="timeline-item">
|
|
<div class="timeline-marker">🗄️</div>
|
|
<div class="timeline-content">
|
|
<strong>Database System</strong><br>
|
|
SQLite for storing jokes, votes, and user preferences
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Slide 8: Learning Outcomes -->
|
|
<div class="slide" id="slide8">
|
|
<h1>Learning Outcomes</h1>
|
|
|
|
<div class="benefits-grid">
|
|
<div class="benefit-card">
|
|
<div class="benefit-icon">💻</div>
|
|
<div class="benefit-title">API Integration</div>
|
|
<p>Telegram Bot API and Yandex AI API implementation</p>
|
|
</div>
|
|
|
|
<div class="benefit-card">
|
|
<div class="benefit-icon">🗄️</div>
|
|
<div class="benefit-title">Database Design</div>
|
|
<p>SQLite database architecture and management</p>
|
|
</div>
|
|
|
|
<div class="benefit-card">
|
|
<div class="benefit-icon">🔄</div>
|
|
<div class="benefit-title">Iterative Development</div>
|
|
<p>Progressive implementation from basic to complex features</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="highlight">
|
|
<h3>Development Methodology</h3>
|
|
<p>The project followed an iterative approach: starting with a simple working prototype (hardcoded jokes), adding AI capabilities, and finally implementing a full database system with user-generated content and community features.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Slide 9: Future Applications -->
|
|
<div class="slide" id="slide9">
|
|
<h1>Future Applications</h1>
|
|
|
|
<div class="future-grid">
|
|
<div class="future-card">
|
|
<div class="future-icon">🏫</div>
|
|
<div class="future-title">Educational Platform</div>
|
|
<p>Adapt voting system for feedback collection in school communication platforms.</p>
|
|
</div>
|
|
|
|
<div class="future-card">
|
|
<div class="future-icon">📊</div>
|
|
<div class="future-title">Survey System</div>
|
|
<p>Repurpose database structure for structured feedback collection.</p>
|
|
</div>
|
|
|
|
<div class="future-card">
|
|
<div class="future-icon">🤖</div>
|
|
<div class="future-title">Hybrid AI System</div>
|
|
<p>Combine user-generated content with AI moderation and enhancement.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="info-block">
|
|
<h3>Scalable Architecture</h3>
|
|
<p>The modular design allows adaptation for various educational and institutional applications beyond joke sharing.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Slide 10: Conclusion -->
|
|
<div class="slide active" id="slide10">
|
|
<h1>Conclusion</h1>
|
|
|
|
<div class="info-block">
|
|
<p>This project demonstrates practical application of Python programming, API integration, and database design through a progressive development approach.</p>
|
|
</div>
|
|
|
|
<div class="benefits-grid">
|
|
<div class="benefit-card">
|
|
<div class="benefit-icon">🎯</div>
|
|
<div class="benefit-title">Technical Implementation</div>
|
|
<p>Three-phase development from simple to complex system</p>
|
|
</div>
|
|
|
|
<div class="benefit-card">
|
|
<div class="benefit-icon">📈</div>
|
|
<div class="benefit-title">Iterative Approach</div>
|
|
<p>Progressive feature addition and system refinement</p>
|
|
</div>
|
|
|
|
<div class="benefit-card">
|
|
<div class="benefit-icon">👨🏫</div>
|
|
<div class="benefit-title">Educational Framework</div>
|
|
<p>Practical learning in API usage and database management</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="text-align: center; margin-top: 40px; padding-top: 20px; border-top: 1px solid #e0e0e0;">
|
|
<h3>Thank You</h3>
|
|
<p style="color: #5d6d7e; max-width: 600px; margin: 0 auto;">Questions about the Telegram Joke Bot development process?</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Navigation -->
|
|
<div class="navigation">
|
|
<button class="nav-btn" id="prev-btn">← Previous</button>
|
|
|
|
<div class="slide-counter">
|
|
Slide <span id="current-slide">10</span> of <span id="total-slides">10</span>
|
|
</div>
|
|
|
|
<button class="nav-btn" id="next-btn">Finish</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let currentSlide = 1;
|
|
const totalSlides = 10;
|
|
|
|
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('total-slides').textContent = totalSlides;
|
|
|
|
document.getElementById('prev-btn').disabled = slideNumber === 1;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
showSlide(1);
|
|
|
|
document.getElementById('next-btn').addEventListener('click', nextSlide);
|
|
document.getElementById('prev-btn').addEventListener('click', prevSlide);
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'ArrowRight' || e.key === ' ' || e.key === 'Enter') {
|
|
nextSlide();
|
|
} else if (e.key === 'ArrowLeft') {
|
|
prevSlide();
|
|
}
|
|
});
|
|
|
|
let touchStartY = 0;
|
|
let touchEndY = 0;
|
|
|
|
document.addEventListener('touchstart', (e) => {
|
|
touchStartY = e.changedTouches[0].screenY;
|
|
});
|
|
|
|
document.addEventListener('touchend', (e) => {
|
|
touchEndY = e.changedTouches[0].screenY;
|
|
handleSwipe();
|
|
});
|
|
|
|
function handleSwipe() {
|
|
const swipeThreshold = 100;
|
|
|
|
if (touchEndY < touchStartY - swipeThreshold) {
|
|
nextSlide();
|
|
}
|
|
|
|
if (touchEndY > touchStartY + swipeThreshold) {
|
|
prevSlide();
|
|
}
|
|
}
|
|
</script>
|
|
|
|
</body></html> |