big update
This commit is contained in:
@@ -0,0 +1,345 @@
|
||||
"""Contrôle centralisé des flux Twitch, bots et boucles IA / envoi chat."""
|
||||
|
||||
import json
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
from fonction.first_class import (
|
||||
IA_generator,
|
||||
RecordTwitch,
|
||||
Subtitle_translation,
|
||||
TwitchChatBot,
|
||||
messageTwitch,
|
||||
storage,
|
||||
)
|
||||
|
||||
from twitch_bot import chat_state
|
||||
from twitch_bot.interaction_chat import InteractionChatProcessor
|
||||
|
||||
|
||||
def _resolve_user_index(pseudo: str) -> int:
|
||||
"""
|
||||
Retourne l'index d'un compte dans config/user.json (case-insensitive).
|
||||
Fallback: 0.
|
||||
"""
|
||||
try:
|
||||
with open("config/user.json", "r", encoding="utf-8") as f:
|
||||
users = json.load(f) or []
|
||||
pseudo_l = (pseudo or "").strip().lstrip("@").lower()
|
||||
for i, u in enumerate(users):
|
||||
p = (u or {}).get("tw_acc_pseudo")
|
||||
if isinstance(p, str) and p.strip().lower() == pseudo_l:
|
||||
return i
|
||||
except Exception:
|
||||
pass
|
||||
return 0
|
||||
|
||||
|
||||
def _resolve_first_enabled_user_index() -> int:
|
||||
try:
|
||||
with open("config/user.json", "r", encoding="utf-8") as f:
|
||||
users = json.load(f) or []
|
||||
for i, u in enumerate(users):
|
||||
if isinstance(u, dict) and u.get("enabled", True):
|
||||
return i
|
||||
except Exception:
|
||||
pass
|
||||
return 0
|
||||
|
||||
|
||||
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()
|
||||
self.ia_generator = None
|
||||
self.control_twitch = None
|
||||
self.ia_generator_running = False
|
||||
self.control_twitch_running = False
|
||||
|
||||
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 get_system_status(self):
|
||||
"""Obtenir le statut de tous les composants"""
|
||||
return {
|
||||
'ia_generator': {
|
||||
'running': self.ia_generator_running,
|
||||
'status': 'En cours' if self.ia_generator_running else 'Arrêté'
|
||||
},
|
||||
'control_twitch': {
|
||||
'running': self.control_twitch_running,
|
||||
'status': 'En cours' if self.control_twitch_running else 'Arrêté'
|
||||
},
|
||||
'flux_count': len(self.flux_list),
|
||||
'active_flux': len([f for f in self.flux_list if f['active']])
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
# Interaction chat (mentions -> réponses préenregistrées)
|
||||
def get_registered_accounts():
|
||||
try:
|
||||
with open("config/user.json", "r", encoding="utf-8") as f:
|
||||
users = json.load(f)
|
||||
pseudos = []
|
||||
for u in users or []:
|
||||
p = (u or {}).get("tw_acc_pseudo")
|
||||
enabled = (u or {}).get("enabled", True)
|
||||
if enabled and isinstance(p, str) and p.strip():
|
||||
pseudos.append(p.strip())
|
||||
return pseudos
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
def get_account_policies():
|
||||
try:
|
||||
with open("config/user.json", "r", encoding="utf-8") as f:
|
||||
users = json.load(f) or []
|
||||
out = {}
|
||||
for u in users:
|
||||
if not isinstance(u, dict):
|
||||
continue
|
||||
p = (u.get("tw_acc_pseudo") or "").strip().lstrip("@").lower()
|
||||
if not p:
|
||||
continue
|
||||
out[p] = {
|
||||
"enabled": bool(u.get("enabled", True)),
|
||||
"interaction_bypass_antiloop": bool(u.get("interaction_bypass_antiloop", False)),
|
||||
}
|
||||
return out
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
msg_bot_for_interaction = messageTwitch("config/user.json", channel_name)
|
||||
interaction = InteractionChatProcessor(
|
||||
channel_name=channel_name,
|
||||
get_registered_accounts=get_registered_accounts,
|
||||
get_account_policies=get_account_policies,
|
||||
send_message_as=lambda pseudo, text: msg_bot_for_interaction.send_message_user(
|
||||
_resolve_user_index(pseudo), text
|
||||
),
|
||||
)
|
||||
|
||||
self.bots[flux_id] = {
|
||||
'chat_bot': chat_bot,
|
||||
'record_bot': None,
|
||||
'subtitle_bot': None,
|
||||
'ia_bot': None,
|
||||
'message_bot': None,
|
||||
'interaction': interaction,
|
||||
}
|
||||
chat_bot.start_background()
|
||||
|
||||
interaction.start_background(get_latest_messages=lambda: chat_bot.messages)
|
||||
|
||||
# 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 Exception:
|
||||
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].get('interaction'):
|
||||
self.bots[flux_id]['interaction'].stop()
|
||||
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
|
||||
|
||||
def start_ia_generator(self):
|
||||
"""Démarrer le générateur IA de manière contrôlée"""
|
||||
if self.ia_generator_running:
|
||||
return False, "IA Generator déjà en cours d'exécution"
|
||||
|
||||
try:
|
||||
self.ia_generator = IA_generator("config/config.json")
|
||||
self.ia_generator_running = True
|
||||
|
||||
# Activer l'envoi de messages quand l'IA Generator est démarré
|
||||
chat_state.chat_messages_enabled = True
|
||||
|
||||
# Démarrer dans un thread séparé
|
||||
threading.Thread(target=self._ia_generator_loop, daemon=True).start()
|
||||
|
||||
print(f"[{datetime.now().strftime('%H:%M:%S')}] IA Generator démarré")
|
||||
return True, "IA Generator démarré avec succès"
|
||||
except Exception as e:
|
||||
self.ia_generator_running = False
|
||||
return False, f"Erreur lors du démarrage de l'IA Generator: {str(e)}"
|
||||
|
||||
def stop_ia_generator(self):
|
||||
"""Arrêter le générateur IA"""
|
||||
if not self.ia_generator_running:
|
||||
return False, "IA Generator n'est pas en cours d'exécution"
|
||||
|
||||
try:
|
||||
self.ia_generator_running = False
|
||||
if self.ia_generator:
|
||||
self.ia_generator.stop()
|
||||
|
||||
# Désactiver l'envoi de messages quand l'IA Generator est arrêté
|
||||
chat_state.chat_messages_enabled = False
|
||||
|
||||
print(f"[{datetime.now().strftime('%H:%M:%S')}] IA Generator arrêté")
|
||||
return True, "IA Generator arrêté avec succès"
|
||||
except Exception as e:
|
||||
return False, f"Erreur lors de l'arrêt de l'IA Generator: {str(e)}"
|
||||
|
||||
def _ia_generator_loop(self):
|
||||
"""Boucle contrôlée pour l'IA Generator"""
|
||||
while self.ia_generator_running:
|
||||
try:
|
||||
if self.ia_generator:
|
||||
self.ia_generator.main_ask("") # Génération automatique
|
||||
time.sleep(20) # Attendre 20 secondes entre les générations
|
||||
except Exception as e:
|
||||
print(f"[{datetime.now().strftime('%H:%M:%S')}] Erreur dans IA Generator: {e}")
|
||||
time.sleep(10)
|
||||
|
||||
def start_control_twitch(self):
|
||||
"""Démarrer le contrôleur Twitch de manière contrôlée"""
|
||||
if self.control_twitch_running:
|
||||
return False, "Control Twitch déjà en cours d'exécution"
|
||||
|
||||
try:
|
||||
# Utiliser le premier utilisateur par défaut
|
||||
self.control_twitch = messageTwitch("config/user.json", "default")
|
||||
self.control_twitch_running = True
|
||||
|
||||
# Démarrer dans un thread séparé
|
||||
threading.Thread(target=self._control_twitch_loop, daemon=True).start()
|
||||
|
||||
print(f"[{datetime.now().strftime('%H:%M:%S')}] Control Twitch démarré")
|
||||
return True, "Control Twitch démarré avec succès"
|
||||
except Exception as e:
|
||||
self.control_twitch_running = False
|
||||
return False, f"Erreur lors du démarrage de Control Twitch: {str(e)}"
|
||||
|
||||
def stop_control_twitch(self):
|
||||
"""Arrêter le contrôleur Twitch"""
|
||||
if not self.control_twitch_running:
|
||||
return False, "Control Twitch n'est pas en cours d'exécution"
|
||||
|
||||
try:
|
||||
self.control_twitch_running = False
|
||||
if self.control_twitch:
|
||||
self.control_twitch.stop()
|
||||
print(f"[{datetime.now().strftime('%H:%M:%S')}] Control Twitch arrêté")
|
||||
return True, "Control Twitch arrêté avec succès"
|
||||
except Exception as e:
|
||||
return False, f"Erreur lors de l'arrêt de Control Twitch: {str(e)}"
|
||||
|
||||
def _control_twitch_loop(self):
|
||||
"""Boucle contrôlée pour Control Twitch"""
|
||||
while self.control_twitch_running:
|
||||
try:
|
||||
if self.control_twitch:
|
||||
# Vérifier s'il y a des générations à envoyer
|
||||
generation_data = storage.read("IA_generator")
|
||||
if generation_data:
|
||||
sorted_keys = sorted(generation_data.keys())
|
||||
if sorted_keys:
|
||||
last_generation = generation_data[sorted_keys[-1]]
|
||||
# Envoyer le message avec le premier utilisateur activé
|
||||
self.control_twitch.send_message_user(_resolve_first_enabled_user_index(), last_generation)
|
||||
# Supprimer la génération envoyée
|
||||
storage.delete("IA_generator", sorted_keys[-1])
|
||||
print(f"[{datetime.now().strftime('%H:%M:%S')}] Message envoyé: {last_generation[:50]}...")
|
||||
time.sleep(10) # Attendre 10 secondes entre les vérifications
|
||||
except Exception as e:
|
||||
print(f"[{datetime.now().strftime('%H:%M:%S')}] Erreur dans Control Twitch: {e}")
|
||||
time.sleep(10)
|
||||
|
||||
|
||||
bot_controller = BotController()
|
||||
Reference in New Issue
Block a user