from flask import Flask, render_template, request, jsonify, redirect, url_for from flask_socketio import SocketIO, emit import json import os import threading import time from datetime import datetime import sys # Ajouter le chemin de l'environnement virtuel au PYTHONPATH venv_path = os.path.join(os.path.dirname(__file__), 'env', 'lib', 'python3.10', 'site-packages') if venv_path not in sys.path: sys.path.insert(0, venv_path) # Import des classes du bot sys.path.append('.') from fonction.first_class import RecordTwitch, Subtitle_translation, IA_generator, messageTwitch, TwitchChatBot, storage app = Flask(__name__) app.config['SECRET_KEY'] = 'your-secret-key-here' socketio = SocketIO(app, cors_allowed_origins="*") class BotController: def __init__(self): self.bots = {} # Stockage des instances de bots (pour l'utilisation interne) self.flux_list = [] # Liste des flux surveillés (pour l'API JSON) self.config = self.load_config() def load_config(self): try: with open('config/config.json', 'r') as file: return json.load(file) except FileNotFoundError: return {} def save_config(self): with open('config/config.json', 'w') as file: json.dump(self.config, file, indent=4, ensure_ascii=False) def add_flux(self, channel_name, record_audio=True): flux_id = len(self.flux_list) + 1 # Créer l'objet flux pour l'API (sans les instances de bots) flux_data = { 'id': flux_id, 'name': channel_name, 'twitchname': channel_name, 'record_audio': record_audio, 'active': True, 'created_at': datetime.now().isoformat(), 'status': 'starting' } try: # Créer le bot de chat pour ce flux chat_bot = TwitchChatBot(channel_name) self.bots[flux_id] = { 'chat_bot': chat_bot, 'record_bot': None, 'subtitle_bot': None, 'ia_bot': None, 'message_bot': None } chat_bot.start_background() # Si enregistrement audio activé if record_audio: record_bot = RecordTwitch(channel_name, 60) self.bots[flux_id]['record_bot'] = record_bot threading.Thread(target=record_bot.main, daemon=True).start() # Démarrer le bot de sous-titres subtitle_bot = Subtitle_translation("config/config.json") self.bots[flux_id]['subtitle_bot'] = subtitle_bot subtitle_bot.start_main_loop() # Démarrer le générateur IA ia_bot = IA_generator("config/config.json") self.bots[flux_id]['ia_bot'] = ia_bot ia_bot.start_main_loop() # Démarrer le contrôleur de messages message_bot = messageTwitch("config/user.json", channel_name) self.bots[flux_id]['message_bot'] = message_bot message_bot.start_loop_respond() # Mettre à jour le statut flux_data['status'] = 'active' self.flux_list.append(flux_data) return flux_id except Exception as e: print(f"Erreur lors de l'ajout du flux {channel_name}: {str(e)}") # Nettoyer en cas d'erreur if flux_id in self.bots: try: if self.bots[flux_id]['chat_bot']: self.bots[flux_id]['chat_bot'].stop() if self.bots[flux_id]['record_bot']: self.bots[flux_id]['record_bot'].stop() if self.bots[flux_id]['subtitle_bot']: self.bots[flux_id]['subtitle_bot'].stop() if self.bots[flux_id]['ia_bot']: self.bots[flux_id]['ia_bot'].stop() if self.bots[flux_id]['message_bot']: self.bots[flux_id]['message_bot'].stop() except: pass del self.bots[flux_id] flux_data['status'] = 'error' flux_data['error'] = str(e) self.flux_list.append(flux_data) raise e def remove_flux(self, flux_id): for i, flux in enumerate(self.flux_list): if flux['id'] == flux_id: # Arrêter les bots si ils existent if flux_id in self.bots: try: if self.bots[flux_id]['chat_bot']: self.bots[flux_id]['chat_bot'].stop() if self.bots[flux_id]['record_bot']: self.bots[flux_id]['record_bot'].stop() if self.bots[flux_id]['subtitle_bot']: self.bots[flux_id]['subtitle_bot'].stop() if self.bots[flux_id]['ia_bot']: self.bots[flux_id]['ia_bot'].stop() if self.bots[flux_id]['message_bot']: self.bots[flux_id]['message_bot'].stop() except Exception as e: print(f"Erreur lors de l'arrêt des bots: {e}") del self.bots[flux_id] del self.flux_list[i] return True return False def get_flux_list(self): # Retourner seulement les données JSON (pas les instances de bots) return self.flux_list bot_controller = BotController() @app.route('/') def index(): return render_template('index.html') @app.route('/api/flux', methods=['GET']) def get_flux(): return jsonify(bot_controller.get_flux_list()) @app.route('/api/flux', methods=['POST']) def add_flux(): data = request.json channel_name = data.get('channel_name') record_audio = data.get('record_audio', True) if not channel_name: return jsonify({'error': 'Nom du canal requis'}), 400 try: flux_id = bot_controller.add_flux(channel_name, record_audio) return jsonify({'success': True, 'flux_id': flux_id}) except Exception as e: error_msg = f"Erreur lors de l'ajout du flux: {str(e)}" print(f"Erreur API add_flux: {error_msg}") return jsonify({'error': error_msg}), 500 @app.route('/api/flux/', methods=['DELETE']) def remove_flux(flux_id): if bot_controller.remove_flux(flux_id): return jsonify({'success': True}) return jsonify({'error': 'Flux non trouvé'}), 404 @app.route('/api/flux//status', methods=['GET']) def get_flux_status(flux_id): """Obtenir le statut détaillé d'un flux spécifique""" for flux in bot_controller.flux_list: if flux['id'] == flux_id: status = { 'id': flux_id, 'name': flux['name'], 'active': flux['active'], 'status': flux.get('status', 'unknown'), 'created_at': flux['created_at'], 'bots': {} } # Ajouter les informations des bots si disponibles if flux_id in bot_controller.bots: bots = bot_controller.bots[flux_id] if bots['chat_bot']: status['bots']['chat'] = { 'running': bots['chat_bot'].is_running if hasattr(bots['chat_bot'], 'is_running') else True } if bots['record_bot']: status['bots']['record'] = { 'running': bots['record_bot'].running if hasattr(bots['record_bot'], 'running') else True } return jsonify(status) return jsonify({'error': 'Flux non trouvé'}), 404 @app.route('/api/flux//toggle', methods=['POST']) def toggle_flux(flux_id): """Activer/désactiver un flux""" for flux in bot_controller.flux_list: if flux['id'] == flux_id: flux['active'] = not flux['active'] # Arrêter/démarrer les bots selon le nouveau statut if flux_id in bot_controller.bots: bots = bot_controller.bots[flux_id] if not flux['active']: # Arrêter les bots try: if bots['chat_bot']: bots['chat_bot'].stop() if bots['record_bot']: bots['record_bot'].stop() if bots['subtitle_bot']: bots['subtitle_bot'].stop() if bots['ia_bot']: bots['ia_bot'].stop() if bots['message_bot']: bots['message_bot'].stop() except Exception as e: print(f"Erreur lors de l'arrêt des bots: {e}") else: # Redémarrer les bots try: if bots['chat_bot']: bots['chat_bot'].start_background() if bots['record_bot']: threading.Thread(target=bots['record_bot'].main, daemon=True).start() if bots['subtitle_bot']: bots['subtitle_bot'].start_main_loop() if bots['ia_bot']: bots['ia_bot'].start_main_loop() if bots['message_bot']: bots['message_bot'].start_loop_respond() except Exception as e: print(f"Erreur lors du redémarrage des bots: {e}") return jsonify({'success': True, 'active': flux['active']}) return jsonify({'error': 'Flux non trouvé'}), 404 @app.route('/api/config/prompts', methods=['GET']) def get_prompts(): return jsonify(bot_controller.config.get('list_prompt', [])) @app.route('/api/config/prompts', methods=['POST']) def update_prompts(): data = request.json prompts = data.get('prompts', []) bot_controller.config['list_prompt'] = prompts bot_controller.save_config() return jsonify({'success': True}) @app.route('/api/config/users', methods=['GET']) def get_users(): """Récupérer la liste des utilisateurs""" try: with open('config/user.json', 'r') as file: users = json.load(file) return jsonify(users) except FileNotFoundError: return jsonify([]) except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/api/config/users', methods=['POST']) def add_user(): """Ajouter un nouvel utilisateur""" data = request.json pseudo = data.get('tw_acc_pseudo') token = data.get('tw_acc_token') charactere = data.get('charactere', '😊') if not pseudo or not token: return jsonify({'error': 'Pseudo et token requis'}), 400 try: with open('config/user.json', 'r') as file: users = json.load(file) # Vérifier si l'utilisateur existe déjà for user in users: if user['tw_acc_pseudo'] == pseudo: return jsonify({'error': 'Cet utilisateur existe déjà'}), 400 # Ajouter le nouvel utilisateur new_user = { 'tw_acc_pseudo': pseudo, 'tw_acc_token': token, 'charactere': charactere } users.append(new_user) # Sauvegarder with open('config/user.json', 'w') as file: json.dump(users, file, indent=4, ensure_ascii=False) return jsonify({'success': True, 'user': new_user}) except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/api/config/users/', methods=['PUT']) def update_user(user_id): """Modifier un utilisateur existant""" data = request.json pseudo = data.get('tw_acc_pseudo') token = data.get('tw_acc_token') charactere = data.get('charactere', '😊') if not pseudo or not token: return jsonify({'error': 'Pseudo et token requis'}), 400 try: with open('config/user.json', 'r') as file: users = json.load(file) if user_id >= len(users): return jsonify({'error': 'Utilisateur non trouvé'}), 404 # Vérifier si le pseudo existe déjà (sauf pour l'utilisateur actuel) for i, user in enumerate(users): if i != user_id and user['tw_acc_pseudo'] == pseudo: return jsonify({'error': 'Ce pseudo est déjà utilisé'}), 400 # Mettre à jour l'utilisateur users[user_id] = { 'tw_acc_pseudo': pseudo, 'tw_acc_token': token, 'charactere': charactere } # Sauvegarder with open('config/user.json', 'w') as file: json.dump(users, file, indent=4, ensure_ascii=False) return jsonify({'success': True, 'user': users[user_id]}) except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/api/config/users/', methods=['DELETE']) def delete_user(user_id): """Supprimer un utilisateur""" try: with open('config/user.json', 'r') as file: users = json.load(file) if user_id >= len(users): return jsonify({'error': 'Utilisateur non trouvé'}), 404 # Supprimer l'utilisateur deleted_user = users.pop(user_id) # Sauvegarder with open('config/user.json', 'w') as file: json.dump(users, file, indent=4, ensure_ascii=False) return jsonify({'success': True, 'deleted_user': deleted_user}) except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/api/subtitles', methods=['GET']) def get_subtitles(): data = storage.read("subtitle_data") return jsonify(data) @app.route('/api/subtitles/process', methods=['POST']) def process_subtitles(): """Lancer manuellement le traitement des sous-titres""" try: import subprocess import os import json from datetime import datetime # Vérifier que le dossier record existe record_dir = "record" if not os.path.exists(record_dir): return jsonify({ 'success': False, 'error': 'Dossier record non trouvé' }), 404 # Trouver les fichiers audio audio_files = [f for f in os.listdir(record_dir) if f.endswith('.mp3')] if not audio_files: return jsonify({ 'success': False, 'error': 'Aucun fichier audio trouvé' }), 404 subtitles_created = 0 subtitles_data = {} # Traiter chaque fichier audio for audio_file in audio_files[:3]: # Limiter à 3 fichiers pour éviter de surcharger audio_path = os.path.join(record_dir, audio_file) try: # Lancer Whisper command = [ 'whisper', '--language', 'fr', audio_path, '--device', 'cuda', '--model', 'large-v3' ] result = subprocess.run(command, capture_output=True, text=True, timeout=60) if result.returncode == 0: # Lire le fichier .txt généré txt_file = audio_file.replace('.mp3', '.txt') if os.path.exists(txt_file): with open(txt_file, 'r', encoding='utf-8') as f: content = f.read().strip() # Nettoyer le contenu content = content.replace("'", "").replace('"', "").replace("\n", " ").replace(",", "") # Supprimer les répétitions de mots words = content.split() seen = set() result_words = [] for word in words: if word not in seen: result_words.append(word) seen.add(word) cleaned_content = " ".join(result_words) # Sauvegarder dans le stockage current_time = datetime.now().strftime('%H:%M:%S') subtitles_data[current_time] = cleaned_content # Sauvegarder dans le fichier de stockage storage_dir = "storage" if not os.path.exists(storage_dir): os.makedirs(storage_dir) subtitle_file = os.path.join(storage_dir, "subtitle_data.json") try: with open(subtitle_file, 'r', encoding='utf-8') as f: existing_data = json.load(f) except (FileNotFoundError, json.JSONDecodeError): existing_data = {} existing_data[current_time] = cleaned_content with open(subtitle_file, 'w', encoding='utf-8') as f: json.dump(existing_data, f, indent=4, ensure_ascii=False) subtitles_created += 1 # Nettoyer les fichiers temporaires os.remove(txt_file) os.remove(audio_path) # Supprimer le fichier audio traité except subprocess.TimeoutExpired: continue # Passer au fichier suivant except Exception as e: continue # Passer au fichier suivant return jsonify({ 'success': True, 'message': f'Traitement terminé. {subtitles_created} sous-titre(s) créé(s).', 'subtitles': subtitles_data }) except Exception as e: return jsonify({ 'success': False, 'error': f'Erreur lors du traitement: {str(e)}' }), 500 @app.route('/api/generations', methods=['GET']) def get_generations(): data = storage.read("IA_generator") return jsonify(data) @app.route('/api/send-message', methods=['POST']) def send_message(): data = request.json message = data.get('message') channel = data.get('channel', 'default') user_id = data.get('user_id', 0) # Nouveau paramètre pour choisir l'utilisateur if not message: return jsonify({'error': 'Message requis'}), 400 # Vérifier si l'envoi de messages est activé if not chat_messages_enabled: return jsonify({'error': 'Envoi de messages désactivé'}), 403 # Trouver le bot de message pour ce canal try: msg_bot = messageTwitch("config/user.json", channel) # Utiliser send_message_user au lieu de send_message pour spécifier l'utilisateur msg_bot.send_message_user(user_id, message) return jsonify({'success': True}) except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/api/generate-response', methods=['POST']) def generate_response(): data = request.json text = data.get('text', '') try: ia_gen = IA_generator("config/config.json") ia_gen.main_ask(text) return jsonify({'success': True}) except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/api/chat//messages', methods=['GET']) def get_chat_messages(flux_id): """Récupérer les messages de chat d'un flux spécifique""" try: if flux_id not in bot_controller.bots: return jsonify({'error': 'Flux non trouvé'}), 404 chat_bot = bot_controller.bots[flux_id]['chat_bot'] if not chat_bot: return jsonify({'error': 'Bot de chat non disponible'}), 404 # Récupérer les messages du bot de chat messages = [] for msg in chat_bot.messages[-50:]: # Derniers 50 messages messages.append({ 'timestamp': msg.timestamp.isoformat(), 'username': msg.username, 'content': msg.content }) return jsonify({ 'success': True, 'flux_id': flux_id, 'messages': messages }) except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/api/chat//send', methods=['POST']) def send_chat_message(flux_id): """Envoyer un message dans le chat d'un flux spécifique""" data = request.json message = data.get('message', '') user_id = data.get('user_id', 0) # Nouveau paramètre pour choisir l'utilisateur if not message: return jsonify({'error': 'Message requis'}), 400 # Vérifier si l'envoi de messages est activé if not chat_messages_enabled: return jsonify({'error': 'Envoi de messages désactivé'}), 403 try: # Trouver le flux flux = None for f in bot_controller.flux_list: if f['id'] == flux_id: flux = f break if not flux: return jsonify({'error': 'Flux non trouvé'}), 404 # Envoyer le message avec l'utilisateur spécifié msg_bot = messageTwitch("config/user.json", flux['twitchname']) msg_bot.send_message_user(user_id, message) return jsonify({'success': True}) except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/api/status', methods=['GET']) def get_status(): status = { 'flux_count': len(bot_controller.flux_list), 'active_recordings': sum(1 for f in bot_controller.flux_list if f['record_audio'] and f['active']), 'chat_connections': sum(1 for f in bot_controller.flux_list if f['active']), 'last_subtitle': '', 'next_message': '', 'recent_messages': [] } # Récupérer le dernier sous-titre subtitle_data = storage.read("subtitle_data") if subtitle_data: sorted_keys = sorted(subtitle_data.keys()) if sorted_keys: status['last_subtitle'] = subtitle_data[sorted_keys[-1]] # Récupérer la dernière génération generation_data = storage.read("IA_generator") if generation_data: sorted_keys = sorted(generation_data.keys()) if sorted_keys: status['next_message'] = generation_data[sorted_keys[-1]] return jsonify(status) @socketio.on('connect') def handle_connect(): print('Client connecté') emit('status', {'message': 'Connecté au serveur'}) @socketio.on('disconnect') def handle_disconnect(): print('Client déconnecté') # Thread pour envoyer les mises à jour en temps réel def background_updates(): while True: try: status = { 'timestamp': datetime.now().isoformat(), 'flux_count': len(bot_controller.flux_list), 'active_recordings': sum(1 for f in bot_controller.flux_list if f['record_audio'] and f['active']), } socketio.emit('status_update', status) time.sleep(5) # Mise à jour toutes les 5 secondes except Exception as e: print(f"Erreur dans background_updates: {e}") time.sleep(10) # Variables globales pour la génération automatique auto_subtitle_running = False current_processing_file = None # Variables globales pour l'envoi automatique de messages auto_message_running = False current_message_bot = None # Variable globale pour contrôler l'envoi de messages dans le chat chat_messages_enabled = True @app.route('/api/subtitles/auto/start', methods=['POST']) def start_auto_subtitle(): """Démarrer la génération automatique de sous-titres""" global auto_subtitle_running try: auto_subtitle_running = True # Démarrer le thread de génération automatique threading.Thread(target=auto_subtitle_loop, daemon=True).start() return jsonify({ 'success': True, 'message': 'Génération automatique démarrée' }) except Exception as e: return jsonify({ 'success': False, 'error': f'Erreur lors du démarrage: {str(e)}' }), 500 @app.route('/api/subtitles/auto/stop', methods=['POST']) def stop_auto_subtitle(): """Arrêter la génération automatique de sous-titres""" global auto_subtitle_running try: auto_subtitle_running = False return jsonify({ 'success': True, 'message': 'Génération automatique arrêtée' }) except Exception as e: return jsonify({ 'success': False, 'error': f'Erreur lors de l\'arrêt: {str(e)}' }), 500 @app.route('/api/subtitles/auto/status', methods=['GET']) def get_auto_subtitle_status(): """Obtenir le statut de la génération automatique""" global auto_subtitle_running, current_processing_file return jsonify({ 'running': auto_subtitle_running, 'current_file': current_processing_file }) def auto_subtitle_loop(): """Boucle de génération automatique de sous-titres""" global auto_subtitle_running, current_processing_file while auto_subtitle_running: try: # Vérifier s'il y a des fichiers audio à traiter record_dir = "record" if not os.path.exists(record_dir): time.sleep(5) continue audio_files = [f for f in os.listdir(record_dir) if f.endswith('.mp3')] if not audio_files: time.sleep(5) continue # Traiter le premier fichier audio_file = audio_files[0] current_processing_file = audio_file # Émettre l'événement de début de traitement socketio.emit('subtitle_processing_start', { 'file': audio_file, 'timestamp': datetime.now().isoformat() }) # Traiter le fichier audio_path = os.path.join(record_dir, audio_file) try: # Lancer Whisper command = [ 'whisper', '--language', 'fr', audio_path, '--device', 'cuda', '--model', 'large-v3' ] result = subprocess.run(command, capture_output=True, text=True, timeout=60) if result.returncode == 0: # Lire le fichier .txt généré txt_file = audio_file.replace('.mp3', '.txt') if os.path.exists(txt_file): with open(txt_file, 'r', encoding='utf-8') as f: content = f.read().strip() # Nettoyer le contenu content = content.replace("'", "").replace('"', "").replace("\n", " ").replace(",", "") # Supprimer les répétitions de mots words = content.split() seen = set() result_words = [] for word in words: if word not in seen: result_words.append(word) seen.add(word) cleaned_content = " ".join(result_words) # Sauvegarder dans le stockage current_time = datetime.now().strftime('%H:%M:%S') # Sauvegarder dans le fichier de stockage storage_dir = "storage" if not os.path.exists(storage_dir): os.makedirs(storage_dir) subtitle_file = os.path.join(storage_dir, "subtitle_data.json") try: with open(subtitle_file, 'r', encoding='utf-8') as f: existing_data = json.load(f) except (FileNotFoundError, json.JSONDecodeError): existing_data = {} existing_data[current_time] = cleaned_content with open(subtitle_file, 'w', encoding='utf-8') as f: json.dump(existing_data, f, indent=4, ensure_ascii=False) # Émettre l'événement de fin de traitement socketio.emit('subtitle_processing_complete', { 'file': audio_file, 'subtitle': cleaned_content, 'timestamp': current_time }) # Nettoyer les fichiers temporaires os.remove(txt_file) os.remove(audio_path) else: # Émettre l'événement d'erreur socketio.emit('subtitle_processing_error', { 'file': audio_file, 'error': 'Aucun fichier .txt généré' }) else: # Émettre l'événement d'erreur socketio.emit('subtitle_processing_error', { 'file': audio_file, 'error': f'Erreur Whisper: {result.stderr}' }) except subprocess.TimeoutExpired: socketio.emit('subtitle_processing_error', { 'file': audio_file, 'error': 'Timeout - Whisper a pris trop de temps' }) except Exception as e: socketio.emit('subtitle_processing_error', { 'file': audio_file, 'error': f'Erreur: {str(e)}' }) current_processing_file = None # Attendre avant de traiter le prochain fichier time.sleep(2) except Exception as e: print(f"Erreur dans la boucle de génération automatique: {e}") time.sleep(5) @app.route('/api/messages/auto/start', methods=['POST']) def start_auto_message(): """Démarrer l'envoi automatique de messages""" global auto_message_running, current_message_bot try: # Vérifier si déjà en cours if auto_message_running: return jsonify({ 'success': False, 'error': 'L\'envoi automatique est déjà en cours' }), 400 auto_message_running = True # Créer une instance du bot de messages current_message_bot = messageTwitch("config/user.json", "default") # Démarrer le thread d'envoi automatique threading.Thread(target=auto_message_loop, daemon=True).start() print(f"[{datetime.now().strftime('%H:%M:%S')}] Envoi automatique de messages démarré") return jsonify({ 'success': True, 'message': 'Envoi automatique de messages démarré' }) except Exception as e: auto_message_running = False current_message_bot = None return jsonify({ 'success': False, 'error': f'Erreur lors du démarrage: {str(e)}' }), 500 @app.route('/api/messages/auto/stop', methods=['POST']) def stop_auto_message(): """Arrêter l'envoi automatique de messages""" global auto_message_running, current_message_bot try: if not auto_message_running: return jsonify({ 'success': False, 'error': 'L\'envoi automatique n\'est pas en cours' }), 400 auto_message_running = False current_message_bot = None print(f"[{datetime.now().strftime('%H:%M:%S')}] Envoi automatique de messages arrêté") return jsonify({ 'success': True, 'message': 'Envoi automatique de messages arrêté' }) except Exception as e: return jsonify({ 'success': False, 'error': f'Erreur lors de l\'arrêt: {str(e)}' }), 500 @app.route('/api/messages/auto/force-stop', methods=['POST']) def force_stop_auto_message(): """Forcer l'arrêt de l'envoi automatique de messages""" global auto_message_running, current_message_bot try: auto_message_running = False current_message_bot = None print(f"[{datetime.now().strftime('%H:%M:%S')}] Arrêt forcé de l'envoi automatique de messages") return jsonify({ 'success': True, 'message': 'Arrêt forcé de l\'envoi automatique de messages' }) except Exception as e: return jsonify({ 'success': False, 'error': f'Erreur lors de l\'arrêt forcé: {str(e)}' }), 500 @app.route('/api/messages/auto/status', methods=['GET']) def get_auto_message_status(): """Obtenir le statut de l'envoi automatique de messages""" global auto_message_running return jsonify({ 'running': auto_message_running }) def auto_message_loop(): """Boucle d'envoi automatique de messages""" global auto_message_running, current_message_bot print(f"[{datetime.now().strftime('%H:%M:%S')}] Démarrage de la boucle d'envoi automatique") while auto_message_running: try: # Vérifier si l'envoi de messages est activé if not chat_messages_enabled: print(f"[{datetime.now().strftime('%H:%M:%S')}] Envoi de messages désactivé, attente...") time.sleep(5) continue # Vérifier s'il y a des générations disponibles generation_data = storage.read("IA_generator") if not generation_data: time.sleep(5) continue # Récupérer la dernière génération sorted_keys = sorted(generation_data.keys()) if not sorted_keys: time.sleep(5) continue last_generation = generation_data[sorted_keys[-1]] print(f"[{datetime.now().strftime('%H:%M:%S')}] Envoi automatique: {last_generation}") # Émettre l'événement de début d'envoi socketio.emit('message_sending_start', { 'message': last_generation, 'timestamp': datetime.now().isoformat() }) # Envoyer le message try: if current_message_bot: # Utiliser le premier utilisateur par défaut current_message_bot.send_message_user(0, last_generation) # Émettre l'événement de fin d'envoi socketio.emit('message_sending_complete', { 'message': last_generation, 'timestamp': datetime.now().isoformat() }) # Supprimer la génération envoyée storage.delete("IA_generator", sorted_keys[-1]) print(f"[{datetime.now().strftime('%H:%M:%S')}] Message envoyé avec succès") except Exception as e: # Émettre l'événement d'erreur socketio.emit('message_sending_error', { 'message': last_generation, 'error': str(e) }) print(f"[{datetime.now().strftime('%H:%M:%S')}] Erreur d'envoi: {e}") # Attendre avant d'envoyer le prochain message time.sleep(10) except Exception as e: print(f"[{datetime.now().strftime('%H:%M:%S')}] Erreur dans la boucle d'envoi automatique: {e}") time.sleep(5) print(f"[{datetime.now().strftime('%H:%M:%S')}] Arrêt de la boucle d'envoi automatique") @app.route('/api/chat/messages/enable', methods=['POST']) def enable_chat_messages(): """Activer l'envoi de messages dans le chat""" global chat_messages_enabled try: chat_messages_enabled = True return jsonify({ 'success': True, 'message': 'Envoi de messages dans le chat activé' }) except Exception as e: return jsonify({ 'success': False, 'error': f'Erreur lors de l\'activation: {str(e)}' }), 500 @app.route('/api/chat/messages/disable', methods=['POST']) def disable_chat_messages(): """Désactiver l'envoi de messages dans le chat""" global chat_messages_enabled try: chat_messages_enabled = False return jsonify({ 'success': True, 'message': 'Envoi de messages dans le chat désactivé' }) except Exception as e: return jsonify({ 'success': False, 'error': f'Erreur lors de la désactivation: {str(e)}' }), 500 @app.route('/api/chat/messages/status', methods=['GET']) def get_chat_messages_status(): """Obtenir le statut de l'envoi de messages dans le chat""" global chat_messages_enabled return jsonify({ 'enabled': chat_messages_enabled }) if __name__ == '__main__': # Démarrer les mises à jour en arrière-plan update_thread = threading.Thread(target=background_updates, daemon=True) update_thread.start() # Démarrer l'application Flask socketio.run(app, host='0.0.0.0', port=5000, debug=True)