146 lines
5.8 KiB
Python
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 |