Add more debug logging and remove nest_asyncio
Browse files
main.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# main.py (Revised for Hugging Face -
|
| 2 |
import os
|
| 3 |
import re
|
| 4 |
import logging
|
|
@@ -13,7 +13,8 @@ from telegram.ext import (
|
|
| 13 |
MessageHandler,
|
| 14 |
filters,
|
| 15 |
ContextTypes,
|
| 16 |
-
CallbackQueryHandler
|
|
|
|
| 17 |
)
|
| 18 |
from telegram.constants import ParseMode # Import ParseMode explicitly
|
| 19 |
|
|
@@ -26,18 +27,17 @@ _apify_token_exists = bool(os.environ.get('APIFY_API_TOKEN'))
|
|
| 26 |
if _apify_token_exists:
|
| 27 |
from apify_client import ApifyClient
|
| 28 |
else:
|
| 29 |
-
ApifyClient = None
|
| 30 |
|
| 31 |
-
#
|
| 32 |
-
import nest_asyncio
|
| 33 |
-
nest_asyncio.apply()
|
| 34 |
|
| 35 |
# --- Logging Setup ---
|
| 36 |
logging.basicConfig(
|
| 37 |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
| 38 |
-
level=logging.DEBUG # Keep DEBUG
|
| 39 |
)
|
| 40 |
-
# Reduce noise from libraries
|
| 41 |
logging.getLogger("httpx").setLevel(logging.WARNING)
|
| 42 |
if ApifyClient: logging.getLogger("apify_client").setLevel(logging.WARNING)
|
| 43 |
logging.getLogger("telegram.ext").setLevel(logging.DEBUG)
|
|
@@ -47,17 +47,14 @@ logging.getLogger('gunicorn.error').setLevel(logging.INFO)
|
|
| 47 |
logger = logging.getLogger(__name__)
|
| 48 |
logger.info("Logging configured (DEBUG level).")
|
| 49 |
|
| 50 |
-
# --- Environment Variable Loading
|
| 51 |
logger.info("Attempting to load secrets from environment variables...")
|
| 52 |
-
|
| 53 |
def get_secret(secret_name):
|
| 54 |
-
"""Reads secret and logs the attempt and result."""
|
| 55 |
logger.debug(f"Attempting to read secret: {secret_name}")
|
| 56 |
value = os.environ.get(secret_name)
|
| 57 |
-
if value:
|
| 58 |
-
|
| 59 |
-
else:
|
| 60 |
-
logger.warning(f"Secret '{secret_name}': Not Found")
|
| 61 |
return value
|
| 62 |
|
| 63 |
TELEGRAM_TOKEN = get_secret('TELEGRAM_TOKEN')
|
|
@@ -65,11 +62,11 @@ OPENROUTER_API_KEY = get_secret('OPENROUTER_API_KEY')
|
|
| 65 |
URLTOTEXT_API_KEY = get_secret('URLTOTEXT_API_KEY')
|
| 66 |
SUPADATA_API_KEY = get_secret('SUPADATA_API_KEY')
|
| 67 |
APIFY_API_TOKEN = get_secret('APIFY_API_TOKEN')
|
| 68 |
-
|
| 69 |
logger.info("Secret loading attempt finished.")
|
| 70 |
|
| 71 |
# --- Bot Logic Functions ---
|
| 72 |
# [PASTE ALL YOUR BOT LOGIC FUNCTIONS HERE - FROM is_youtube_url to generate_summary]
|
|
|
|
| 73 |
# Helper Functions
|
| 74 |
def is_youtube_url(url):
|
| 75 |
"""Checks if the URL is a valid YouTube video or shorts URL."""
|
|
@@ -526,6 +523,7 @@ Here is the text to summarise:"""
|
|
| 526 |
return "Sorry, an unexpected error occurred while generating the summary."
|
| 527 |
|
| 528 |
|
|
|
|
| 529 |
# --- Telegram Bot Handlers (Command, Message, CallbackQuery) ---
|
| 530 |
|
| 531 |
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
@@ -591,7 +589,13 @@ async def handle_summary_type_callback(update: Update, context: ContextTypes.DEF
|
|
| 591 |
"""Handles button presses for summary type selection."""
|
| 592 |
query = update.callback_query
|
| 593 |
if not query: return
|
| 594 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 595 |
|
| 596 |
summary_type = query.data
|
| 597 |
user = update.effective_user or query.from_user # Get user info
|
|
@@ -640,9 +644,10 @@ async def handle_summary_type_callback(update: Update, context: ContextTypes.DEF
|
|
| 640 |
try:
|
| 641 |
# Edit the message to show processing status
|
| 642 |
await query.edit_message_text(processing_message)
|
|
|
|
| 643 |
except Exception as e:
|
| 644 |
# If editing fails (e.g., message too old), send a new status message
|
| 645 |
-
logger.warning(f"Could not edit original message: {e}
|
| 646 |
try:
|
| 647 |
message_to_delete_later = await context.bot.send_message(chat_id=user.id, text=processing_message)
|
| 648 |
except Exception as send_err:
|
|
@@ -657,6 +662,7 @@ async def handle_summary_type_callback(update: Update, context: ContextTypes.DEF
|
|
| 657 |
|
| 658 |
try:
|
| 659 |
# Show "typing..." status in Telegram chat
|
|
|
|
| 660 |
await context.bot.send_chat_action(chat_id=user.id, action='typing')
|
| 661 |
|
| 662 |
# --- Content Fetching Logic ---
|
|
@@ -664,6 +670,7 @@ async def handle_summary_type_callback(update: Update, context: ContextTypes.DEF
|
|
| 664 |
video_id = extract_youtube_id(url)
|
| 665 |
if video_id:
|
| 666 |
# Fetch YT transcript using the function with fallbacks
|
|
|
|
| 667 |
content = await get_youtube_transcript(
|
| 668 |
video_id,
|
| 669 |
url, # Pass full URL for Apify
|
|
@@ -672,6 +679,7 @@ async def handle_summary_type_callback(update: Update, context: ContextTypes.DEF
|
|
| 672 |
)
|
| 673 |
# Set feedback message only if content fetching failed
|
| 674 |
user_feedback_message = None if content else "Sorry, I couldn't get the transcript for that YouTube video using any available method (unavailable/private/no captions?)."
|
|
|
|
| 675 |
else:
|
| 676 |
user_feedback_message = "Sorry, I couldn't understand that YouTube URL format."
|
| 677 |
else: # Website Logic (Requests/BS4 -> URLToText API)
|
|
@@ -712,6 +720,7 @@ async def handle_summary_type_callback(update: Update, context: ContextTypes.DEF
|
|
| 712 |
logger.warning(f"Summary generation failed or returned error: {summary}")
|
| 713 |
else:
|
| 714 |
# Send the successful summary
|
|
|
|
| 715 |
await context.bot.send_message(
|
| 716 |
chat_id=user.id,
|
| 717 |
text=summary,
|
|
@@ -727,6 +736,7 @@ async def handle_summary_type_callback(update: Update, context: ContextTypes.DEF
|
|
| 727 |
|
| 728 |
# --- Send Feedback if any step failed ---
|
| 729 |
if user_feedback_message and not success:
|
|
|
|
| 730 |
await context.bot.send_message(chat_id=user.id, text=user_feedback_message)
|
| 731 |
|
| 732 |
except Exception as e:
|
|
@@ -741,12 +751,14 @@ async def handle_summary_type_callback(update: Update, context: ContextTypes.DEF
|
|
| 741 |
finally:
|
| 742 |
# --- Cleanup ---
|
| 743 |
# Delete the "Processing..." status message or the original message with buttons
|
|
|
|
| 744 |
try:
|
| 745 |
if message_to_delete_later: # If we sent a separate status message
|
| 746 |
await context.bot.delete_message(chat_id=user.id, message_id=message_to_delete_later.message_id)
|
|
|
|
| 747 |
elif query: # Otherwise, delete the original message with the buttons
|
| 748 |
-
# We might have already edited it, but deleting ensures cleanup
|
| 749 |
await query.delete_message()
|
|
|
|
| 750 |
except Exception as del_e:
|
| 751 |
# Log if deletion fails, but don't let it stop anything
|
| 752 |
logger.warning(f"Could not delete status/button message: {del_e}")
|
|
@@ -756,33 +768,8 @@ async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> N
|
|
| 756 |
"""Log Errors caused by Updates."""
|
| 757 |
# Log the error and traceback
|
| 758 |
logger.error(f"Exception while handling an update: {context.error}", exc_info=context.error)
|
|
|
|
| 759 |
|
| 760 |
-
# Optionally send a notification to developer chat ID (replace with your actual ID)
|
| 761 |
-
# developer_chat_id = 12345678
|
| 762 |
-
# try:
|
| 763 |
-
# # Extract user/chat info if available
|
| 764 |
-
# chat_info = "N/A"
|
| 765 |
-
# user_info = "N/A"
|
| 766 |
-
# update_details = "N/A"
|
| 767 |
-
# if isinstance(update, Update) and update.effective_chat:
|
| 768 |
-
# chat_info = f"Chat: {update.effective_chat.id} ({update.effective_chat.type})"
|
| 769 |
-
# if isinstance(update, Update) and update.effective_user:
|
| 770 |
-
# user_info = f"User: {update.effective_user.id} (@{update.effective_user.username})"
|
| 771 |
-
# if update:
|
| 772 |
-
# update_details = f"Update Type: {update.__class__.__name__}"
|
| 773 |
-
|
| 774 |
-
# tb_list = traceback.format_exception(None, context.error, context.error.__traceback__)
|
| 775 |
-
# tb_string = "".join(tb_list)
|
| 776 |
-
# # Keep message reasonably short
|
| 777 |
-
# error_message = (
|
| 778 |
-
# f"🚨 Bot Error 🚨\n"
|
| 779 |
-
# f"{chat_info}\n{user_info}\n{update_details}\n"
|
| 780 |
-
# f"Error: {context.error}\n\n"
|
| 781 |
-
# f"Traceback (last part):\n```\n{tb_string[-1000:]}\n```" # Limit traceback length
|
| 782 |
-
# )
|
| 783 |
-
# await context.bot.send_message(chat_id=developer_chat_id, text=error_message[:4096]) # Limit msg len
|
| 784 |
-
# except Exception as e:
|
| 785 |
-
# logger.error(f"Failed to send error notification to developer: {e}")
|
| 786 |
|
| 787 |
# --- Bot Application Setup Function ---
|
| 788 |
async def setup_bot():
|
|
@@ -812,8 +799,6 @@ async def setup_bot():
|
|
| 812 |
|
| 813 |
# --- Run Setup and Store Application Instance ---
|
| 814 |
logger.info("Running bot setup...")
|
| 815 |
-
# Run the async setup function and store the application instance globally
|
| 816 |
-
# This runs once when the script/module is first loaded by Gunicorn worker
|
| 817 |
ptb_app = asyncio.run(setup_bot())
|
| 818 |
logger.info(f"Bot setup finished. Application instance: {'OK' if ptb_app else 'Failed'}")
|
| 819 |
|
|
|
|
| 1 |
+
# main.py (Revised for Hugging Face - Fix Event Loop Issue)
|
| 2 |
import os
|
| 3 |
import re
|
| 4 |
import logging
|
|
|
|
| 13 |
MessageHandler,
|
| 14 |
filters,
|
| 15 |
ContextTypes,
|
| 16 |
+
CallbackQueryHandler,
|
| 17 |
+
ApplicationBuilder # Import ApplicationBuilder
|
| 18 |
)
|
| 19 |
from telegram.constants import ParseMode # Import ParseMode explicitly
|
| 20 |
|
|
|
|
| 27 |
if _apify_token_exists:
|
| 28 |
from apify_client import ApifyClient
|
| 29 |
else:
|
| 30 |
+
ApifyClient = None
|
| 31 |
|
| 32 |
+
# NO nest_asyncio needed here usually when using native async framework integration
|
| 33 |
+
# import nest_asyncio
|
| 34 |
+
# nest_asyncio.apply()
|
| 35 |
|
| 36 |
# --- Logging Setup ---
|
| 37 |
logging.basicConfig(
|
| 38 |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
| 39 |
+
level=logging.DEBUG # Keep DEBUG
|
| 40 |
)
|
|
|
|
| 41 |
logging.getLogger("httpx").setLevel(logging.WARNING)
|
| 42 |
if ApifyClient: logging.getLogger("apify_client").setLevel(logging.WARNING)
|
| 43 |
logging.getLogger("telegram.ext").setLevel(logging.DEBUG)
|
|
|
|
| 47 |
logger = logging.getLogger(__name__)
|
| 48 |
logger.info("Logging configured (DEBUG level).")
|
| 49 |
|
| 50 |
+
# --- Environment Variable Loading ---
|
| 51 |
logger.info("Attempting to load secrets from environment variables...")
|
| 52 |
+
# (Keep the get_secret function and secret loading as before)
|
| 53 |
def get_secret(secret_name):
|
|
|
|
| 54 |
logger.debug(f"Attempting to read secret: {secret_name}")
|
| 55 |
value = os.environ.get(secret_name)
|
| 56 |
+
if value: logger.info(f"Secret '{secret_name}': Found (Value length: {len(value)})")
|
| 57 |
+
else: logger.warning(f"Secret '{secret_name}': Not Found")
|
|
|
|
|
|
|
| 58 |
return value
|
| 59 |
|
| 60 |
TELEGRAM_TOKEN = get_secret('TELEGRAM_TOKEN')
|
|
|
|
| 62 |
URLTOTEXT_API_KEY = get_secret('URLTOTEXT_API_KEY')
|
| 63 |
SUPADATA_API_KEY = get_secret('SUPADATA_API_KEY')
|
| 64 |
APIFY_API_TOKEN = get_secret('APIFY_API_TOKEN')
|
|
|
|
| 65 |
logger.info("Secret loading attempt finished.")
|
| 66 |
|
| 67 |
# --- Bot Logic Functions ---
|
| 68 |
# [PASTE ALL YOUR BOT LOGIC FUNCTIONS HERE - FROM is_youtube_url to generate_summary]
|
| 69 |
+
# --- [ Ensure all functions from previous main.py are here ] ---
|
| 70 |
# Helper Functions
|
| 71 |
def is_youtube_url(url):
|
| 72 |
"""Checks if the URL is a valid YouTube video or shorts URL."""
|
|
|
|
| 523 |
return "Sorry, an unexpected error occurred while generating the summary."
|
| 524 |
|
| 525 |
|
| 526 |
+
|
| 527 |
# --- Telegram Bot Handlers (Command, Message, CallbackQuery) ---
|
| 528 |
|
| 529 |
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
|
|
| 589 |
"""Handles button presses for summary type selection."""
|
| 590 |
query = update.callback_query
|
| 591 |
if not query: return
|
| 592 |
+
# --- Acknowledge callback query ---
|
| 593 |
+
try:
|
| 594 |
+
await query.answer() # Acknowledge button press immediately
|
| 595 |
+
logger.debug(f"Callback query {query.id} answered.")
|
| 596 |
+
except Exception as e:
|
| 597 |
+
logger.error(f"Failed to answer callback query {query.id}: {e}", exc_info=True)
|
| 598 |
+
# Proceed anyway, but logging the error is important
|
| 599 |
|
| 600 |
summary_type = query.data
|
| 601 |
user = update.effective_user or query.from_user # Get user info
|
|
|
|
| 644 |
try:
|
| 645 |
# Edit the message to show processing status
|
| 646 |
await query.edit_message_text(processing_message)
|
| 647 |
+
logger.debug(f"Edited message for query {query.id} to show processing status.")
|
| 648 |
except Exception as e:
|
| 649 |
# If editing fails (e.g., message too old), send a new status message
|
| 650 |
+
logger.warning(f"Could not edit original message for query {query.id}: {e}. Sending new status message.")
|
| 651 |
try:
|
| 652 |
message_to_delete_later = await context.bot.send_message(chat_id=user.id, text=processing_message)
|
| 653 |
except Exception as send_err:
|
|
|
|
| 662 |
|
| 663 |
try:
|
| 664 |
# Show "typing..." status in Telegram chat
|
| 665 |
+
logger.debug(f"Sending 'typing' action for chat {user.id}")
|
| 666 |
await context.bot.send_chat_action(chat_id=user.id, action='typing')
|
| 667 |
|
| 668 |
# --- Content Fetching Logic ---
|
|
|
|
| 670 |
video_id = extract_youtube_id(url)
|
| 671 |
if video_id:
|
| 672 |
# Fetch YT transcript using the function with fallbacks
|
| 673 |
+
logger.info(f"Fetching YouTube transcript for video_id: {video_id}")
|
| 674 |
content = await get_youtube_transcript(
|
| 675 |
video_id,
|
| 676 |
url, # Pass full URL for Apify
|
|
|
|
| 679 |
)
|
| 680 |
# Set feedback message only if content fetching failed
|
| 681 |
user_feedback_message = None if content else "Sorry, I couldn't get the transcript for that YouTube video using any available method (unavailable/private/no captions?)."
|
| 682 |
+
logger.info(f"YouTube transcript fetch completed. Content found: {bool(content)}")
|
| 683 |
else:
|
| 684 |
user_feedback_message = "Sorry, I couldn't understand that YouTube URL format."
|
| 685 |
else: # Website Logic (Requests/BS4 -> URLToText API)
|
|
|
|
| 720 |
logger.warning(f"Summary generation failed or returned error: {summary}")
|
| 721 |
else:
|
| 722 |
# Send the successful summary
|
| 723 |
+
logger.info("Summary generated successfully. Sending response.")
|
| 724 |
await context.bot.send_message(
|
| 725 |
chat_id=user.id,
|
| 726 |
text=summary,
|
|
|
|
| 736 |
|
| 737 |
# --- Send Feedback if any step failed ---
|
| 738 |
if user_feedback_message and not success:
|
| 739 |
+
logger.warning(f"Sending failure feedback to user: {user_feedback_message}")
|
| 740 |
await context.bot.send_message(chat_id=user.id, text=user_feedback_message)
|
| 741 |
|
| 742 |
except Exception as e:
|
|
|
|
| 751 |
finally:
|
| 752 |
# --- Cleanup ---
|
| 753 |
# Delete the "Processing..." status message or the original message with buttons
|
| 754 |
+
logger.debug("Cleaning up status message...")
|
| 755 |
try:
|
| 756 |
if message_to_delete_later: # If we sent a separate status message
|
| 757 |
await context.bot.delete_message(chat_id=user.id, message_id=message_to_delete_later.message_id)
|
| 758 |
+
logger.debug("Deleted separate status message.")
|
| 759 |
elif query: # Otherwise, delete the original message with the buttons
|
|
|
|
| 760 |
await query.delete_message()
|
| 761 |
+
logger.debug(f"Deleted original message for query {query.id}.")
|
| 762 |
except Exception as del_e:
|
| 763 |
# Log if deletion fails, but don't let it stop anything
|
| 764 |
logger.warning(f"Could not delete status/button message: {del_e}")
|
|
|
|
| 768 |
"""Log Errors caused by Updates."""
|
| 769 |
# Log the error and traceback
|
| 770 |
logger.error(f"Exception while handling an update: {context.error}", exc_info=context.error)
|
| 771 |
+
# (Keep optional developer notification code as before if desired)
|
| 772 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 773 |
|
| 774 |
# --- Bot Application Setup Function ---
|
| 775 |
async def setup_bot():
|
|
|
|
| 799 |
|
| 800 |
# --- Run Setup and Store Application Instance ---
|
| 801 |
logger.info("Running bot setup...")
|
|
|
|
|
|
|
| 802 |
ptb_app = asyncio.run(setup_bot())
|
| 803 |
logger.info(f"Bot setup finished. Application instance: {'OK' if ptb_app else 'Failed'}")
|
| 804 |
|