import asyncio import gradio as gr from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.future import select from sqlalchemy.orm import sessionmaker import logging import os import sys from typing import List, Dict, Any # Global variables for database session and engine db_session = None engine = None monitoring_task = None logger = logging.getLogger(__name__) # Function for dynamically setting the database connection async def set_db_connection(host: str, port: str, user: str, password: str, db_name: str): global db_session, engine try: engine = create_async_engine(f"mysql+aiomysql://{user}:{password}@{host}:{port}/{db_name}", echo=False) Session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) db_session = Session() return "Database connection established." except Exception as e: logger.error(f"Failed to establish database connection: {e}") return f"Failed to connect to database: {e}" # Periodic feed updater with error handling and logging improvements async def periodic_update_with_error_handling(): while True: try: await asyncio.sleep(300) # Wait for 5 minutes before updating the feed content. await update_feed_content() # Update the feed content. except Exception as e: # Catch all exceptions for logging purposes. logger.error(f"Error in periodic update: {e}") # Improved logging message format. # Function to fetch RSS feed content from the provided URL with error handling and logging improvements. async def fetch_feed_content(feed_url: str) -> Dict[str, Any]: try: result = await db_session.execute(select(Article).order_by(Article.timestamp.desc()).limit(20)) articles = result.scalars().all() # Fetch latest articles feed = { 'title': 'Website Changes Feed', 'link': feed_url, 'description': 'Feed of changes detected on monitored websites.', 'items': [{'title': article.title, 'link': article.url, 'description': article.content, 'pubDate': str(article.timestamp)} for article in articles] if articles else [] } return feed except Exception as e: logger.error(f"Error fetching feed content: {e}") return {} # Main application that runs Gradio UI and background tasks async def main(): global db_session, monitoring_task engine = None demo = gr.Blocks() # Define the Gradio interface with demo: gr.Markdown("# Website Monitor and Chatbot") with gr.Row(): with gr.Column(): gr.Markdown("## Database Settings") db_host = gr.Textbox(label="Database Host", placeholder="localhost", value="localhost") db_port = gr.Textbox(label="Database Port", placeholder="3306", value="3306") db_user = gr.Textbox(label="Database User", placeholder="username", value="") db_pass = gr.Textbox(label="Database Password", placeholder="password", type="password", value="") db_name = gr.Textbox(label="Database Name", placeholder="database_name", value="monitoring") db_status_textbox = gr.Textbox(label="Database Status", interactive=False) status_text = gr.Textbox(label="Status", interactive=False) gr.Markdown("## RSS Feed Reader Settings") feed_target_url = gr.Textbox(label="RSS Feed Target URL", placeholder="http://yourwebsite.com/feed") view_button = gr.Button("View Feed") target_urls = gr.Textbox(label="Target URLs (comma-separated)", placeholder="https://example.com, https://another-site.com") storage_location = gr.Textbox(label="Storage Location (CSV file path)", placeholder="/path/to/your/file.csv") feed_rss_checkbox = gr.Checkbox(label="Enable RSS Feed") start_button = gr.Button("Start Monitoring") stop_button = gr.Button("Stop Monitoring") with gr.Column(): feed_content = gr.JSON(label="RSS Feed Content") chatbot_interface = gr.Chatbot(type='messages') message_input = gr.Textbox(placeholder="Type your message here...") send_button = gr.Button("Send") # Define button actions async def on_start_click(target_urls_str: str, storage_loc: str, feed_enabled: bool, host: str, port: str, user: str, password: str, db_name: str): global monitoring_task urls = [url.strip() for url in target_urls_str.split(",")] await set_db_connection(host, port, user, password, db_name) monitoring_task = asyncio.create_task(start_monitoring(urls, storage_loc, feed_enabled)) return "Monitoring started." async def on_stop_click(): global monitoring_task if monitoring_task: monitoring_task.cancel() monitoring_task = None return "Monitoring stopped." async def on_view_feed_click(feed_url: str): return await fetch_feed_content(feed_url) stop_button.click(on_stop_click, outputs=[status_text]) view_button.click(on_view_feed_click, inputs=[feed_target_url], outputs=[feed_content]) send_button.click(chatbot_response, inputs=[message_input, chatbot_interface], outputs=[chatbot_interface, message_input]) # Set up the timer for periodic updates feed_updater = gr.Timer(interval=300) feed_updater.tick(fn=update_feed_content, outputs=feed_content) # Load and check database status when the UI is loaded demo.load(update_db_status, outputs=db_status_textbox) asyncio.create_task(periodic_update_with_error_handling()) # Launch the Gradio demo await demo.launch() # Launch the app using asyncio if __name__ == "__main__": asyncio.run(main())