import logging from telegram.constants import ParseMode from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import Application, CommandHandler, MessageHandler, CallbackQueryHandler, filters, ContextTypes, ConversationHandler from PIL import Image, ImageDraw, ImageFont # Login configuration logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO) # Conversation states ASK_NAME, ASK_Q1, ASK_Q2, ASK_Q3 = range(4) FILE_FEEDBACK = "npse-sandri-feedback.txt" # Certificate template path TEMPLATE_PATH = "C:/certificates/npse-template.png" FONT_PATH = "arial.ttf" OUTPUT_PATH = "C:/certificates/" # Multiple-choice questions QUESTIONS = [ ("Did you like the presentation?", ["Yes, it was very interesting.", "It was okay, but could be improved.", "No, I didn’t find it engaging."]), ("Were you aware of the use of bots in education and dissemination?", ["Yes, I already knew about it.", "I had heard of it but didn’t know much.", "No, this was new to me."]), ("Do you think you will use them?", ["Yes, definitely!", "Maybe, if I find a good use for them.", "No, I don’t think so."]) ] def save_feedback(nome, q1, q2, q3): with open(FILE_FEEDBACK, "a") as f: f.write(f"{nome}; {q1}; {q2}; {q3}\n") # Start function async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: user = update.message.from_user logging.info(f"User {user.first_name} started the bot with args: {context.args}") if context.args: qr_code_id = context.args[0] if qr_code_id == "npse-sandri": photo_url = "https://play.inaf.it/wp-content/uploads/2025/03/npse-banner-firenze.png" await context.bot.send_photo( chat_id=update.effective_chat.id, photo=photo_url, caption=f"Dear *{user.first_name}*, Thank you for attending the conference *New Perspectives in Science Education*.", parse_mode=ParseMode.MARKDOWN ) await update.message.reply_text("I kindly ask you to share your feedback on the presentation _Telegram Bots in Science Education: Applications in the Context of Astrophysics_.",parse_mode=ParseMode.MARKDOWN) await update.message.reply_text("At the end of the survey, I will send you the personalized certificate 😊 Please write your name exactly as you would like it to appear on the certificate.") return ASK_NAME return ConversationHandler.END # Receiving the name async def get_name(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: context.user_data["cert_name"] = update.message.text return await ask_question(update, context, question_index=0) # Function to submit a multiple-choice question async def ask_question(update: Update, context: ContextTypes.DEFAULT_TYPE, question_index: int) -> int: question, options = QUESTIONS[question_index] keyboard = [[InlineKeyboardButton(opt, callback_data=f"{question_index}_{opt}")] for opt in options] reply_markup = InlineKeyboardMarkup(keyboard) await update.message.reply_text(question, reply_markup=reply_markup) return ASK_Q1 + question_index # Pass to next question (ASK_Q1, ASK_Q2, ASK_Q3) # Function to manage the answer to a question async def handle_answer(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: query = update.callback_query await query.answer() question_index, answer = query.data.split("_") question_index = int(question_index) context.user_data[f"q{question_index+1}"] = answer # Save the answer logging.info(f"User answered question {question_index+1}: {answer}") if question_index + 1 < len(QUESTIONS): return await ask_question(query, context, question_index + 1) # Save user data save_feedback( context.user_data['cert_name'], context.user_data.get('q1', 'N/A'), context.user_data.get('q2', 'N/A'), context.user_data.get('q3', 'N/A') ) cert_name = context.user_data["cert_name"] # Generates the certificate with the name cert_path = generate_certificate(cert_name) # Send the certificate to the user if cert_path: await query.message.reply_photo(photo=open(cert_path, "rb"), caption="Here is your certificate! 🎉") else: await query.message.reply_text("An error occurred while generating the certificate 😢") return ConversationHandler.END # Function to generate the certificate def generate_certificate(name: str) -> str: try: # Upload template img = Image.open(TEMPLATE_PATH) draw = ImageDraw.Draw(img) # Choose an appropriate font and size font = ImageFont.truetype(FONT_PATH, 60) # Define the size of the box (change these values according to your template) box_width = 800 box_height = 200 box_x = 343 box_y = 700 # Calculate text bounding box bbox = draw.textbbox((0, 0), name, font=font) text_width = bbox[2] - bbox[0] text_height = bbox[3] - bbox[1] # Calculates the position of the text to center it in the box text_x = box_x + (box_width - text_width) // 2 text_y = box_y + (box_height - text_height) // 2 # Text color text_color = (0, 0, 0) # Nero # Writes the name centered on the image draw.text((text_x, text_y), name, font=font, fill=text_color) output_file = f"{OUTPUT_PATH}{name.replace(' ', '_')}.png" img.save(output_file) return output_file except Exception as e: logging.error(f"An error occurred while generating the certificate: {e}") return None # Cancel the conversation async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: await update.message.reply_text("Operation canceled.") return ConversationHandler.END # Main function def main() -> None: token = "TOKEN" application = Application.builder().token(token).build() conv_handler = ConversationHandler( entry_points=[CommandHandler("start", start)], states={ ASK_NAME: [MessageHandler(filters.TEXT & ~filters.COMMAND, get_name)], ASK_Q1: [CallbackQueryHandler(handle_answer, pattern="^0_")], ASK_Q2: [CallbackQueryHandler(handle_answer, pattern="^1_")], ASK_Q3: [CallbackQueryHandler(handle_answer, pattern="^2_")], }, fallbacks=[CommandHandler("cancel", cancel)], ) application.add_handler(conv_handler) application.run_polling() if __name__ == "__main__": main()
2025-03-07