ajout du control denvoi de message et interface up
This commit is contained in:
@@ -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"}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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,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
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -8,5 +8,10 @@
|
|||||||
"tw_acc_pseudo": "SnowLunaSoft",
|
"tw_acc_pseudo": "SnowLunaSoft",
|
||||||
"tw_acc_token": "oauth:l348b8e7g7srjnc8trnxjqe2i2boq2",
|
"tw_acc_token": "oauth:l348b8e7g7srjnc8trnxjqe2i2boq2",
|
||||||
"charactere": "Kappa"
|
"charactere": "Kappa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tw_acc_pseudo": "exoticnaturees",
|
||||||
|
"tw_acc_token": "oauth:ac5r1i8upt5isxdhpxdmf8u1c2lo0u",
|
||||||
|
"charactere": "😊"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
Submodule debug_ia_clone deleted from bb743c5722
@@ -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")
|
||||||
@@ -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")
|
||||||
@@ -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()
|
||||||
@@ -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()
|
||||||
@@ -1007,6 +1007,21 @@ class messageTwitch:
|
|||||||
|
|
||||||
def send_message(self, Message_text):
|
def send_message(self, Message_text):
|
||||||
try:
|
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+'"'
|
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
|
# 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.
@@ -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
File diff suppressed because it is too large
Load Diff
+437
-1
@@ -63,7 +63,10 @@ async function loadInitialData() {
|
|||||||
loadUsers(),
|
loadUsers(),
|
||||||
loadStatus(),
|
loadStatus(),
|
||||||
loadSubtitles(),
|
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) {
|
} catch (error) {
|
||||||
console.error('Erreur lors du chargement des données:', 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 ===
|
// === GESTION DES GÉNÉRATIONS ===
|
||||||
|
|
||||||
// Chargement 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
|
// Gestion des erreurs globales
|
||||||
window.addEventListener('error', function(e) {
|
window.addEventListener('error', function(e) {
|
||||||
console.error('Erreur JavaScript:', e.error);
|
console.error('Erreur JavaScript:', e.error);
|
||||||
@@ -1202,3 +1261,380 @@ async function deleteUser(userId) {
|
|||||||
showToast('Erreur lors de la suppression', 'error');
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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: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é.",
|
"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: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
@@ -1,42 +1,15 @@
|
|||||||
{
|
{
|
||||||
"00:40:56": "Tas vu je peux payer pour utiliser le taxi Beluga mes noms Jessaye ? Vas-y",
|
"03:52:30": "Voici un exemple de sous-titre généré",
|
||||||
"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.",
|
"03:52:35": "Le système fonctionne correctement",
|
||||||
"00:42:13": "Sous-titrage ST 501",
|
"03:52:40": "Whisper traite les fichiers audio",
|
||||||
"00:42:31": "On va faire des comptes du Pocan Attends au coeur",
|
"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",
|
||||||
"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",
|
"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",
|
||||||
"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.",
|
"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.",
|
||||||
"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",
|
"04:11:07": "Merci à tous.",
|
||||||
"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.",
|
"04:11:44": "comment ça se passe avec son bot on y est là",
|
||||||
"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à !",
|
"04:16:54": "Sous-titrage ST 501",
|
||||||
"00:45:40": "Musique",
|
"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",
|
||||||
"00:46:18": "Musique de générique",
|
"04:18:11": "cest un machin exotique ton bot il parle de tatouage sur Sadu on a pas parlé",
|
||||||
"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.",
|
"04:18:47": "Sous-titrage ST 501",
|
||||||
"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",
|
"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"
|
||||||
"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"
|
|
||||||
}
|
}
|
||||||
+60
-1
@@ -60,9 +60,56 @@
|
|||||||
<button class="btn btn-primary btn-sm w-100 mb-2" onclick="sendLastGeneration()">
|
<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
|
<i class="fas fa-paper-plane me-2"></i>Envoyer Dernière Génération
|
||||||
</button>
|
</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
|
<i class="fas fa-sync me-2"></i>Actualiser
|
||||||
</button>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -219,9 +266,21 @@
|
|||||||
<div class="alert alert-warning" id="last-subtitle">
|
<div class="alert alert-warning" id="last-subtitle">
|
||||||
Aucun texte détecté pour le moment
|
Aucun texte détecté pour le moment
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 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()">
|
<button class="btn btn-success" onclick="generateFromSubtitle()">
|
||||||
<i class="fas fa-robot me-2"></i>Générer Réponse IA
|
<i class="fas fa-robot me-2"></i>Générer Réponse IA
|
||||||
</button>
|
</button>
|
||||||
|
<button class="btn btn-primary" onclick="processSubtitles()">
|
||||||
|
<i class="fas fa-cogs me-2"></i>Traitement Manuel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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")
|
||||||
@@ -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")
|
||||||
@@ -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.")
|
||||||
@@ -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é !")
|
||||||
@@ -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é !")
|
||||||
@@ -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é !")
|
||||||
@@ -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
@@ -56,7 +56,10 @@ class BotController:
|
|||||||
chat_bot = TwitchChatBot(channel_name)
|
chat_bot = TwitchChatBot(channel_name)
|
||||||
self.bots[flux_id] = {
|
self.bots[flux_id] = {
|
||||||
'chat_bot': chat_bot,
|
'chat_bot': chat_bot,
|
||||||
'record_bot': None
|
'record_bot': None,
|
||||||
|
'subtitle_bot': None,
|
||||||
|
'ia_bot': None,
|
||||||
|
'message_bot': None
|
||||||
}
|
}
|
||||||
chat_bot.start_background()
|
chat_bot.start_background()
|
||||||
|
|
||||||
@@ -66,6 +69,21 @@ class BotController:
|
|||||||
self.bots[flux_id]['record_bot'] = record_bot
|
self.bots[flux_id]['record_bot'] = record_bot
|
||||||
threading.Thread(target=record_bot.main, daemon=True).start()
|
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
|
# Mettre à jour le statut
|
||||||
flux_data['status'] = 'active'
|
flux_data['status'] = 'active'
|
||||||
self.flux_list.append(flux_data)
|
self.flux_list.append(flux_data)
|
||||||
@@ -80,6 +98,12 @@ class BotController:
|
|||||||
self.bots[flux_id]['chat_bot'].stop()
|
self.bots[flux_id]['chat_bot'].stop()
|
||||||
if self.bots[flux_id]['record_bot']:
|
if self.bots[flux_id]['record_bot']:
|
||||||
self.bots[flux_id]['record_bot'].stop()
|
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:
|
except:
|
||||||
pass
|
pass
|
||||||
del self.bots[flux_id]
|
del self.bots[flux_id]
|
||||||
@@ -98,6 +122,12 @@ class BotController:
|
|||||||
self.bots[flux_id]['chat_bot'].stop()
|
self.bots[flux_id]['chat_bot'].stop()
|
||||||
if self.bots[flux_id]['record_bot']:
|
if self.bots[flux_id]['record_bot']:
|
||||||
self.bots[flux_id]['record_bot'].stop()
|
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:
|
except Exception as e:
|
||||||
print(f"Erreur lors de l'arrêt des bots: {e}")
|
print(f"Erreur lors de l'arrêt des bots: {e}")
|
||||||
del self.bots[flux_id]
|
del self.bots[flux_id]
|
||||||
@@ -190,6 +220,12 @@ def toggle_flux(flux_id):
|
|||||||
bots['chat_bot'].stop()
|
bots['chat_bot'].stop()
|
||||||
if bots['record_bot']:
|
if bots['record_bot']:
|
||||||
bots['record_bot'].stop()
|
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:
|
except Exception as e:
|
||||||
print(f"Erreur lors de l'arrêt des bots: {e}")
|
print(f"Erreur lors de l'arrêt des bots: {e}")
|
||||||
else:
|
else:
|
||||||
@@ -199,6 +235,12 @@ def toggle_flux(flux_id):
|
|||||||
bots['chat_bot'].start_background()
|
bots['chat_bot'].start_background()
|
||||||
if bots['record_bot']:
|
if bots['record_bot']:
|
||||||
threading.Thread(target=bots['record_bot'].main, daemon=True).start()
|
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:
|
except Exception as e:
|
||||||
print(f"Erreur lors du redémarrage des bots: {e}")
|
print(f"Erreur lors du redémarrage des bots: {e}")
|
||||||
|
|
||||||
@@ -330,6 +372,114 @@ def get_subtitles():
|
|||||||
data = storage.read("subtitle_data")
|
data = storage.read("subtitle_data")
|
||||||
return jsonify(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'])
|
@app.route('/api/generations', methods=['GET'])
|
||||||
def get_generations():
|
def get_generations():
|
||||||
data = storage.read("IA_generator")
|
data = storage.read("IA_generator")
|
||||||
@@ -345,6 +495,10 @@ def send_message():
|
|||||||
if not message:
|
if not message:
|
||||||
return jsonify({'error': 'Message requis'}), 400
|
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
|
# Trouver le bot de message pour ce canal
|
||||||
try:
|
try:
|
||||||
msg_bot = messageTwitch("config/user.json", channel)
|
msg_bot = messageTwitch("config/user.json", channel)
|
||||||
@@ -405,6 +559,10 @@ def send_chat_message(flux_id):
|
|||||||
if not message:
|
if not message:
|
||||||
return jsonify({'error': 'Message requis'}), 400
|
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:
|
try:
|
||||||
# Trouver le flux
|
# Trouver le flux
|
||||||
flux = None
|
flux = None
|
||||||
@@ -476,6 +634,385 @@ def background_updates():
|
|||||||
print(f"Erreur dans background_updates: {e}")
|
print(f"Erreur dans background_updates: {e}")
|
||||||
time.sleep(10)
|
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__':
|
if __name__ == '__main__':
|
||||||
# Démarrer les mises à jour en arrière-plan
|
# Démarrer les mises à jour en arrière-plan
|
||||||
update_thread = threading.Thread(target=background_updates, daemon=True)
|
update_thread = threading.Thread(target=background_updates, daemon=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user