312 lines
11 KiB
Python
312 lines
11 KiB
Python
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
|
|
|
|
# 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
|
|
}
|
|
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()
|
|
|
|
# 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()
|
|
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()
|
|
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/<int:flux_id>', 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/<int:flux_id>/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/<int:flux_id>/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()
|
|
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()
|
|
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/subtitles', methods=['GET'])
|
|
def get_subtitles():
|
|
data = storage.read("subtitle_data")
|
|
return jsonify(data)
|
|
|
|
@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')
|
|
|
|
if not message:
|
|
return jsonify({'error': 'Message requis'}), 400
|
|
|
|
# Trouver le bot de message pour ce canal
|
|
try:
|
|
msg_bot = messageTwitch("config/user.json", channel)
|
|
msg_bot.send_message(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/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)
|
|
|
|
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) |