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
-1
View File
@@ -1 +0,0 @@
{"text": " Je fais quoi ? Gant de boxe ou club de golf ? Vas-y club de golf 32 d\u00e9g\u00e2ts pour l'attaque charg\u00e9e ? Ah ouais Pourquoi tu n'as pas pris les gants de boxe ? Parce que \u00e7a, \u00e7a fait 32 d\u00e9g\u00e2ts quand c'est charg\u00e9 C'est excellent Je pensais que c'\u00e9tait les gants de boxe Apr\u00e8s les gants de boxe ils t'aiment vite En vrai vas-y \u00e7a donne envie de les jouer C'est quoi tu veux pour le coup ? Ouais non", "segments": [{"id": 0, "seek": 0, "start": 0.0, "end": 2.72, "text": " Je fais quoi ?", "tokens": [50365, 2588, 12153, 11714, 2506, 50501], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}, {"id": 1, "seek": 0, "start": 2.72, "end": 5.4, "text": " Gant de boxe ou club de golf ?", "tokens": [50501, 460, 394, 368, 2424, 68, 2820, 6482, 368, 12880, 2506, 50635], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}, {"id": 2, "seek": 0, "start": 5.4, "end": 6.24, "text": " Vas-y club de golf", "tokens": [50635, 23299, 12, 88, 6482, 368, 12880, 50677], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}, {"id": 3, "seek": 0, "start": 6.24, "end": 7.5200000000000005, "text": " 32 d\u00e9g\u00e2ts pour l'attaque charg\u00e9e ?", "tokens": [50677, 8858, 2795, 70, 3201, 1373, 2016, 287, 6, 18405, 1077, 1290, 70, 3856, 2506, 50741], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}, {"id": 4, "seek": 0, "start": 7.5200000000000005, "end": 7.9, "text": " Ah ouais", "tokens": [50741, 2438, 30570, 50760], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}, {"id": 5, "seek": 0, "start": 7.9, "end": 12.120000000000001, "text": " Pourquoi tu n'as pas pris les gants de boxe ?", "tokens": [50760, 30333, 2604, 297, 6, 296, 1736, 16163, 1512, 290, 1719, 368, 2424, 68, 2506, 50971], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}, {"id": 6, "seek": 0, "start": 12.120000000000001, "end": 14.200000000000001, "text": " Parce que \u00e7a, \u00e7a fait 32 d\u00e9g\u00e2ts quand c'est charg\u00e9", "tokens": [50971, 20429, 631, 2788, 11, 2788, 3887, 8858, 2795, 70, 3201, 1373, 6932, 269, 6, 377, 1290, 70, 526, 51075], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}, {"id": 7, "seek": 0, "start": 14.200000000000001, "end": 16.86, "text": " C'est excellent", "tokens": [51075, 383, 6, 377, 7103, 51208], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}, {"id": 8, "seek": 0, "start": 16.86, "end": 17.94, "text": " Je pensais que c'\u00e9tait les gants de boxe", "tokens": [51208, 2588, 6099, 1527, 631, 269, 6, 9743, 1512, 290, 1719, 368, 2424, 68, 51262], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}, {"id": 9, "seek": 0, "start": 17.94, "end": 20.56, "text": " Apr\u00e8s les gants de boxe ils t'aiment vite", "tokens": [51262, 29265, 1512, 290, 1719, 368, 2424, 68, 9047, 256, 6, 64, 2328, 24462, 51393], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}, {"id": 10, "seek": 0, "start": 20.56, "end": 21.78, "text": " En vrai vas-y \u00e7a donne envie de les jouer", "tokens": [51393, 2193, 17815, 11481, 12, 88, 2788, 21837, 24149, 368, 1512, 30823, 51454], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}, {"id": 11, "seek": 0, "start": 21.78, "end": 24.0, "text": " C'est quoi tu veux pour le coup ?", "tokens": [51454, 383, 6, 377, 11714, 2604, 16389, 2016, 476, 8682, 2506, 51565], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}, {"id": 12, "seek": 0, "start": 25.28, "end": 25.96, "text": " Ouais non", "tokens": [51629, 25475, 2107, 51663], "temperature": 0.0, "avg_logprob": -0.25769146068676096, "compression_ratio": 1.6570247933884297, "no_speech_prob": 0.4927598834037781}], "language": "fr"}
-52
View File
@@ -1,52 +0,0 @@
1
00:00:00,000 --> 00:00:02,720
Je fais quoi ?
2
00:00:02,720 --> 00:00:05,400
Gant de boxe ou club de golf ?
3
00:00:05,400 --> 00:00:06,240
Vas-y club de golf
4
00:00:06,240 --> 00:00:07,520
32 dégâts pour l'attaque chargée ?
5
00:00:07,520 --> 00:00:07,900
Ah ouais
6
00:00:07,900 --> 00:00:12,120
Pourquoi tu n'as pas pris les gants de boxe ?
7
00:00:12,120 --> 00:00:14,200
Parce que ça, ça fait 32 dégâts quand c'est chargé
8
00:00:14,200 --> 00:00:16,860
C'est excellent
9
00:00:16,860 --> 00:00:17,940
Je pensais que c'était les gants de boxe
10
00:00:17,940 --> 00:00:20,560
Après les gants de boxe ils t'aiment vite
11
00:00:20,560 --> 00:00:21,780
En vrai vas-y ça donne envie de les jouer
12
00:00:21,780 --> 00:00:24,000
C'est quoi tu veux pour le coup ?
13
00:00:25,280 --> 00:00:25,960
Ouais non
-14
View File
@@ -1,14 +0,0 @@
start end text
0 2720 Je fais quoi ?
2720 5400 Gant de boxe ou club de golf ?
5400 6240 Vas-y club de golf
6240 7520 32 dégâts pour l'attaque chargée ?
7520 7900 Ah ouais
7900 12120 Pourquoi tu n'as pas pris les gants de boxe ?
12120 14200 Parce que ça, ça fait 32 dégâts quand c'est chargé
14200 16860 C'est excellent
16860 17940 Je pensais que c'était les gants de boxe
17940 20560 Après les gants de boxe ils t'aiment vite
20560 21780 En vrai vas-y ça donne envie de les jouer
21780 24000 C'est quoi tu veux pour le coup ?
25280 25960 Ouais non
1 start end text
2 0 2720 Je fais quoi ?
3 2720 5400 Gant de boxe ou club de golf ?
4 5400 6240 Vas-y club de golf
5 6240 7520 32 dégâts pour l'attaque chargée ?
6 7520 7900 Ah ouais
7 7900 12120 Pourquoi tu n'as pas pris les gants de boxe ?
8 12120 14200 Parce que ça, ça fait 32 dégâts quand c'est chargé
9 14200 16860 C'est excellent
10 16860 17940 Je pensais que c'était les gants de boxe
11 17940 20560 Après les gants de boxe ils t'aiment vite
12 20560 21780 En vrai vas-y ça donne envie de les jouer
13 21780 24000 C'est quoi tu veux pour le coup ?
14 25280 25960 Ouais non
-13
View File
@@ -1,13 +0,0 @@
Je fais quoi ?
Gant de boxe ou club de golf ?
Vas-y club de golf
32 dégâts pour l'attaque chargée ?
Ah ouais
Pourquoi tu n'as pas pris les gants de boxe ?
Parce que ça, ça fait 32 dégâts quand c'est chargé
C'est excellent
Je pensais que c'était les gants de boxe
Après les gants de boxe ils t'aiment vite
En vrai vas-y ça donne envie de les jouer
C'est quoi tu veux pour le coup ?
Ouais non
-41
View File
@@ -1,41 +0,0 @@
WEBVTT
00:00.000 --> 00:02.720
Je fais quoi ?
00:02.720 --> 00:05.400
Gant de boxe ou club de golf ?
00:05.400 --> 00:06.240
Vas-y club de golf
00:06.240 --> 00:07.520
32 dégâts pour l'attaque chargée ?
00:07.520 --> 00:07.900
Ah ouais
00:07.900 --> 00:12.120
Pourquoi tu n'as pas pris les gants de boxe ?
00:12.120 --> 00:14.200
Parce que ça, ça fait 32 dégâts quand c'est chargé
00:14.200 --> 00:16.860
C'est excellent
00:16.860 --> 00:17.940
Je pensais que c'était les gants de boxe
00:17.940 --> 00:20.560
Après les gants de boxe ils t'aiment vite
00:20.560 --> 00:21.780
En vrai vas-y ça donne envie de les jouer
00:21.780 --> 00:24.000
C'est quoi tu veux pour le coup ?
00:25.280 --> 00:25.960
Ouais non
+139
View File
@@ -0,0 +1,139 @@
# Toggle d'Envoi de Messages Chat
## 🎯 Fonctionnalité
Un nouveau bouton slide a été ajouté à l'interface web pour contrôler l'envoi de messages dans le chat Twitch. Cette fonctionnalité permet de désactiver temporairement tous les envois de messages du bot sans avoir à arrêter complètement le système.
## 🔧 Fonctionnement
### Interface Utilisateur
Le toggle se trouve dans la section "Actions Rapides" de l'interface web :
- **"Envoi Messages Chat"** : Un switch on/off pour activer/désactiver l'envoi de messages
- **Statut** : Indique si l'envoi est "Activé" (vert) ou "Désactivé" (gris)
### Comportement
Quand l'envoi de messages est **désactivé** :
1. ✅ Les messages manuels via l'interface web sont bloqués
2. ✅ Les messages automatiques sont bloqués
3. ✅ Les messages d'auto-réponse sont bloqués
4. ✅ Les messages de chat sont bloqués
5. ✅ Le bot continue de fonctionner normalement (enregistrement, génération IA, etc.)
6. ✅ Aucun message n'est envoyé sur Twitch
Quand l'envoi de messages est **activé** :
1. ✅ Tous les types de messages fonctionnent normalement
2. ✅ Les messages sont envoyés sur Twitch comme avant
## 🛠️ Implémentation Technique
### Backend (Python)
#### Variables Globales
```python
# Dans web_interface.py
chat_messages_enabled = True # Contrôle global de l'envoi de messages
```
#### Nouvelles Routes API
- `POST /api/chat/messages/enable` : Activer l'envoi de messages
- `POST /api/chat/messages/disable` : Désactiver l'envoi de messages
- `GET /api/chat/messages/status` : Obtenir le statut actuel
#### Vérifications Ajoutées
- Dans `send_message()` : Vérification avant envoi manuel
- Dans `send_chat_message()` : Vérification avant envoi de chat
- Dans `auto_message_loop()` : Vérification avant envoi automatique
- Dans `messageTwitch.send_message()` : Vérification au niveau de la classe
### Frontend (JavaScript)
#### Nouvelles Fonctions
- `toggleChatMessage()` : Gère le changement d'état du toggle
- `checkChatMessageStatus()` : Vérifie le statut au chargement
#### Interface HTML
```html
<!-- Chat Message Toggle -->
<div class="mt-3">
<div class="d-flex justify-content-between align-items-center">
<span class="small text-muted">Envoi Messages Chat</span>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="chatMessageToggle" onchange="toggleChatMessage()" checked>
<label class="form-check-label small" for="chatMessageToggle"></label>
</div>
</div>
<div class="mt-2">
<small class="text-muted" id="chatMessageStatus">Activé</small>
</div>
</div>
```
## 🧪 Tests
Un script de test est disponible : `test_chat_toggle.py`
```bash
# Démarrer le serveur web
python start_web_interface.py
# Dans un autre terminal, lancer les tests
python test_chat_toggle.py
```
## 📋 Utilisation
### Via l'Interface Web
1. Ouvrir l'interface web sur `http://localhost:5000`
2. Aller dans la section "Actions Rapides" (sidebar gauche)
3. Trouver le toggle "Envoi Messages Chat"
4. Cliquer pour activer/désactiver
### Via l'API REST
```bash
# Désactiver l'envoi de messages
curl -X POST http://localhost:5000/api/chat/messages/disable
# Activer l'envoi de messages
curl -X POST http://localhost:5000/api/chat/messages/enable
# Vérifier le statut
curl http://localhost:5000/api/chat/messages/status
```
## 🔒 Sécurité
- Le toggle est persistant pendant la session du serveur
- Les tentatives d'envoi de messages sont bloquées avec un message d'erreur approprié
- Aucun message n'est envoyé quand le toggle est désactivé
- Le système continue de fonctionner normalement pour les autres fonctionnalités
## 🚀 Avantages
1. **Contrôle Granulaire** : Permet de désactiver uniquement l'envoi de messages
2. **Sécurité** : Évite les envois accidentels de messages
3. **Flexibilité** : Activation/désactivation en temps réel
4. **Transparence** : Interface claire avec statut visuel
5. **Non-intrusif** : N'affecte pas les autres fonctionnalités du bot
## 🐛 Dépannage
### Le toggle ne fonctionne pas
- Vérifier que le serveur web est démarré
- Recharger la page web
- Vérifier les logs du serveur pour les erreurs
### Les messages sont toujours envoyés
- Vérifier que le toggle est bien désactivé
- Redémarrer le serveur web si nécessaire
- Vérifier que les routes API répondent correctement
### Erreur 403 lors de l'envoi de messages
- C'est normal quand l'envoi est désactivé
- Réactiver le toggle pour pouvoir envoyer des messages
+5
View File
@@ -8,5 +8,10 @@
"tw_acc_pseudo": "SnowLunaSoft",
"tw_acc_token": "oauth:l348b8e7g7srjnc8trnxjqe2i2boq2",
"charactere": "Kappa"
},
{
"tw_acc_pseudo": "exoticnaturees",
"tw_acc_token": "oauth:ac5r1i8upt5isxdhpxdmf8u1c2lo0u",
"charactere": "😊"
}
]
Submodule debug_ia_clone deleted from bb743c5722
+127
View File
@@ -0,0 +1,127 @@
#!/usr/bin/env python3
"""
Script de démonstration des systèmes automatiques
"""
import os
import json
from datetime import datetime
def demo_auto_systems():
"""Démonstration des systèmes automatiques"""
print("🎬 Démonstration des systèmes automatiques")
print("=" * 60)
# 1. Vérifier les fichiers audio
record_dir = "record"
if os.path.exists(record_dir):
audio_files = [f for f in os.listdir(record_dir) if f.endswith('.mp3')]
print(f"{len(audio_files)} fichiers audio disponibles pour les sous-titres")
else:
print("❌ Dossier record non trouvé")
# 2. Vérifier les générations
storage_dir = "storage"
generation_file = os.path.join(storage_dir, "IA_generator.json")
if os.path.exists(generation_file):
try:
with open(generation_file, 'r', encoding='utf-8') as f:
generation_data = json.load(f)
print(f"{len(generation_data)} générations disponibles pour l'envoi automatique")
if generation_data:
sorted_keys = sorted(generation_data.keys())
last_generation = generation_data[sorted_keys[-1]]
print(f"📝 Dernière génération: {last_generation}")
except Exception as e:
print(f"⚠️ Erreur lecture générations: {e}")
else:
print("📝 Aucune génération disponible")
# 3. Vérifier les utilisateurs
user_config = "config/user.json"
if os.path.exists(user_config):
try:
with open(user_config, 'r') as f:
users = json.load(f)
print(f"{len(users)} utilisateur(s) configuré(s) pour l'envoi")
except Exception as e:
print(f"⚠️ Erreur lecture utilisateurs: {e}")
else:
print("❌ Fichier de configuration utilisateur non trouvé")
return True
def show_interface_instructions():
"""Afficher les instructions pour l'interface"""
print("\n🌐 Instructions pour l'interface web:")
print("=" * 50)
print("\n📺 Génération automatique de sous-titres:")
print(" 1. Ouvrir http://localhost:5000")
print(" 2. Dans le tableau de bord (sidebar gauche)")
print(" 3. Trouver le switch 'Génération Auto Sous-titres'")
print(" 4. Activer le switch pour démarrer")
print(" 5. Aller dans l'onglet 'Sous-titres' pour voir le fichier en cours")
print(" 6. Les sous-titres seront créés automatiquement fichier par fichier")
print("\n💬 Envoi automatique de messages:")
print(" 1. Dans le tableau de bord (sidebar gauche)")
print(" 2. Trouver le switch 'Envoi Auto Messages'")
print(" 3. Activer le switch pour démarrer")
print(" 4. Les messages seront envoyés automatiquement quand des générations sont disponibles")
print(" 5. Délai de 10 secondes entre chaque envoi")
print("\n🔄 Fonctionnement combiné:")
print(" - Les sous-titres sont générés automatiquement")
print(" - Les générations IA sont créées à partir des sous-titres")
print(" - Les messages sont envoyés automatiquement")
print(" - Tout fonctionne en boucle automatique")
def show_features():
"""Afficher les fonctionnalités ajoutées"""
print("\n📋 Fonctionnalités ajoutées:")
print("=" * 50)
print("\n🎛️ Contrôles automatiques:")
print(" ✅ Switch 'Génération Auto Sous-titres'")
print(" ✅ Switch 'Envoi Auto Messages'")
print(" ✅ Indicateurs de statut en temps réel")
print(" ✅ Gestion des erreurs avec alertes")
print("\n🔄 Traitement automatique:")
print(" ✅ Surveillance des fichiers audio")
print(" ✅ Transcription avec Whisper")
print(" ✅ Nettoyage et formatage des sous-titres")
print(" ✅ Sauvegarde automatique")
print(" ✅ Surveillance des générations IA")
print(" ✅ Envoi automatique de messages")
print(" ✅ Suppression des données traitées")
print("\n📡 Communication temps réel:")
print(" ✅ Événements Socket.IO pour le traitement")
print(" ✅ Événements Socket.IO pour l'envoi")
print(" ✅ Alertes en temps réel")
print(" ✅ Actualisation automatique de l'interface")
if __name__ == '__main__':
print("🚀 Démonstration des systèmes automatiques")
print("=" * 60)
# Test des systèmes
success = demo_auto_systems()
# Instructions d'interface
show_interface_instructions()
# Fonctionnalités
show_features()
print("\n" + "=" * 60)
if success:
print("✅ Systèmes prêts !")
print("🎉 Vous pouvez maintenant utiliser les switches dans l'interface web")
print("💡 Les deux systèmes fonctionnent indépendamment ou ensemble")
else:
print("❌ Problèmes détectés")
print("🔧 Vérifiez la configuration avant d'utiliser les systèmes automatiques")
+126
View File
@@ -0,0 +1,126 @@
#!/usr/bin/env python3
"""
Script de démonstration du système de sous-titres
"""
import os
import json
from datetime import datetime
def demo_subtitle_system():
"""Démonstration du système de sous-titres"""
print("🎬 Démonstration du système de sous-titres")
print("=" * 60)
# 1. Vérifier les fichiers audio
record_dir = "record"
if not os.path.exists(record_dir):
print(f"❌ Dossier record non trouvé: {record_dir}")
return False
audio_files = [f for f in os.listdir(record_dir) if f.endswith('.mp3')]
if not audio_files:
print(f"❌ Aucun fichier audio trouvé dans {record_dir}")
return False
print(f"{len(audio_files)} fichiers audio trouvés")
print(f"📁 Premier fichier: {audio_files[0]}")
print(f"📁 Dernier fichier: {audio_files[-1]}")
# 2. Vérifier le stockage
storage_dir = "storage"
subtitle_file = os.path.join(storage_dir, "subtitle_data.json")
if os.path.exists(subtitle_file):
try:
with open(subtitle_file, 'r', encoding='utf-8') as f:
subtitle_data = json.load(f)
print(f"✅ Stockage existant avec {len(subtitle_data)} sous-titre(s)")
if subtitle_data:
print("📝 Derniers sous-titres:")
sorted_keys = sorted(subtitle_data.keys())
for key in sorted_keys[-3:]: # Afficher les 3 derniers
print(f" {key}: {subtitle_data[key]}")
except Exception as e:
print(f"⚠️ Erreur lecture stockage: {e}")
else:
print("📝 Aucun stockage existant")
# 3. Simuler le traitement manuel
print("\n🔧 Simulation du traitement manuel:")
print(" 1. Détection des fichiers audio ✅")
print(" 2. Lancement de Whisper sur chaque fichier")
print(" 3. Nettoyage et suppression des répétitions")
print(" 4. Sauvegarde dans le stockage")
print(" 5. Nettoyage des fichiers temporaires")
# 4. Créer un exemple de sous-titre
example_subtitle = {
"03:52:30": "Voici un exemple de sous-titre généré",
"03:52:35": "Le système fonctionne correctement",
"03:52:40": "Whisper traite les fichiers audio"
}
# Sauvegarder l'exemple
if not os.path.exists(storage_dir):
os.makedirs(storage_dir)
try:
with open(subtitle_file, 'w', encoding='utf-8') as f:
json.dump(example_subtitle, f, indent=4, ensure_ascii=False)
print("✅ Exemple de sous-titres sauvegardé")
except Exception as e:
print(f"❌ Erreur sauvegarde: {e}")
# 5. Afficher les instructions pour l'interface web
print("\n🌐 Instructions pour l'interface web:")
print(" 1. Ouvrir http://localhost:5000")
print(" 2. Aller dans l'onglet 'Sous-titres'")
print(" 3. Cliquer sur 'Traitement Manuel'")
print(" 4. Attendre le traitement des fichiers audio")
print(" 5. Voir les sous-titres générés")
return True
def test_whisper_availability():
"""Tester la disponibilité de Whisper"""
print("\n🔍 Test de Whisper:")
try:
import subprocess
result = subprocess.run(['whisper', '--help'], capture_output=True, text=True, timeout=10)
if result.returncode == 0:
print("✅ Whisper est disponible et fonctionnel")
return True
else:
print("❌ Whisper ne répond pas correctement")
return False
except FileNotFoundError:
print("❌ Whisper n'est pas installé")
return False
except Exception as e:
print(f"❌ Erreur test Whisper: {e}")
return False
if __name__ == '__main__':
print("🚀 Démonstration du système de sous-titres")
print("=" * 60)
# Test 1: Système de base
system_ok = demo_subtitle_system()
# Test 2: Whisper
whisper_ok = test_whisper_availability()
print("\n" + "=" * 60)
if system_ok and whisper_ok:
print("✅ Système prêt !")
print("🎉 Vous pouvez maintenant utiliser le bouton 'Traitement Manuel'")
print(" dans l'interface web pour créer des sous-titres.")
else:
print("❌ Problèmes détectés")
if not system_ok:
print(" - Problème avec le système de base")
if not whisper_ok:
print(" - Problème avec Whisper")
+140
View File
@@ -0,0 +1,140 @@
#!/usr/bin/env python3
"""
Script de diagnostic pour l'envoi automatique de messages
"""
import os
import json
import requests
from datetime import datetime
def check_server_status():
"""Vérifier le statut du serveur web"""
try:
response = requests.get('http://localhost:5000/api/messages/auto/status', timeout=5)
if response.status_code == 200:
status = response.json()
print(f"✅ Serveur web accessible")
print(f"📊 Statut envoi automatique: {'Actif' if status['running'] else 'Arrêté'}")
return status['running']
else:
print(f"❌ Erreur serveur: {response.status_code}")
return None
except requests.exceptions.ConnectionError:
print("❌ Serveur web non accessible")
return None
except Exception as e:
print(f"❌ Erreur: {e}")
return None
def force_stop_auto_message():
"""Forcer l'arrêt de l'envoi automatique"""
try:
response = requests.post('http://localhost:5000/api/messages/auto/force-stop', timeout=5)
if response.status_code == 200:
result = response.json()
if result['success']:
print("✅ Arrêt forcé réussi")
return True
else:
print(f"❌ Erreur: {result['error']}")
return False
else:
print(f"❌ Erreur serveur: {response.status_code}")
return False
except Exception as e:
print(f"❌ Erreur: {e}")
return False
def check_generations():
"""Vérifier les générations disponibles"""
storage_dir = "storage"
generation_file = os.path.join(storage_dir, "IA_generator.json")
if os.path.exists(generation_file):
try:
with open(generation_file, 'r', encoding='utf-8') as f:
generation_data = json.load(f)
print(f"📝 {len(generation_data)} génération(s) disponible(s)")
if generation_data:
sorted_keys = sorted(generation_data.keys())
last_generation = generation_data[sorted_keys[-1]]
print(f"📝 Dernière génération: {last_generation}")
return len(generation_data)
except Exception as e:
print(f"⚠️ Erreur lecture générations: {e}")
else:
print("📝 Aucune génération disponible")
return 0
def check_users():
"""Vérifier les utilisateurs configurés"""
user_config = "config/user.json"
if os.path.exists(user_config):
try:
with open(user_config, 'r') as f:
users = json.load(f)
print(f"👥 {len(users)} utilisateur(s) configuré(s)")
return len(users)
except Exception as e:
print(f"⚠️ Erreur lecture utilisateurs: {e}")
else:
print("❌ Fichier de configuration utilisateur non trouvé")
return 0
def main():
"""Diagnostic principal"""
print("🔍 Diagnostic de l'envoi automatique de messages")
print("=" * 60)
# 1. Vérifier le serveur
print("\n🌐 Vérification du serveur web...")
server_running = check_server_status()
# 2. Vérifier les générations
print("\n📝 Vérification des générations...")
generations_count = check_generations()
# 3. Vérifier les utilisateurs
print("\n👥 Vérification des utilisateurs...")
users_count = check_users()
# 4. Diagnostic et solutions
print("\n🔧 Diagnostic et solutions:")
print("=" * 40)
if server_running is None:
print("❌ Problème: Serveur web non accessible")
print("💡 Solution: Démarrer le serveur avec 'python web_interface.py'")
return
if server_running:
print("⚠️ Problème: L'envoi automatique est actif mais le bouton est désactivé")
print("💡 Solution: Utiliser le bouton 'Force Stop' dans l'interface")
# Proposer d'arrêter automatiquement
print("\n🛑 Arrêt automatique de l'envoi...")
if force_stop_auto_message():
print("✅ Envoi automatique arrêté avec succès")
else:
print("❌ Échec de l'arrêt automatique")
else:
print("✅ Envoi automatique correctement arrêté")
if generations_count == 0:
print("⚠️ Aucune génération disponible pour l'envoi")
print("💡 Solution: Créer des générations IA d'abord")
if users_count == 0:
print("❌ Aucun utilisateur configuré")
print("💡 Solution: Configurer des utilisateurs dans l'interface")
print("\n" + "=" * 60)
print("✅ Diagnostic terminé")
print("💡 Vérifiez l'interface web pour confirmer l'état")
if __name__ == '__main__':
main()
+106
View File
@@ -0,0 +1,106 @@
#!/usr/bin/env python3
"""
Script de diagnostic simplifié pour l'envoi automatique de messages
"""
import os
import json
from datetime import datetime
def check_generations():
"""Vérifier les générations disponibles"""
storage_dir = "storage"
generation_file = os.path.join(storage_dir, "IA_generator.json")
if os.path.exists(generation_file):
try:
with open(generation_file, 'r', encoding='utf-8') as f:
generation_data = json.load(f)
print(f"📝 {len(generation_data)} génération(s) disponible(s)")
if generation_data:
sorted_keys = sorted(generation_data.keys())
last_generation = generation_data[sorted_keys[-1]]
print(f"📝 Dernière génération: {last_generation}")
return len(generation_data)
except Exception as e:
print(f"⚠️ Erreur lecture générations: {e}")
else:
print("📝 Aucune génération disponible")
return 0
def check_users():
"""Vérifier les utilisateurs configurés"""
user_config = "config/user.json"
if os.path.exists(user_config):
try:
with open(user_config, 'r') as f:
users = json.load(f)
print(f"👥 {len(users)} utilisateur(s) configuré(s)")
for i, user in enumerate(users):
print(f" {i}: {user['tw_acc_pseudo']} {user['charactere']}")
return len(users)
except Exception as e:
print(f"⚠️ Erreur lecture utilisateurs: {e}")
else:
print("❌ Fichier de configuration utilisateur non trouvé")
return 0
def check_web_interface():
"""Vérifier si l'interface web est accessible"""
print("🌐 Vérification de l'interface web...")
print(" Ouvrez http://localhost:5000 dans votre navigateur")
print(" Vérifiez le statut du switch 'Envoi Auto Messages'")
print(" Si le switch est désactivé mais que des messages sont envoyés:")
print(" 1. Cliquez sur le bouton 'Force Stop'")
print(" 2. Attendez quelques secondes")
print(" 3. Rechargez la page")
def main():
"""Diagnostic principal"""
print("🔍 Diagnostic de l'envoi automatique de messages")
print("=" * 60)
# 1. Vérifier les générations
print("\n📝 Vérification des générations...")
generations_count = check_generations()
# 2. Vérifier les utilisateurs
print("\n👥 Vérification des utilisateurs...")
users_count = check_users()
# 3. Instructions pour l'interface
print("\n🌐 Instructions pour corriger le problème:")
print("=" * 50)
if generations_count > 0:
print("✅ Des générations sont disponibles")
print("⚠️ Si l'envoi automatique est actif, les messages seront envoyés")
else:
print("📝 Aucune génération disponible")
print("💡 Créez des générations IA d'abord")
if users_count > 0:
print("✅ Des utilisateurs sont configurés")
else:
print("❌ Aucun utilisateur configuré")
print("💡 Configurez des utilisateurs dans l'interface")
print("\n🔧 Solutions pour le problème:")
print(" 1. Ouvrir http://localhost:5000")
print(" 2. Dans le tableau de bord (sidebar gauche)")
print(" 3. Trouver le switch 'Envoi Auto Messages'")
print(" 4. Si le switch est désactivé mais que des messages sont envoyés:")
print(" - Cliquer sur le bouton 'Force Stop'")
print(" - Attendre quelques secondes")
print(" - Recharger la page")
print(" 5. Vérifier que le statut affiche 'Arrêté'")
print("\n" + "=" * 60)
print("✅ Diagnostic terminé")
print("💡 Suivez les instructions ci-dessus pour corriger le problème")
if __name__ == '__main__':
main()
+15
View File
@@ -1007,6 +1007,21 @@ class messageTwitch:
def send_message(self, Message_text):
try:
# Vérifier si l'envoi de messages est activé (variable globale accessible depuis web_interface)
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
# Essayer d'importer la variable depuis web_interface
try:
from web_interface import chat_messages_enabled
if not chat_messages_enabled:
debug_print("w", "Envoi de messages désactivé, message ignoré", self.type_debug, self.script_name)
return
except ImportError:
# Si web_interface n'est pas disponible, on continue normalement
pass
command = '-pseudo "'+self.tw_acc_pseudo+'" -token "'+self.tw_acc_token+'" -twitchname "'+self.channel_name+'" -message " '+self.charactere+' '+Message_text+'"'
# Utiliser le Python de l'environnement virtuel
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-5
View File
@@ -1,5 +0,0 @@
Flask==2.3.2
Flask-SocketIO==5.3.4
python-socketio==5.8.0
python-engineio==4.7.1
eventlet==0.33.3
+1236 -45
View File
File diff suppressed because it is too large Load Diff
+437 -1
View File
@@ -63,7 +63,10 @@ async function loadInitialData() {
loadUsers(),
loadStatus(),
loadSubtitles(),
loadGenerations()
loadGenerations(),
checkAutoSubtitleStatus(), // Ajouter la vérification du statut auto
checkAutoMessageStatus(), // Ajouter la vérification du statut auto messages
checkChatMessageStatus() // Ajouter la vérification du statut chat messages
]);
} catch (error) {
console.error('Erreur lors du chargement des données:', error);
@@ -558,6 +561,40 @@ async function generateFromSubtitle() {
}
}
function processSubtitles() {
// Afficher un indicateur de chargement
const button = event.target;
const originalText = button.innerHTML;
button.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Traitement en cours...';
button.disabled = true;
fetch('/api/subtitles/process', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.message, 'success');
// Actualiser les sous-titres
loadSubtitles();
} else {
showAlert('Erreur: ' + data.error, 'danger');
}
})
.catch(error => {
console.error('Erreur:', error);
showAlert('Erreur lors du traitement des sous-titres', 'danger');
})
.finally(() => {
// Restaurer le bouton
button.innerHTML = originalText;
button.disabled = false;
});
}
// === GESTION DES GÉNÉRATIONS ===
// Chargement des générations
@@ -685,6 +722,28 @@ function showToast(message, type = 'info') {
});
}
// === FONCTIONS UTILITAIRES ===
function showAlert(message, type = 'info') {
const alertDiv = document.createElement('div');
alertDiv.className = `alert alert-${type} alert-dismissible fade show`;
alertDiv.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
// Ajouter l'alerte en haut de la page
const container = document.querySelector('.container-fluid');
container.insertBefore(alertDiv, container.firstChild);
// Supprimer automatiquement après 5 secondes
setTimeout(() => {
if (alertDiv.parentNode) {
alertDiv.remove();
}
}, 5000);
}
// Gestion des erreurs globales
window.addEventListener('error', function(e) {
console.error('Erreur JavaScript:', e.error);
@@ -1202,3 +1261,380 @@ async function deleteUser(userId) {
showToast('Erreur lors de la suppression', 'error');
}
}
// Variables globales pour la génération automatique
let autoSubtitleRunning = false;
// Variables globales pour l'envoi automatique de messages
let autoMessageRunning = false;
// Écouteurs Socket.IO pour la génération automatique
socket.on('subtitle_processing_start', function(data) {
console.log('Début de traitement:', data.file);
showProcessingFile(data.file);
});
socket.on('subtitle_processing_complete', function(data) {
console.log('Traitement terminé:', data.file);
hideProcessingFile();
showAlert(`Sous-titre créé pour ${data.file}: ${data.subtitle}`, 'success');
loadSubtitles(); // Actualiser les sous-titres
});
socket.on('subtitle_processing_error', function(data) {
console.log('Erreur de traitement:', data.file, data.error);
hideProcessingFile();
showAlert(`Erreur pour ${data.file}: ${data.error}`, 'danger');
});
// Écouteurs Socket.IO pour l'envoi automatique de messages
socket.on('message_sending_start', function(data) {
console.log('Début d\'envoi de message:', data.message);
showAlert(`Envoi en cours: ${data.message}`, 'info');
});
socket.on('message_sending_complete', function(data) {
console.log('Message envoyé:', data.message);
showAlert(`Message envoyé: ${data.message}`, 'success');
loadGenerations(); // Actualiser les générations
});
socket.on('message_sending_error', function(data) {
console.log('Erreur d\'envoi:', data.message, data.error);
showAlert(`Erreur d'envoi: ${data.error}`, 'danger');
});
// Fonction pour activer/désactiver l'envoi automatique de messages
async function toggleAutoMessage() {
const toggle = document.getElementById('autoMessageToggle');
const statusElement = document.getElementById('autoMessageStatus');
if (toggle.checked) {
// Démarrer l'envoi automatique de messages
try {
const response = await fetch('/api/messages/auto/start', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (result.success) {
autoMessageRunning = true;
statusElement.textContent = 'En cours...';
statusElement.className = 'text-success';
showAlert('Envoi automatique de messages démarré', 'success');
} else {
toggle.checked = false;
showAlert('Erreur: ' + result.error, 'danger');
}
} catch (error) {
console.error('Erreur:', error);
toggle.checked = false;
showAlert('Erreur lors du démarrage', 'danger');
}
} else {
// Arrêter l'envoi automatique de messages
try {
const response = await fetch('/api/messages/auto/stop', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (result.success) {
autoMessageRunning = false;
statusElement.textContent = 'Arrêté';
statusElement.className = 'text-muted';
showAlert('Envoi automatique de messages arrêté', 'info');
} else {
toggle.checked = true;
showAlert('Erreur: ' + result.error, 'danger');
}
} catch (error) {
console.error('Erreur:', error);
toggle.checked = true;
showAlert('Erreur lors de l\'arrêt', 'danger');
}
}
}
// Fonction pour vérifier le statut de l'envoi automatique de messages au chargement
async function checkAutoMessageStatus() {
try {
const response = await fetch('/api/messages/auto/status');
const status = await response.json();
const toggle = document.getElementById('autoMessageToggle');
const statusElement = document.getElementById('autoMessageStatus');
if (toggle && statusElement) {
// Synchroniser l'état du toggle avec le serveur
toggle.checked = status.running;
autoMessageRunning = status.running;
if (status.running) {
statusElement.textContent = 'En cours...';
statusElement.className = 'text-success';
console.log('Envoi automatique de messages actif');
} else {
statusElement.textContent = 'Arrêté';
statusElement.className = 'text-muted';
console.log('Envoi automatique de messages arrêté');
}
}
} catch (error) {
console.error('Erreur lors de la vérification du statut:', error);
// En cas d'erreur, forcer l'arrêt
const toggle = document.getElementById('autoMessageToggle');
const statusElement = document.getElementById('autoMessageStatus');
if (toggle && statusElement) {
toggle.checked = false;
statusElement.textContent = 'Arrêté';
statusElement.className = 'text-muted';
autoMessageRunning = false;
}
}
}
// Fonction pour activer/désactiver la génération automatique
async function toggleAutoSubtitle() {
const toggle = document.getElementById('autoSubtitleToggle');
const statusElement = document.getElementById('autoSubtitleStatus');
if (toggle.checked) {
// Démarrer la génération automatique
try {
const response = await fetch('/api/subtitles/auto/start', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (result.success) {
autoSubtitleRunning = true;
statusElement.textContent = 'En cours...';
statusElement.className = 'text-success';
showAlert('Génération automatique démarrée', 'success');
} else {
toggle.checked = false;
showAlert('Erreur: ' + result.error, 'danger');
}
} catch (error) {
console.error('Erreur:', error);
toggle.checked = false;
showAlert('Erreur lors du démarrage', 'danger');
}
} else {
// Arrêter la génération automatique
try {
const response = await fetch('/api/subtitles/auto/stop', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (result.success) {
autoSubtitleRunning = false;
statusElement.textContent = 'Arrêté';
statusElement.className = 'text-muted';
hideProcessingFile();
showAlert('Génération automatique arrêtée', 'info');
} else {
toggle.checked = true;
showAlert('Erreur: ' + result.error, 'danger');
}
} catch (error) {
console.error('Erreur:', error);
toggle.checked = true;
showAlert('Erreur lors de l\'arrêt', 'danger');
}
}
}
// Fonction pour afficher le fichier en cours de traitement
function showProcessingFile(fileName) {
const processingElement = document.getElementById('processing-file');
const fileNameElement = document.getElementById('current-file-name');
if (processingElement && fileNameElement) {
fileNameElement.textContent = `Traitement de: ${fileName}`;
processingElement.classList.remove('d-none');
}
}
// Fonction pour masquer le fichier en cours de traitement
function hideProcessingFile() {
const processingElement = document.getElementById('processing-file');
if (processingElement) {
processingElement.classList.add('d-none');
}
}
// Fonction pour vérifier le statut de la génération automatique au chargement
async function checkAutoSubtitleStatus() {
try {
const response = await fetch('/api/subtitles/auto/status');
const status = await response.json();
const toggle = document.getElementById('autoSubtitleToggle');
const statusElement = document.getElementById('autoSubtitleStatus');
if (toggle && statusElement) {
toggle.checked = status.running;
autoSubtitleRunning = status.running;
if (status.running) {
statusElement.textContent = 'En cours...';
statusElement.className = 'text-success';
if (status.current_file) {
showProcessingFile(status.current_file);
}
} else {
statusElement.textContent = 'Arrêté';
statusElement.className = 'text-muted';
hideProcessingFile();
}
}
} catch (error) {
console.error('Erreur lors de la vérification du statut:', error);
}
}
// Fonction pour forcer l'arrêt de l'envoi automatique
async function forceStopAutoMessage() {
try {
const response = await fetch('/api/messages/auto/force-stop', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (result.success) {
// Mettre à jour l'interface
const toggle = document.getElementById('autoMessageToggle');
const statusElement = document.getElementById('autoMessageStatus');
if (toggle && statusElement) {
toggle.checked = false;
statusElement.textContent = 'Arrêté';
statusElement.className = 'text-muted';
autoMessageRunning = false;
}
showAlert('Arrêt forcé de l\'envoi automatique de messages', 'warning');
} else {
showAlert('Erreur: ' + result.error, 'danger');
}
} catch (error) {
console.error('Erreur lors de l\'arrêt forcé:', error);
showAlert('Erreur lors de l\'arrêt forcé', 'danger');
}
}
// Fonction pour activer/désactiver l'envoi de messages dans le chat
async function toggleChatMessage() {
const toggle = document.getElementById('chatMessageToggle');
const statusElement = document.getElementById('chatMessageStatus');
if (toggle.checked) {
// Activer l'envoi de messages
try {
const response = await fetch('/api/chat/messages/enable', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (result.success) {
statusElement.textContent = 'Activé';
statusElement.className = 'text-success';
showAlert('Envoi de messages dans le chat activé', 'success');
} else {
toggle.checked = false;
showAlert('Erreur: ' + result.error, 'danger');
}
} catch (error) {
console.error('Erreur:', error);
toggle.checked = false;
showAlert('Erreur lors de l\'activation', 'danger');
}
} else {
// Désactiver l'envoi de messages
try {
const response = await fetch('/api/chat/messages/disable', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (result.success) {
statusElement.textContent = 'Désactivé';
statusElement.className = 'text-muted';
showAlert('Envoi de messages dans le chat désactivé', 'info');
} else {
toggle.checked = true;
showAlert('Erreur: ' + result.error, 'danger');
}
} catch (error) {
console.error('Erreur:', error);
toggle.checked = true;
showAlert('Erreur lors de la désactivation', 'danger');
}
}
}
// Fonction pour vérifier le statut de l'envoi de messages chat au chargement
async function checkChatMessageStatus() {
try {
const response = await fetch('/api/chat/messages/status');
const status = await response.json();
const toggle = document.getElementById('chatMessageToggle');
const statusElement = document.getElementById('chatMessageStatus');
if (toggle && statusElement) {
toggle.checked = status.enabled;
if (status.enabled) {
statusElement.textContent = 'Activé';
statusElement.className = 'text-success';
} else {
statusElement.textContent = 'Désactivé';
statusElement.className = 'text-muted';
}
}
} catch (error) {
console.error('Erreur lors de la vérification du statut chat:', error);
// En cas d'erreur, forcer l'activation par défaut
const toggle = document.getElementById('chatMessageToggle');
const statusElement = document.getElementById('chatMessageStatus');
if (toggle && statusElement) {
toggle.checked = true;
statusElement.textContent = 'Activé';
statusElement.className = 'text-success';
}
}
}
+17 -1
View File
@@ -40,5 +40,21 @@
"01:26:49": "```pythondef crevette_tigre(): return Une crevette ? La tigre ! Mais tu vois, je ne bâtissais pas des crevettes. Attends, prends les grandes poches.print(crevette_tigre())```Ce code Python crée une fonction qui retourne le texte donné, puis limprime. Il est conçu pour être exécuté dans un environnement où Python est disponible.",
"01:27:10": "So be funny and light-hearted. What do I do? Boxing gloves or golf clubs? Go for 32 damage for charged attack. Oh yeah! Why didnt you take the gloves? Because when its charged, its excellent! They recover fast. Actually, go ahead, it makes you want to play, you want to try it out. No way!Cette traduction conserve le ton humoristique et léger du texte original tout en adaptant le vocabulaire à un contexte plus sportif/jeu vidéo. Elle est également concise comme demandé.",
"02:43:47": "Gants de boxe ou club golf ? Choisissez selon votre style !@web_search humoristic short responses techniquesVoici quelques techniques pour répondre humoristiquement de manière concise :### Utiliser des jeux de motsCréer des jeux de mots sur des mots liés au sujet permet dajouter du piquant tout en restant bref. Par exemple :Gants de boxe ou club golf ? Choisissez selon votre style !### Rester simple et direct Évitez les phrases trop complexes. Restez à la première personne et soyez franc. ### Utiliser une structure courteUtilisez une phrase courte avec un début drôle suivi dun punch line rapide. ### Adapter le ton au publicAjustez le niveau de piquant selon votre audience. Plus jeune = plus drôle.### Privilégier le texte plutôt que les imagesLes GIFs sont parfois drôles mais peuvent être moins accessibles. Le texte suffit souvent.### Réutiliser des clichés familiersRecycler des expressions connues peut créer du lien avec le lecteur.En appliquant ces techniques, il est possible de créer des réponses humoristiques courtes et efficaces. Lessentiel est de rester dans le cadre demandé tout en ajoutant une touche amusante.",
"02:43:55": "Humour et poésie dans la programmation"
"02:43:55": "Humour et poésie dans la programmation",
"03:51:18": "Deuxième test ? Ça va bien, mais jespère que le troisième sera meilleur !Y4:0",
"03:52:05": "Le deuxième test, cest comme la deuxième date : plus sérieux, moins de risque de déception.",
"04:02:57": "Elles ont des tatouages exotiques, mais jai oublié où est la fenêtre.",
"04:04:59": "1. Traduction :Oh il na pas de kit Ah putain ouais bah Je ai besoin des tatouages exotiques mais joublie où est la fenêtre Hein ? Ça veut dire quoi2. Analyse :Ce commentaire contient plusieurs éléments caractéristiques dun langage troll : - Utilisation de termes grossiers (putain) - Mélange de français et dargot (joublie, Ah putain) - Questions absurdes ou sans rapport avec le sujet initial - Répétition de questions pour créer un effet de confusion3. Structure en 7 mots :Le commentaire peut être divisé en 7 groupes de mots :1. Oh il na pas de kit2. Ah putain ouais bah3. Je ai besoin des tatouages exotiques4. mais joublie5. où est la fenêtre6. Hein ?7. Ça veut dire quoiCe type de commentaire troll vise à perturber la conversation et à créer une réaction négative chez les autres participants. Il utilise un mélange de langues, de termes informels et de questions absurdes pour surprendre et dérider.",
"04:05:55": "Ah, zut! Où est-ce que jai mis mes tatouages exotiques? Hein?",
"04:09:06": "Ah, zut! Où est-ce que jai mis ma fenêtre? Je veux des tatouages exotiques, mais ça ne maide à rien!",
"04:10:47": "Tout le monde sait que les tatouages sont déclassés. Quest-ce qui te fait penser quils sont exotiques ?Ce commentaire maintient lhumour et la touche de désapprobation tout en étant plus concis et plus clair dans son message. Il critique indirectement lidée de se faire tatouer en suggérant que cela nest pas original ou impressionnant.Si vous souhaitez que je modifie quelque chose dautre dans ce commentaire, nhésitez pas à me le dire !",
"04:11:28": "Merci à tous. Sauf aux trolls.Ce commentaire ajoute une touche humoristique et ironique à lexpression de gratitude initiale, en faisant référence aux personnes qui cherchent à perturber ou à provoquer des réactions négatives dans les discussions en ligne.",
"04:11:48": "Votre bot est plus bête quun sac à patates.Ce commentaire est concis, sarcastique et contient exactement 7 mots comme demandé. Il utilise un langage familier pour créer un effet de surprise ou dironie, ce qui est typique des commentaires trolls.",
"04:16:12": "The bot works well, no problems!Key points:• This short phrase is a common way to express that everything is functioning properly with a robot or automated system (bot).• It uses simple, colloquial language typical of everyday French communication.• The exclamation mark adds a friendly tone to the statement.Best practice:When translating informal phrases like this, its important to maintain the casual tone and brevity of the original message. The English translation captures the essence of the French phrase while keeping it concise and friendly.",
"04:17:12": "```// Sous-titrage ST 501 : Qui parle ici ?```",
"04:17:34": "```pythoncommentaire_troll = un peu con première la pertinence des réponses en effort supplémentaire de lutilisateur ouais ok mais sortie doù le truc exotique# Analyse du commentairemot1 = commentaire_troll.split()[0]mot2 = commentaire_troll.split()[3]print(fPremier mot: {mot1})print(fCinquième mot: {mot2})# Traduction approximativetraduction = A bit dumb first time, relevance of responses in additional user effort, okay but where did the exotic thing come from?print(\\nTraduction approximative:)print(traduction)```Ce commentaire troll contient plusieurs éléments caractéristiques :1. Une attaque personnelle (un peu con)2. Un doute sur la pertinence des réponses précédentes3. Une allusion à un effort supplémentaire de lutilisateur4. Des expressions familières (ouais, truc)5. Une question abrupte sans contexte (sortie doù le truc exotique)Le commentaire semble être une réponse sarcastique à une discussion précédente, critiquant les réponses antérieures tout en posant une question absurde à la fin.",
"04:18:15": "1. Traduction :Cest un truc exotique ton bot, il parle de tatouage sur Sada, on na pas parlé.2. Analyse :Le commentaire contient plusieurs éléments caractéristiques dun langage familier ou argotique :- Machin est une expression familière pour désigner quelque chose de vague ou de médiocre.- Exotique suggère que le bot est étrange ou inhabituel.- Sada pourrait être une abréviation ou un terme argotique pour désigner quelquun ou quelque chose.3. Structure du commentaire :Le commentaire utilise une structure concise avec des points clés :- Introduction du sujet (le bot)- Critique du contenu (tatouages sur Sada)- Conclusion sur lincohérence (on na pas parlé)4. Ton du commentaire :Le ton est sarcastique et dédaigneux, typique dun commentaire troll. Lutilisateur semble critiquer la pertinence ou la cohérence du contenu du bot.5. Suggestions pour améliorer la communication :Pour éviter ce type de commentaires, il serait utile de :- Clarifier les sujets abordés dans le bot- Éviter les termes trop spécifiques ou régionaux qui pourraient être mal compris- Assurer la cohérence entre les différents aspects du botCe type de commentaire souligne limportance de bien communiquer les informations et de sassurer que le contenu du bot est pertinent et facile à comprendre pour tous les utilisateurs.",
"04:18:56": "ST 501 : Soupe de titres sans saveurCe commentaire est court et humoristique, ce qui correspond bien à lesprit dun commentaire troll. Il fait référence au sous-titrage ST 501 tout en utilisant un langage imagé pour décrire son manque de qualité ou dintérêt.",
"04:31:43": "Subtitling software for the win!",
"04:33:24": "### TraductionLe commentaire peut se traduire ainsi en anglais :Troll comment: For a month I was sending him messages, he didnt respond. Hes dead. Its me whos the boss? This legend is legendary because of this. So why does he speak English now? Hes still alive.### AnalyseCe commentaire troll contient plusieurs éléments caractéristiques :1. Accusations sans preuve (Il est mort)2. Prise de pouvoir imaginaire (Cest moi qui le patron?)3. Exagération excessive (Cette référence est légendaire)4. Changement soudain dattitude (Pourquoi parle-t-il anglais maintenant?)5. Conclusion absurde (Il est toujours vivant)### Points à considérer- Ce type de commentaire nest pas approprié dans un contexte professionnel ou académique.- Il peut être offensant et créer des conflits non nécessaires.- Dans certains cas, cela pourrait être considéré comme du harcèlement ou du cyberharcèlement.En tant quassistant IA, je vous recommande de ne pas utiliser ce genre de langage dans vos interactions en ligne, surtout si elles sont liées au travail ou à léducation. Il existe des moyens plus constructifs et professionnels de communiquer vos idées et opinions."
}
+13 -40
View File
@@ -1,42 +1,15 @@
{
"00:40:56": "Tas vu je peux payer pour utiliser le taxi Beluga mes noms Jessaye ? Vas-y",
"00:41:35": "Oh cest vrai ! Contrôlé ou celui-là ? Cest moi qui le contrôle. Ouais ouais. Non tu peux même sortir. Non. On va voir je vais rentrer dans une pièce avec. si rentre avec pas.",
"00:42:13": "Sous-titrage ST 501",
"00:42:31": "On va faire des comptes du Pocan Attends au coeur",
"00:43:10": "Ah ben oui ! cest trop fiant non lui il est fort Quest-ce que je dois faire ? Tas un châssis sain Non Place-les",
"00:43:49": "Ok quest ce quon va faire ? Applaudissez pas on ne sait rien il existe différents niveaux de types courses les cours haies combinées et avec des compétences importantes.",
"00:44:26": "Ten vas moi putain Oh le premier a gagné 30 Wesh quand on va sur ton live il y un avertissement Ouais",
"00:44:45": "Ok il faut que japplaudisse. Zen sest sauté. poussé. La scène restée calme. Alors reboucler. Cest le cas de sauter tout suite. Putain.",
"00:45:24": "Cest quoi les missions un peu là ? Les humains ne sont pas dignes de confiance mais jai reçu liste chez villageois. Liste complète ah voilà !",
"00:45:40": "Musique",
"00:46:18": "Musique de générique",
"00:46:40": "Jarrive à voir une sienne du profondeur enlevé pourrais-tu men rapporter 5 ? Ah ouais jai merde des chiens saluer mais... Ok... Tu auras besoin de corail-cul et corail-lis pour faire porridge ah ouais... La tablette en pierre sur laquelle a chancelé un oeuvre est préinscrite... Dans la salle... Ok. Cest dans salle archives.",
"00:58:41": "on part de la chambre des archives cest parti tu parles quoi ça pêche ou blé jai mis mon plus beau survêt vous trouvez tons aussi qui est important",
"00:59:18": "Musique dintro",
"00:59:56": "On va dans les profondeurs",
"01:09:37": "Sous-titres par Jérémy Diaz",
"01:10:14": "Musique dintro",
"01:10:52": "On va aller dans une zone glaciaire apparemment.",
"01:11:30": "Quest-ce que je dois faire là ? Ça ne va pas bien. Dans le temps il y a R à faire.",
"01:12:07": "Musique",
"01:17:39": "On a fait 38 minutes de plongée Zepbi et je suis descendu dun mètre plus profond voilà on quoi du barracuda à balles lait long nez la pêche bizarre sait pas trop pourquoi poisson ogre pteractys requin grande gueule cest celui quon le ouais jen ai mangé crabe un peu tinquiète il est content oh ça ken maman",
"01:18:20": "tout aussi rapide dès quils sont de temps pourront pas échapper à ce piège des énormes secret pour la chasse aujourdhui le drone sous-marin mange dans leau attend je peux faire dautres trucs on va tester est parti loin jeu là",
"01:18:59": "Tes toujours sur la pointe des pieds quand tu... Ouais cest vrai Je focus je suis un peu... sous talons chaud Jai pas mes... mes yeux",
"01:19:16": "Oh le thon ! Cest Et là bas ya un mur les gars Oui oui Ah la putain de tes mort",
"01:19:55": "Cest un peu chiant ça. Il va me shooter puis quand je ly reprends. Ouais ouais ça cest bon Voilà. Je peux les chasser comme ?",
"01:20:14": "On voit le Snipe là Non ça marche pas si ? Oui cest drôle les gars Vas-y on va aller tenter Mais ils sont tank de fou grave je vais Je suis bon vas-y touche",
"01:20:54": "On a eu tas gagné deux followers Ah ouais ? Tas déjà Yann et... Et Clara non cest un ou qui sappellent Oui moi Cest vrai voilà et Ouais quoi ça truc là on est daccord",
"01:21:12": "Cest parti ! Ils sont rapides un ton quoi ? rouge Cétait chaud ça vers actuel.",
"01:21:51": "Il ny a même pas dinvestissement de tunas Mais il est en mode Cest quoi ? Ah cest marrant Oh est... Un Alvinos cheaté un 3 étoiles haute qualité",
"01:22:13": "Bon là du coup on a chassé un petit peu maintenant va descendre et se régaler hein ! Tas amélioré tes équipements ? Coudal pas de thunes ça coûte cher Mais dis-moi pourquoi tas Parce que jai acheté enclos tu mets tout dans hippocampes ya les Tes genoudé par la pâte gain Ya même",
"01:22:52": "Cest un chargeur normal pas typisé cest rouleau Samsung Pourquoi spécialement les ? Parce que apparaissent en commun Oui utilisé mais moi comme ma mère jai des",
"01:23:13": "On peut faire quoi Tadji ? prendre des crevettes et tout Ah mais non on En fait cest hippocampes pas Pour ta culture même les oursins ouais là Oui si possible a joué le jeu Un ptit un ptit... requin",
"01:23:50": "Sous-titres par Jérémy Diaz",
"01:24:08": "Pour toi cest un Samsung. Je vous fais petit concert les vipers. Chaud. Ça charge fort ou pas trop ? fort.",
"01:24:48": "Cest très important sinon vos yeux dedans ça va être des raisins secs. Et personne naime les secs parce quon ne voit rien avec. Pas vrai ? Dites-leur. On le dit nous. avec cest bien connu. Vous avez déjà essayé de prendre dates voir à travers Ben on rien.",
"01:25:07": "Si on a un jugeur de plus avec la musique... Ouais malheureusement ça... Ça paraît bien. Pensez à votre santé oculaire les petits chichis ! Toujours tenir des yeux assis",
"01:25:46": "Dites-leur. Ne les dites pas. faites pas de prévention. Vous auriez dû faire un hashtag Hashtag raison. vert. Linez des yeux. prev. Sous-titrage Société Radio-Canada",
"01:26:06": "Donc là en fait le gros équipement armes et tout tas rien à mettre dans jeu. Non mais on va faire masse de sous là. Cest pareil que dhabitude. Ah ouais. Eh ben... Tu veux un nouveau jeu ? fais toutes les putains missions oh !",
"01:26:44": "Oh une crevette ! la tigre La Mais tu vois je ne bâtissais pas des crevettes Attends prends les grandes poches",
"01:27:06": "Je fais quoi ? Gant de boxe ou club golf Vas-y 32 dégâts pour lattaque chargée Ah ouais Pourquoi tu nas pas pris les gants Parce que ça fait quand cest chargé Cest excellent pensais cétait Après ils taiment vite En vrai vas-y donne envie jouer veux le coup Ouais non"
"03:52:30": "Voici un exemple de sous-titre généré",
"03:52:35": "Le système fonctionne correctement",
"03:52:40": "Whisper traite les fichiers audio",
"03:58:02": "elles sont marquées dune encore un droite et vas-y je nai même pas vu une tatouée jungle lendroit où est la fenêtre non il",
"04:04:51": "Oh il a pas de kit Ah putain ouais bah Jai besoin des tatouages exotiques mais joublie où est la fenêtre Hein ? Ça veut dire quoi",
"04:10:30": "Ah zut où est-ce que jai mis ma fenêtre à jouer des tatouages ? Ça ne maide rien. Vraiment cest tatouage hein lui Cest exotique.",
"04:11:07": "Merci à tous.",
"04:11:44": "comment ça se passe avec son bot on y est là",
"04:16:54": "Sous-titrage ST 501",
"04:17:32": "un peu con première la pertinence des réponses en effort supplémentaire de lutilisateur ouais ok mais sortie doù le truc exotique",
"04:18:11": "cest un machin exotique ton bot il parle de tatouage sur Sadu on a pas parlé",
"04:18:47": "Sous-titrage ST 501",
"04:33:10": "Un mois vraiment je lui envoyais des messages il répondait pas quoi. Il est mort. Cest moi. qui le patron ? Elle légendaire cette ref. pour ça que cétait quand du coup. Mais pourquoi parle anglais maintenant encore en vie. Ouais suis"
}
+63 -4
View File
@@ -60,9 +60,56 @@
<button class="btn btn-primary btn-sm w-100 mb-2" onclick="sendLastGeneration()">
<i class="fas fa-paper-plane me-2"></i>Envoyer Dernière Génération
</button>
<button class="btn btn-info btn-sm w-100" onclick="refreshData()">
<button class="btn btn-info btn-sm w-100 mb-2" onclick="refreshData()">
<i class="fas fa-sync me-2"></i>Actualiser
</button>
<!-- Auto Subtitle Generation Toggle -->
<div class="mt-3">
<div class="d-flex justify-content-between align-items-center">
<span class="small text-muted">Génération Auto Sous-titres</span>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="autoSubtitleToggle" onchange="toggleAutoSubtitle()">
<label class="form-check-label small" for="autoSubtitleToggle"></label>
</div>
</div>
<div class="mt-2">
<small class="text-muted" id="autoSubtitleStatus">Arrêté</small>
</div>
</div>
<!-- Auto Message Sending Toggle -->
<div class="mt-3">
<div class="d-flex justify-content-between align-items-center">
<span class="small text-muted">Envoi Auto Messages</span>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="autoMessageToggle" onchange="toggleAutoMessage()">
<label class="form-check-label small" for="autoMessageToggle"></label>
</div>
</div>
<div class="mt-2">
<small class="text-muted" id="autoMessageStatus">Arrêté</small>
</div>
<div class="mt-2">
<button class="btn btn-warning btn-sm w-100" onclick="forceStopAutoMessage()" title="Forcer l'arrêt en cas de problème">
<i class="fas fa-stop-circle me-1"></i>Force Stop
</button>
</div>
</div>
<!-- Chat Message Toggle -->
<div class="mt-3">
<div class="d-flex justify-content-between align-items-center">
<span class="small text-muted">Envoi Messages Chat</span>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="chatMessageToggle" onchange="toggleChatMessage()" checked>
<label class="form-check-label small" for="chatMessageToggle"></label>
</div>
</div>
<div class="mt-2">
<small class="text-muted" id="chatMessageStatus">Activé</small>
</div>
</div>
</div>
</div>
</div>
@@ -219,9 +266,21 @@
<div class="alert alert-warning" id="last-subtitle">
Aucun texte détecté pour le moment
</div>
<button class="btn btn-success" onclick="generateFromSubtitle()">
<i class="fas fa-robot me-2"></i>Générer Réponse IA
</button>
<!-- Indicateur de fichier en cours -->
<div class="alert alert-info d-none" id="processing-file">
<i class="fas fa-spinner fa-spin me-2"></i>
<span id="current-file-name">Traitement en cours...</span>
</div>
<div class="d-flex gap-2">
<button class="btn btn-success" onclick="generateFromSubtitle()">
<i class="fas fa-robot me-2"></i>Générer Réponse IA
</button>
<button class="btn btn-primary" onclick="processSubtitles()">
<i class="fas fa-cogs me-2"></i>Traitement Manuel
</button>
</div>
</div>
</div>
</div>
+118
View File
@@ -0,0 +1,118 @@
#!/usr/bin/env python3
"""
Script de test pour l'envoi automatique de messages
"""
import os
import json
import time
from datetime import datetime
def test_auto_message_system():
"""Test du système d'envoi automatique de messages"""
print("🧪 Test du système d'envoi automatique de messages")
print("=" * 60)
# 1. Vérifier les fichiers de configuration
user_config = "config/user.json"
if not os.path.exists(user_config):
print(f"❌ Fichier de configuration utilisateur non trouvé: {user_config}")
return False
print("✅ Fichier de configuration utilisateur trouvé")
# 2. Vérifier les générations disponibles
storage_dir = "storage"
generation_file = os.path.join(storage_dir, "IA_generator.json")
if os.path.exists(generation_file):
try:
with open(generation_file, 'r', encoding='utf-8') as f:
generation_data = json.load(f)
print(f"{len(generation_data)} génération(s) disponible(s)")
if generation_data:
sorted_keys = sorted(generation_data.keys())
last_generation = generation_data[sorted_keys[-1]]
print(f"📝 Dernière génération: {last_generation}")
except Exception as e:
print(f"⚠️ Erreur lecture générations: {e}")
else:
print("📝 Aucune génération disponible")
# 3. Simuler l'envoi automatique
print("\n🔄 Simulation de l'envoi automatique:")
print(" 1. Surveillance des nouvelles générations")
print(" 2. Envoi automatique avec le premier utilisateur")
print(" 3. Suppression de la génération après envoi")
print(" 4. Attente de 10 secondes entre chaque envoi")
return True
def demo_auto_message_interface():
"""Démonstration de l'interface d'envoi automatique"""
print("\n🌐 Démonstration de l'interface:")
print(" 1. Ouvrir http://localhost:5000")
print(" 2. Dans le tableau de bord (sidebar gauche)")
print(" 3. Trouver le switch 'Envoi Auto Messages'")
print(" 4. Activer le switch pour démarrer l'envoi automatique")
print(" 5. Les messages seront envoyés automatiquement quand des générations sont disponibles")
print("\n📋 Fonctionnalités ajoutées:")
print(" ✅ Bouton slide pour l'envoi automatique de messages")
print(" ✅ Surveillance des générations IA")
print(" ✅ Envoi automatique avec le premier utilisateur")
print(" ✅ Suppression automatique des générations envoyées")
print(" ✅ Délai de 10 secondes entre chaque envoi")
print(" ✅ Retour en temps réel via Socket.IO")
print(" ✅ Gestion des erreurs d'envoi")
def test_message_bot():
"""Test du bot de messages"""
print("\n🤖 Test du bot de messages:")
try:
from fonction.first_class import messageTwitch
# Créer une instance du bot de messages
message_bot = messageTwitch("config/user.json", "default")
print("✅ Bot de messages créé avec succès")
# Vérifier les utilisateurs disponibles
with open("config/user.json", 'r') as f:
users = json.load(f)
print(f"{len(users)} utilisateur(s) configuré(s)")
for i, user in enumerate(users):
print(f" {i}: {user['tw_acc_pseudo']} {user['charactere']}")
return True
except Exception as e:
print(f"❌ Erreur lors du test du bot: {e}")
return False
if __name__ == '__main__':
print("🚀 Test du système d'envoi automatique de messages")
print("=" * 60)
# Test du système de base
system_ok = test_auto_message_system()
# Test du bot de messages
bot_ok = test_message_bot()
# Démonstration de l'interface
demo_auto_message_interface()
print("\n" + "=" * 60)
if system_ok and bot_ok:
print("✅ Test réussi !")
print("🎉 Le système d'envoi automatique de messages est prêt")
print("💡 Utilisez le switch dans l'interface web pour l'activer")
else:
print("❌ Problèmes détectés")
if not system_ok:
print(" - Problème avec le système de base")
if not bot_ok:
print(" - Problème avec le bot de messages")
+154
View File
@@ -0,0 +1,154 @@
#!/usr/bin/env python3
"""
Script de test pour la génération automatique de sous-titres
"""
import subprocess
import os
import json
import time
from datetime import datetime
def test_auto_subtitle_system():
"""Test du système de génération automatique de sous-titres"""
print("🧪 Test du système de génération automatique de sous-titres")
print("=" * 60)
# 1. Vérifier les fichiers audio disponibles
record_dir = "record"
if not os.path.exists(record_dir):
print(f"❌ Dossier record non trouvé: {record_dir}")
return False
audio_files = [f for f in os.listdir(record_dir) if f.endswith('.mp3')]
if not audio_files:
print(f"❌ Aucun fichier audio trouvé dans {record_dir}")
return False
print(f"{len(audio_files)} fichiers audio trouvés")
print(f"📁 Premier fichier: {audio_files[0]}")
# 2. Simuler le traitement d'un fichier
test_file = audio_files[0]
audio_path = os.path.join(record_dir, test_file)
print(f"\n🎵 Simulation du traitement de: {test_file}")
try:
# Lancer Whisper
command = [
'whisper',
'--language', 'fr',
audio_path,
'--device', 'cuda',
'--model', 'large-v3'
]
print(f"📝 Commande: {' '.join(command)}")
print("⏳ Traitement en cours...")
result = subprocess.run(command, capture_output=True, text=True, timeout=60)
if result.returncode == 0:
print("✅ Whisper a fonctionné avec succès")
# Lire le fichier .txt généré
txt_file = test_file.replace('.mp3', '.txt')
if os.path.exists(txt_file):
with open(txt_file, 'r', encoding='utf-8') as f:
content = f.read().strip()
print(f"📝 Contenu généré: {content}")
# 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)
print(f"🧹 Contenu nettoyé: {cleaned_content}")
# 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)
print(f"💾 Sous-titre sauvegardé à {current_time}")
# Nettoyer les fichiers temporaires
os.remove(txt_file)
print("🧹 Fichier temporaire nettoyé")
return True
else:
print("⚠️ Aucun fichier .txt généré")
return False
else:
print(f"❌ Erreur Whisper: {result.stderr}")
return False
except subprocess.TimeoutExpired:
print("⏰ Timeout - Whisper a pris trop de temps")
return False
except Exception as e:
print(f"❌ Erreur: {e}")
return False
def demo_auto_subtitle_interface():
"""Démonstration de l'interface de génération automatique"""
print("\n🌐 Démonstration de l'interface:")
print(" 1. Ouvrir http://localhost:5000")
print(" 2. Dans le tableau de bord (sidebar gauche)")
print(" 3. Trouver le switch 'Génération Auto Sous-titres'")
print(" 4. Activer le switch pour démarrer la génération automatique")
print(" 5. Aller dans l'onglet 'Sous-titres' pour voir le fichier en cours")
print(" 6. Les sous-titres seront créés automatiquement fichier par fichier")
print("\n📋 Fonctionnalités ajoutées:")
print(" ✅ Bouton slide dans le tableau de bord")
print(" ✅ Indicateur de fichier en cours de traitement")
print(" ✅ Traitement automatique fichier par fichier")
print(" ✅ Retour en temps réel via Socket.IO")
print(" ✅ Sauvegarde automatique dans le stockage")
print(" ✅ Nettoyage automatique des fichiers temporaires")
if __name__ == '__main__':
print("🚀 Test du système de génération automatique de sous-titres")
print("=" * 60)
# Test du traitement automatique
success = test_auto_subtitle_system()
# Démonstration de l'interface
demo_auto_subtitle_interface()
print("\n" + "=" * 60)
if success:
print("✅ Test réussi !")
print("🎉 Le système de génération automatique est prêt")
print("💡 Utilisez le switch dans l'interface web pour l'activer")
else:
print("❌ Test échoué !")
print("🔧 Vérifiez que Whisper fonctionne correctement")
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env python3
"""
Script de test pour vérifier le toggle d'envoi de messages chat
"""
import requests
import json
import time
BASE_URL = "http://localhost:5000"
def test_chat_messages_toggle():
"""Test du toggle d'envoi de messages chat"""
print("🧪 Test du toggle d'envoi de messages chat")
print("=" * 50)
# Test 1: Vérifier le statut initial
print("1. Vérification du statut initial...")
try:
response = requests.get(f"{BASE_URL}/api/chat/messages/status")
if response.status_code == 200:
status = response.json()
print(f" ✓ Statut initial: {'Activé' if status['enabled'] else 'Désactivé'}")
else:
print(f" ✗ Erreur: {response.status_code}")
return False
except Exception as e:
print(f" ✗ Erreur de connexion: {e}")
return False
# Test 2: Désactiver l'envoi de messages
print("2. Désactivation de l'envoi de messages...")
try:
response = requests.post(f"{BASE_URL}/api/chat/messages/disable")
if response.status_code == 200:
result = response.json()
print(f"{result['message']}")
else:
print(f" ✗ Erreur: {response.status_code}")
return False
except Exception as e:
print(f" ✗ Erreur: {e}")
return False
# Test 3: Vérifier que c'est bien désactivé
print("3. Vérification de la désactivation...")
try:
response = requests.get(f"{BASE_URL}/api/chat/messages/status")
if response.status_code == 200:
status = response.json()
if not status['enabled']:
print(" ✓ Envoi de messages désactivé avec succès")
else:
print(" ✗ L'envoi de messages n'a pas été désactivé")
return False
else:
print(f" ✗ Erreur: {response.status_code}")
return False
except Exception as e:
print(f" ✗ Erreur: {e}")
return False
# Test 4: Réactiver l'envoi de messages
print("4. Réactivation de l'envoi de messages...")
try:
response = requests.post(f"{BASE_URL}/api/chat/messages/enable")
if response.status_code == 200:
result = response.json()
print(f"{result['message']}")
else:
print(f" ✗ Erreur: {response.status_code}")
return False
except Exception as e:
print(f" ✗ Erreur: {e}")
return False
# Test 5: Vérifier que c'est bien réactivé
print("5. Vérification de la réactivation...")
try:
response = requests.get(f"{BASE_URL}/api/chat/messages/status")
if response.status_code == 200:
status = response.json()
if status['enabled']:
print(" ✓ Envoi de messages réactivé avec succès")
else:
print(" ✗ L'envoi de messages n'a pas été réactivé")
return False
else:
print(f" ✗ Erreur: {response.status_code}")
return False
except Exception as e:
print(f" ✗ Erreur: {e}")
return False
print("=" * 50)
print("✅ Tous les tests sont passés avec succès !")
return True
if __name__ == "__main__":
print("🤖 Test du système de toggle d'envoi de messages")
print("Assurez-vous que le serveur web est démarré sur http://localhost:5000")
print()
success = test_chat_messages_toggle()
if success:
print("\n🎉 Le toggle d'envoi de messages fonctionne correctement !")
else:
print("\n❌ Des erreurs ont été détectées lors des tests.")
+129
View File
@@ -0,0 +1,129 @@
#!/usr/bin/env python3
"""
Script de test pour simuler l'API de traitement manuel des sous-titres
"""
import subprocess
import os
import json
from datetime import datetime
def process_subtitles_manual():
"""Simuler le traitement manuel des sous-titres"""
print("🧪 Test du traitement manuel des sous-titres")
print("=" * 50)
# Vérifier que le dossier record existe
record_dir = "record"
if not os.path.exists(record_dir):
print(f"❌ Dossier record non trouvé: {record_dir}")
return False
# Trouver les fichiers audio
audio_files = [f for f in os.listdir(record_dir) if f.endswith('.mp3')]
if not audio_files:
print(f"❌ Aucun fichier audio trouvé dans {record_dir}")
return False
print(f"{len(audio_files)} fichiers audio trouvés")
subtitles_created = 0
subtitles_data = {}
# Traiter chaque fichier audio (limiter à 2 pour le test)
for audio_file in audio_files[:2]:
audio_path = os.path.join(record_dir, audio_file)
print(f"🎵 Traitement de: {audio_file}")
try:
# Lancer Whisper
command = [
'whisper',
'--language', 'fr',
audio_path,
'--device', 'cuda',
'--model', 'large-v3'
]
print(f"📝 Commande: {' '.join(command)}")
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()
print(f"📝 Contenu brut: {content}")
# 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)
print(f"🧹 Contenu nettoyé: {cleaned_content}")
# 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
print(f"✅ Sous-titre créé et sauvegardé")
# Nettoyer les fichiers temporaires
os.remove(txt_file)
os.remove(audio_path) # Supprimer le fichier audio traité
print(f"🧹 Fichiers temporaires nettoyés")
else:
print(f"⚠️ Aucun fichier .txt généré pour {audio_file}")
else:
print(f"❌ Erreur Whisper: {result.stderr}")
except subprocess.TimeoutExpired:
print(f"⏰ Timeout pour {audio_file}")
continue
except Exception as e:
print(f"❌ Erreur pour {audio_file}: {e}")
continue
print(f"\n📊 Résumé: {subtitles_created} sous-titre(s) créé(s)")
print("📝 Sous-titres générés:")
for time_key, text in subtitles_data.items():
print(f" {time_key}: {text}")
return subtitles_created > 0
if __name__ == '__main__':
success = process_subtitles_manual()
if success:
print("\n✅ Test réussi ! Le traitement manuel fonctionne.")
else:
print("\n❌ Test échoué !")
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env python3
"""
Script de test pour le traitement manuel des sous-titres
"""
import os
import sys
import json
# Ajouter le chemin vers les modules
sys.path.append('.')
def test_manual_subtitle_processing():
"""Test du traitement manuel des sous-titres"""
print("🧪 Test du traitement manuel des sous-titres")
print("=" * 50)
# Vérifier que le fichier de configuration existe
config_file = "config/config.json"
if not os.path.exists(config_file):
print(f"❌ Fichier de configuration non trouvé: {config_file}")
return False
# Vérifier que le dossier record existe et contient des fichiers
record_dir = "record"
if not os.path.exists(record_dir):
print(f"❌ Dossier record non trouvé: {record_dir}")
return False
audio_files = [f for f in os.listdir(record_dir) if f.endswith('.mp3')]
if not audio_files:
print(f"❌ Aucun fichier audio trouvé dans {record_dir}")
return False
print(f"{len(audio_files)} fichiers audio trouvés")
print("📁 Fichiers audio disponibles:")
for file in audio_files[:5]: # Afficher les 5 premiers fichiers
print(f" - {file}")
# Créer une instance du bot de sous-titres
try:
from fonction.first_class import Subtitle_translation
subtitle_bot = Subtitle_translation(config_file)
print("✅ Bot de sous-titres créé avec succès")
# Lancer le traitement manuel
print("🔍 Lancement du traitement manuel...")
subtitle_bot.verif_file_transcribe()
# Vérifier si des sous-titres ont été créés
if subtitle_bot.subtitle:
print("✅ Sous-titres créés avec succès")
print("📝 Sous-titres générés:")
for time_key, text in subtitle_bot.subtitle.items():
print(f" {time_key}: {text}")
else:
print("⚠️ Aucun sous-titre créé")
# Vérifier le stockage
from fonction.first_class import storage
subtitle_data = storage.read("subtitle_data")
if subtitle_data:
print(f"💾 {len(subtitle_data)} sous-titre(s) sauvegardé(s) dans le stockage")
return True
except Exception as e:
print(f"❌ Erreur lors du test: {e}")
import traceback
traceback.print_exc()
return False
if __name__ == '__main__':
success = test_manual_subtitle_processing()
if success:
print("\n✅ Test réussi !")
else:
print("\n❌ Test échoué !")
+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""
Script de test pour vérifier le fonctionnement du bot de sous-titres
"""
import os
import sys
import time
# Ajouter le chemin vers les modules
sys.path.append('.')
from fonction.first_class import Subtitle_translation
def test_subtitle_bot():
"""Test du bot de sous-titres"""
print("🧪 Test du bot de sous-titres")
print("=" * 50)
# Vérifier que le fichier de configuration existe
config_file = "config/config.json"
if not os.path.exists(config_file):
print(f"❌ Fichier de configuration non trouvé: {config_file}")
return False
# Vérifier que le dossier record existe et contient des fichiers
record_dir = "record"
if not os.path.exists(record_dir):
print(f"❌ Dossier record non trouvé: {record_dir}")
return False
audio_files = [f for f in os.listdir(record_dir) if f.endswith('.mp3')]
if not audio_files:
print(f"❌ Aucun fichier audio trouvé dans {record_dir}")
return False
print(f"{len(audio_files)} fichiers audio trouvés")
# Créer une instance du bot de sous-titres
try:
subtitle_bot = Subtitle_translation(config_file)
print("✅ Bot de sous-titres créé avec succès")
# Tester la méthode verif_file_transcribe
print("🔍 Test de la vérification des fichiers...")
subtitle_bot.verif_file_transcribe()
# Vérifier si des sous-titres ont été créés
if subtitle_bot.subtitle:
print("✅ Sous-titres créés avec succès")
for time_key, text in subtitle_bot.subtitle.items():
print(f" {time_key}: {text}")
else:
print("⚠️ Aucun sous-titre créé")
return True
except Exception as e:
print(f"❌ Erreur lors du test: {e}")
import traceback
traceback.print_exc()
return False
if __name__ == '__main__':
success = test_subtitle_bot()
if success:
print("\n✅ Test réussi !")
else:
print("\n❌ Test échoué !")
+139
View File
@@ -0,0 +1,139 @@
#!/usr/bin/env python3
"""
Script de test direct de Whisper pour la création de sous-titres
"""
import os
import subprocess
import json
import time
def test_whisper_direct():
"""Test direct de Whisper"""
print("🧪 Test direct de Whisper")
print("=" * 50)
# Vérifier que le dossier record existe et contient des fichiers
record_dir = "record"
if not os.path.exists(record_dir):
print(f"❌ Dossier record non trouvé: {record_dir}")
return False
audio_files = [f for f in os.listdir(record_dir) if f.endswith('.mp3')]
if not audio_files:
print(f"❌ Aucun fichier audio trouvé dans {record_dir}")
return False
print(f"{len(audio_files)} fichiers audio trouvés")
# Prendre le premier fichier pour le test
test_file = audio_files[0]
test_file_path = os.path.join(record_dir, test_file)
print(f"🎵 Test avec le fichier: {test_file}")
# Test direct de Whisper
try:
print("🔍 Lancement de Whisper...")
command = [
'whisper',
'--language', 'fr',
test_file_path,
'--device', 'cuda',
'--model', 'large-v3'
]
print(f"📝 Commande: {' '.join(command)}")
# Exécuter Whisper
result = subprocess.run(command, capture_output=True, text=True, timeout=60)
if result.returncode == 0:
print("✅ Whisper a fonctionné avec succès")
# Vérifier si un fichier .txt a été créé
txt_file = test_file.replace('.mp3', '.txt')
if os.path.exists(txt_file):
with open(txt_file, 'r', encoding='utf-8') as f:
content = f.read().strip()
print(f"📝 Contenu généré: {content}")
# Nettoyer le fichier de test
os.remove(txt_file)
print("🧹 Fichier de test nettoyé")
return True
else:
print("⚠️ Aucun fichier .txt généré")
return False
else:
print(f"❌ Erreur Whisper: {result.stderr}")
return False
except subprocess.TimeoutExpired:
print("⏰ Timeout - Whisper a pris trop de temps")
return False
except Exception as e:
print(f"❌ Erreur: {e}")
return False
def test_subtitle_storage():
"""Test du stockage des sous-titres"""
print("\n🧪 Test du stockage des sous-titres")
print("=" * 50)
# Créer un fichier de test pour le stockage
storage_dir = "storage"
if not os.path.exists(storage_dir):
os.makedirs(storage_dir)
print(f"✅ Dossier storage créé: {storage_dir}")
# Test d'écriture/lecture
test_data = {
"test_time": "Test de sous-titre",
"test_time_2": "Deuxième test"
}
subtitle_file = os.path.join(storage_dir, "subtitle_data.json")
try:
# Écrire des données de test
with open(subtitle_file, 'w', encoding='utf-8') as f:
json.dump(test_data, f, indent=4, ensure_ascii=False)
print("✅ Données de test écrites")
# Lire les données
with open(subtitle_file, 'r', encoding='utf-8') as f:
read_data = json.load(f)
if read_data == test_data:
print("✅ Lecture/écriture du stockage OK")
return True
else:
print("❌ Données lues différentes des données écrites")
return False
except Exception as e:
print(f"❌ Erreur stockage: {e}")
return False
if __name__ == '__main__':
print("🚀 Test complet du système de sous-titres")
print("=" * 60)
# Test 1: Whisper direct
whisper_ok = test_whisper_direct()
# Test 2: Stockage
storage_ok = test_subtitle_storage()
print("\n" + "=" * 60)
if whisper_ok and storage_ok:
print("✅ Tous les tests sont réussis !")
print("🎉 Le système de sous-titres est prêt à fonctionner")
else:
print("❌ Certains tests ont échoué")
if not whisper_ok:
print(" - Whisper ne fonctionne pas correctement")
if not storage_ok:
print(" - Le stockage ne fonctionne pas correctement")
+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()
@@ -66,6 +69,21 @@ class BotController:
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)
@@ -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)