Spaces:
Runtime error
Runtime error
Update main.py
Browse files
main.py
CHANGED
|
@@ -1,124 +1,167 @@
|
|
| 1 |
import os
|
| 2 |
-
import requests
|
| 3 |
import logging
|
| 4 |
-
import
|
|
|
|
| 5 |
|
| 6 |
from hydrogram import Client, filters
|
| 7 |
from hydrogram.types import Message
|
|
|
|
| 8 |
|
| 9 |
# --- Configuration ---
|
| 10 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
| 11 |
logger = logging.getLogger(__name__)
|
| 12 |
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
TEMPLATE_URL = "https://mediaflare.adasin.workers.dev/dl/4AmNTDcYQSPNQS"
|
| 17 |
|
| 18 |
-
#
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
try:
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
return
|
| 28 |
-
except
|
| 29 |
-
logger.error(f"Error
|
| 30 |
-
return
|
| 31 |
|
| 32 |
# --- Initialization ---
|
| 33 |
-
if not
|
| 34 |
-
logger.error("
|
| 35 |
exit(1)
|
| 36 |
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
exit(1)
|
| 42 |
-
|
| 43 |
-
# Fetch the template image content (bytes)
|
| 44 |
-
template_image_bytes = fetch_template(TEMPLATE_URL)
|
| 45 |
-
if template_image_bytes is None:
|
| 46 |
-
logger.warning("Proceeding without template image due to fetch error.")
|
| 47 |
-
|
| 48 |
-
# Initialize the Hydrogram (Pyrogram) client
|
| 49 |
-
# *** Add workdir='.' to explicitly use the current directory for the session file ***
|
| 50 |
-
logger.info("Initializing Hydrogram Client...")
|
| 51 |
try:
|
| 52 |
app = Client(
|
| 53 |
-
name="
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
)
|
| 59 |
logger.info("Hydrogram Client initialized.")
|
| 60 |
except Exception as e:
|
| 61 |
-
# Log the specific exception
|
| 62 |
logger.error(f"Failed to initialize Hydrogram Client: {type(e).__name__} - {e}")
|
| 63 |
exit(1)
|
| 64 |
|
|
|
|
| 65 |
# --- Bot Event Handlers ---
|
| 66 |
-
@app.on_message(filters.command("start"))
|
| 67 |
async def start_handler(client: Client, message: Message):
|
| 68 |
-
"""Handler for the /start command.
|
| 69 |
sender_name = message.from_user.first_name if message.from_user else "User"
|
| 70 |
-
|
| 71 |
-
logger.info(f"Received /start command from {sender_name} (ID: {sender_id})")
|
| 72 |
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
-
if
|
| 76 |
-
|
| 77 |
-
try:
|
| 78 |
-
# Send the image bytes directly using io.BytesIO
|
| 79 |
-
await message.reply_photo(
|
| 80 |
-
photo=io.BytesIO(template_image_bytes),
|
| 81 |
-
caption=start_message_caption + "\n\nHere's the template image."
|
| 82 |
-
)
|
| 83 |
-
logger.info("Template image sent successfully.")
|
| 84 |
-
except Exception as e:
|
| 85 |
-
logger.error(f"Failed to send template image: {e}")
|
| 86 |
-
# Fallback to text message if sending photo fails
|
| 87 |
-
await message.reply_text(start_message_caption + "\n\n(Could not send the template image due to an error.)")
|
| 88 |
else:
|
| 89 |
-
|
| 90 |
-
await message.reply_text(start_message_caption + "\n\n(Could not load the template image.)")
|
| 91 |
|
|
|
|
| 92 |
|
| 93 |
-
@app.on_message(filters.command("
|
| 94 |
-
async def
|
| 95 |
-
"""Handler for the /
|
| 96 |
-
|
| 97 |
-
logger.info(f"Received /
|
| 98 |
-
await message.reply_text(
|
| 99 |
-
"This is a sample bot (Hydrogram).\nCommands:\n/start - Show welcome message and template image\n/help - Show this help message"
|
| 100 |
-
)
|
| 101 |
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
else:
|
| 108 |
-
|
|
|
|
| 109 |
|
| 110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
try:
|
| 112 |
-
app.
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
|
|
|
|
|
|
|
|
|
| 118 |
except Exception as e:
|
| 119 |
-
|
| 120 |
-
logger.error(f"An unexpected error occurred during app.run(): {type(e).__name__} - {e}")
|
| 121 |
finally:
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import os
|
|
|
|
| 2 |
import logging
|
| 3 |
+
import asyncio
|
| 4 |
+
from pathlib import Path # For handling file paths robustly
|
| 5 |
|
| 6 |
from hydrogram import Client, filters
|
| 7 |
from hydrogram.types import Message
|
| 8 |
+
from hydrogram.errors import SessionPasswordNeeded, PhoneCodeInvalid, PhoneNumberInvalid, PasswordHashInvalid
|
| 9 |
|
| 10 |
# --- Configuration ---
|
| 11 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
| 12 |
logger = logging.getLogger(__name__)
|
| 13 |
|
| 14 |
+
# Retrieve Session String from Hugging Face secrets
|
| 15 |
+
# MUST be set in your Hugging Face Space/Repo secrets settings as SESSION_STRING
|
| 16 |
+
SESSION_STRING = os.environ.get('SESSION_STRING')
|
|
|
|
| 17 |
|
| 18 |
+
# Path for storing the template content
|
| 19 |
+
DATA_DIR = Path("data")
|
| 20 |
+
TEMPLATE_FILE_PATH = DATA_DIR / "template_content.txt"
|
| 21 |
+
|
| 22 |
+
# Global variable to hold the loaded template content
|
| 23 |
+
current_template_content = None
|
| 24 |
+
|
| 25 |
+
# --- Helper Functions for Template Management ---
|
| 26 |
+
def ensure_data_dir_exists():
|
| 27 |
+
"""Ensures the data directory exists."""
|
| 28 |
+
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
| 29 |
+
logger.info(f"Data directory '{DATA_DIR}' ensured.")
|
| 30 |
+
|
| 31 |
+
async def load_template_from_file():
|
| 32 |
+
"""Loads template content from the persistent file."""
|
| 33 |
+
global current_template_content
|
| 34 |
+
ensure_data_dir_exists()
|
| 35 |
+
if TEMPLATE_FILE_PATH.exists():
|
| 36 |
+
try:
|
| 37 |
+
with open(TEMPLATE_FILE_PATH, "r", encoding="utf-8") as f:
|
| 38 |
+
current_template_content = f.read()
|
| 39 |
+
logger.info(f"Template loaded successfully from {TEMPLATE_FILE_PATH}")
|
| 40 |
+
except Exception as e:
|
| 41 |
+
logger.error(f"Error loading template from {TEMPLATE_FILE_PATH}: {e}")
|
| 42 |
+
current_template_content = None # Or a default error message
|
| 43 |
+
else:
|
| 44 |
+
logger.info(f"Template file {TEMPLATE_FILE_PATH} not found. No template loaded.")
|
| 45 |
+
current_template_content = None
|
| 46 |
+
|
| 47 |
+
async def save_template_to_file(content: str):
|
| 48 |
+
"""Saves template content to the persistent file."""
|
| 49 |
+
global current_template_content
|
| 50 |
+
ensure_data_dir_exists()
|
| 51 |
try:
|
| 52 |
+
with open(TEMPLATE_FILE_PATH, "w", encoding="utf-8") as f:
|
| 53 |
+
f.write(content)
|
| 54 |
+
current_template_content = content
|
| 55 |
+
logger.info(f"Template saved successfully to {TEMPLATE_FILE_PATH}")
|
| 56 |
+
return True
|
| 57 |
+
except Exception as e:
|
| 58 |
+
logger.error(f"Error saving template to {TEMPLATE_FILE_PATH}: {e}")
|
| 59 |
+
return False
|
| 60 |
|
| 61 |
# --- Initialization ---
|
| 62 |
+
if not SESSION_STRING:
|
| 63 |
+
logger.error("SESSION_STRING environment variable not found. Please set it in Hugging Face secrets.")
|
| 64 |
exit(1)
|
| 65 |
|
| 66 |
+
# Initialize the Hydrogram Client using the session string
|
| 67 |
+
# The name "user_session" is arbitrary when using a session_string,
|
| 68 |
+
# as the session is loaded directly from the string into memory.
|
| 69 |
+
logger.info("Initializing Hydrogram Client with session string...")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
try:
|
| 71 |
app = Client(
|
| 72 |
+
name="user_session", # Name is a placeholder when session_string is used
|
| 73 |
+
session_string=SESSION_STRING,
|
| 74 |
+
# workdir="." # workdir is not strictly necessary for session file when session_string is used,
|
| 75 |
+
# but good if other client files are ever created.
|
| 76 |
+
# The template file path is handled separately.
|
| 77 |
)
|
| 78 |
logger.info("Hydrogram Client initialized.")
|
| 79 |
except Exception as e:
|
|
|
|
| 80 |
logger.error(f"Failed to initialize Hydrogram Client: {type(e).__name__} - {e}")
|
| 81 |
exit(1)
|
| 82 |
|
| 83 |
+
|
| 84 |
# --- Bot Event Handlers ---
|
| 85 |
+
@app.on_message(filters.command("start") & filters.private)
|
| 86 |
async def start_handler(client: Client, message: Message):
|
| 87 |
+
"""Handler for the /start command."""
|
| 88 |
sender_name = message.from_user.first_name if message.from_user else "User"
|
| 89 |
+
logger.info(f"Received /start command from {sender_name} (ID: {message.from_user.id})")
|
|
|
|
| 90 |
|
| 91 |
+
welcome_text = f"Hello {sender_name}!\n"
|
| 92 |
+
welcome_text += "I am ready to manage your template.\n"
|
| 93 |
+
welcome_text += "Use /settemplate <your text> to set a new template.\n"
|
| 94 |
+
welcome_text += "Use /gettemplate to view the current template."
|
| 95 |
|
| 96 |
+
if current_template_content:
|
| 97 |
+
welcome_text += "\n\nA template is currently set."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
else:
|
| 99 |
+
welcome_text += "\n\nNo template is currently set."
|
|
|
|
| 100 |
|
| 101 |
+
await message.reply_text(welcome_text)
|
| 102 |
|
| 103 |
+
@app.on_message(filters.command("settemplate") & filters.private)
|
| 104 |
+
async def set_template_handler(client: Client, message: Message):
|
| 105 |
+
"""Handler for the /settemplate command."""
|
| 106 |
+
user_id = message.from_user.id
|
| 107 |
+
logger.info(f"Received /settemplate command from User ID: {user_id}")
|
|
|
|
|
|
|
|
|
|
| 108 |
|
| 109 |
+
if len(message.command) > 1:
|
| 110 |
+
new_template = message.text.split(" ", 1)[1].strip() # Get content after "/settemplate "
|
| 111 |
+
if new_template:
|
| 112 |
+
if await save_template_to_file(new_template):
|
| 113 |
+
await message.reply_text("✅ Template updated successfully!")
|
| 114 |
+
else:
|
| 115 |
+
await message.reply_text("❌ Failed to save the template. Please check the logs.")
|
| 116 |
+
else:
|
| 117 |
+
await message.reply_text("⚠️ Please provide content for the template. Usage: `/settemplate Your template text here`")
|
| 118 |
+
else:
|
| 119 |
+
await message.reply_text("ℹ️ Usage: `/settemplate Your template text here`")
|
| 120 |
+
|
| 121 |
+
@app.on_message(filters.command("gettemplate") & filters.private)
|
| 122 |
+
async def get_template_handler(client: Client, message: Message):
|
| 123 |
+
"""Handler for the /gettemplate command."""
|
| 124 |
+
user_id = message.from_user.id
|
| 125 |
+
logger.info(f"Received /gettemplate command from User ID: {user_id}")
|
| 126 |
+
|
| 127 |
+
if current_template_content:
|
| 128 |
+
response_text = f"📜 **Current Template:**\n\n{current_template_content}"
|
| 129 |
else:
|
| 130 |
+
response_text = "ℹ️ No template is currently set. Use `/settemplate <your text>` to set one."
|
| 131 |
+
await message.reply_text(response_text)
|
| 132 |
|
| 133 |
+
# --- Main Execution ---
|
| 134 |
+
async def main():
|
| 135 |
+
"""Main function to load initial data and start the bot."""
|
| 136 |
+
await load_template_from_file() # Load any existing template on startup
|
| 137 |
+
|
| 138 |
+
logger.info("Attempting to connect and start the bot...")
|
| 139 |
try:
|
| 140 |
+
await app.start()
|
| 141 |
+
me = await app.get_me()
|
| 142 |
+
logger.info(f"Bot started successfully as {me.first_name} (ID: {me.id})")
|
| 143 |
+
logger.info("Listening for messages...")
|
| 144 |
+
await asyncio.Event().wait() # Keep the bot running indefinitely
|
| 145 |
+
except (SessionPasswordNeeded, PhoneCodeInvalid, PhoneNumberInvalid, PasswordHashInvalid) as e:
|
| 146 |
+
logger.error(f"Authorization error: {type(e).__name__} - {e}. Your SESSION_STRING might be invalid or expired.")
|
| 147 |
+
except ConnectionError as e:
|
| 148 |
+
logger.error(f"Connection error: {e}. Check your network or Telegram's status.")
|
| 149 |
except Exception as e:
|
| 150 |
+
logger.error(f"An unexpected error occurred during bot startup or runtime: {type(e).__name__} - {e}", exc_info=True)
|
|
|
|
| 151 |
finally:
|
| 152 |
+
if app.is_connected:
|
| 153 |
+
logger.info("Stopping the bot...")
|
| 154 |
+
await app.stop()
|
| 155 |
+
logger.info("Bot stopped.")
|
| 156 |
+
else:
|
| 157 |
+
logger.info("Bot was not connected or already stopped.")
|
| 158 |
+
|
| 159 |
+
if __name__ == '__main__':
|
| 160 |
+
# Run the main function in the asyncio event loop
|
| 161 |
+
try:
|
| 162 |
+
asyncio.run(main())
|
| 163 |
+
except KeyboardInterrupt:
|
| 164 |
+
logger.info("Bot manually interrupted. Exiting...")
|
| 165 |
+
except Exception as e:
|
| 166 |
+
logger.critical(f"Critical error in main execution block: {e}", exc_info=True)
|
| 167 |
+
|