zulip_bot/app/__init__.py
2025-05-16 18:00:22 +04:00

146 lines
5.8 KiB
Python

"""
Main application entry point for the Zulip Bot application.
"""
import os
from flask import Flask, request, jsonify
from app.config import load_config
def create_app(config_name=None):
"""Create and configure the Flask application."""
app = Flask(__name__)
# Load configuration
config = load_config(config_name)
app.config.from_object(config)
# Set DEBUG mode for the app
app.config['DEBUG'] = True
# Override any environment flags to disable safety filters
os.environ['GEMINI_NO_SAFETY'] = 'true'
# Apply NumPy compatibility patch for ChromaDB
from app.utils import patch_chromadb_numpy
patch_chromadb_numpy()
# Initialize database connections
from app.db import init_db
init_db(app)
# Check if we're in the main process or a Flask reloader worker
# When Flask reloads in debug mode, it sets an environment variable
# We only want to start services in the main process to avoid duplication
is_flask_reloader_process = os.environ.get('WERKZEUG_RUN_MAIN') == 'true'
is_main_process = not os.environ.get('WERKZEUG_RUN_MAIN')
# Only start services in the main process or if --no-reload is used
# This prevents duplicate services when using Flask's debug mode
should_start_services = is_flask_reloader_process or is_main_process
# Initialize message sync service and bot service regardless of process
# but only start them in the appropriate process
from app.utils.sync_service import MessageSyncService
sync_service = MessageSyncService(sync_interval=60) # Sync every 60 seconds
# Store sync_service in app context so it can be accessed elsewhere
app.sync_service = sync_service
# Initialize Zulip bot service
from app.utils.bot_service import ZulipBotService
bot_service = ZulipBotService()
# Store bot_service in app context so it can be accessed elsewhere
app.bot_service = bot_service
# Start the services in a better way (avoiding deprecated before_first_request)
# But only if this is the main process or Flask reloader's main thread
with app.app_context():
# Add logging to help diagnose any issues
app.logger.info(f"App initialization, should_start_services={should_start_services}, "
f"is_main_process={is_main_process}, is_flask_reloader_process={is_flask_reloader_process}")
if should_start_services:
# Start the sync service
app.logger.info("Starting sync service...")
sync_service.start()
# Start the bot service and log the result
app.logger.info("Starting Zulip bot service...")
if bot_service.thread and bot_service.thread.is_alive():
app.logger.info("Bot service is already running, not starting again")
else:
bot_service.start()
app.logger.info("Bot service started successfully")
else:
app.logger.info("Skipping service startup in Flask reloader process")
# Register a shutdown function to stop the services
@app.teardown_appcontext
def stop_services(exception=None):
if hasattr(app, 'sync_service'):
app.sync_service.stop()
if hasattr(app, 'bot_service'):
app.bot_service.stop()
# Register blueprints
# This will be implemented later
@app.route('/health')
def health_check():
"""Simple health check endpoint."""
return jsonify({'status': 'ok'})
@app.route('/sync/now')
def trigger_sync():
"""Trigger an immediate sync."""
if hasattr(app, 'sync_service'):
app.sync_service.sync_now()
return jsonify({'status': 'sync_triggered'})
return jsonify({'status': 'error', 'message': 'Sync service not available'}), 500
@app.route('/bot/status')
def bot_status():
"""Get the status of the bot service."""
if hasattr(app, 'bot_service') and app.bot_service.thread and app.bot_service.thread.is_alive():
return jsonify({'status': 'running'})
return jsonify({'status': 'stopped'})
@app.route('/bot/start', methods=['POST'])
def start_bot():
"""Start the bot service."""
if hasattr(app, 'bot_service'):
app.bot_service.start()
return jsonify({'status': 'started'})
return jsonify({'status': 'error', 'message': 'Bot service not available'}), 500
@app.route('/bot/stop', methods=['POST'])
def stop_bot():
"""Stop the bot service."""
if hasattr(app, 'bot_service'):
app.bot_service.stop()
return jsonify({'status': 'stopped'})
return jsonify({'status': 'error', 'message': 'Bot service not available'}), 500
@app.route('/bot/test', methods=['POST'])
def test_bot():
"""Send a test message to verify the bot is working."""
if not hasattr(app, 'bot_service'):
return jsonify({'status': 'error', 'message': 'Bot service not available'}), 500
data = request.get_json()
if not data or 'recipient' not in data or 'content' not in data:
return jsonify({'status': 'error', 'message': 'Missing required fields: recipient, content'}), 400
result = app.bot_service.send_test_message(data['recipient'], data['content'])
return jsonify({'status': 'sent', 'result': result})
@app.route('/bot/reset-cache', methods=['POST'])
def reset_bot_cache():
"""Reset the bot's message cache to fix issues with message processing."""
if not hasattr(app, 'bot_service'):
return jsonify({'status': 'error', 'message': 'Bot service not available'}), 500
result = app.bot_service.reset_cache()
return jsonify({'status': 'success', 'message': result})
return app