ajout du control denvoi de message et interface up

This commit is contained in:
gpatruno
2025-07-20 04:34:00 +02:00
parent 75d9a65cc4
commit baefddd6b3
32 changed files with 3759 additions and 219 deletions
+538 -1
View File
@@ -56,7 +56,10 @@ class BotController:
chat_bot = TwitchChatBot(channel_name)
self.bots[flux_id] = {
'chat_bot': chat_bot,
'record_bot': None
'record_bot': None,
'subtitle_bot': None,
'ia_bot': None,
'message_bot': None
}
chat_bot.start_background()
@@ -65,6 +68,21 @@ class BotController:
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'
@@ -80,6 +98,12 @@ class BotController:
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]
@@ -98,6 +122,12 @@ class BotController:
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]
@@ -190,6 +220,12 @@ def toggle_flux(flux_id):
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:
@@ -199,6 +235,12 @@ def toggle_flux(flux_id):
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}")
@@ -330,6 +372,114 @@ 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")
@@ -345,6 +495,10 @@ def send_message():
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)
@@ -405,6 +559,10 @@ def send_chat_message(flux_id):
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
@@ -476,6 +634,385 @@ def background_updates():
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)