+ `).join('');
+}
+
+// Ouvrir le modal pour ajouter un utilisateur
+function openAddUserModal() {
+ document.getElementById('userModalTitle').textContent = 'Ajouter un Utilisateur';
+ document.getElementById('user-edit-id').value = '';
+ document.getElementById('user-pseudo').value = '';
+ document.getElementById('user-token').value = '';
+ document.getElementById('user-charactere').value = '😊';
+
+ // Ouvrir le modal
+ const modal = new bootstrap.Modal(document.getElementById('addUserModal'));
+ modal.show();
+}
+
+// Ouvrir le modal pour modifier un utilisateur
+function editUser(userId) {
+ const user = currentUsers[userId];
+ if (!user) return;
+
+ document.getElementById('userModalTitle').textContent = 'Modifier l\'Utilisateur';
+ document.getElementById('user-edit-id').value = userId;
+ document.getElementById('user-pseudo').value = user.tw_acc_pseudo;
+ document.getElementById('user-token').value = user.tw_acc_token;
+ document.getElementById('user-charactere').value = user.charactere;
+
+ // Ouvrir le modal
+ const modal = new bootstrap.Modal(document.getElementById('addUserModal'));
+ modal.show();
+}
+
+// Sauvegarder un utilisateur (ajout ou modification)
+async function saveUser() {
+ const userId = document.getElementById('user-edit-id').value;
+ const pseudo = document.getElementById('user-pseudo').value.trim();
+ const token = document.getElementById('user-token').value.trim();
+ const charactere = document.getElementById('user-charactere').value.trim();
+
+ if (!pseudo || !token) {
+ showToast('Pseudo et token requis', 'error');
+ return;
+ }
+
+ try {
+ let response;
+ if (userId === '') {
+ // Ajouter un nouvel utilisateur
+ response = await fetch(`${API_BASE}/api/config/users`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ tw_acc_pseudo: pseudo,
+ tw_acc_token: token,
+ charactere: charactere
+ })
+ });
+ } else {
+ // Modifier un utilisateur existant
+ response = await fetch(`${API_BASE}/api/config/users/${userId}`, {
+ method: 'PUT',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ tw_acc_pseudo: pseudo,
+ tw_acc_token: token,
+ charactere: charactere
+ })
+ });
+ }
+
+ const result = await response.json();
+
+ if (result.success) {
+ showToast(userId === '' ? 'Utilisateur ajouté' : 'Utilisateur modifié', 'success');
+ bootstrap.Modal.getInstance(document.getElementById('addUserModal')).hide();
+ await loadUsers();
+ } else {
+ showToast(result.error || 'Erreur lors de la sauvegarde', 'error');
+ }
+ } catch (error) {
+ console.error('Erreur:', error);
+ showToast('Erreur lors de la sauvegarde de l\'utilisateur', 'error');
+ }
+}
+
+// Supprimer un utilisateur
+async function deleteUser(userId) {
+ if (!confirm('Êtes-vous sûr de vouloir supprimer cet utilisateur ?')) {
+ return;
+ }
+
+ try {
+ const response = await fetch(`${API_BASE}/api/config/users/${userId}`, {
+ method: 'DELETE'
+ });
+
+ const result = await response.json();
+
+ if (result.success) {
+ showToast('Utilisateur supprimé avec succès', 'success');
+ await loadUsers();
+ } else {
+ showToast(result.error || 'Erreur lors de la suppression', 'error');
+ }
+ } catch (error) {
+ console.error('Erreur:', error);
+ showToast('Erreur lors de la suppression de l\'utilisateur', 'error');
+ }
+}
\ No newline at end of file
diff --git a/storage/IA_generator.json b/storage/IA_generator.json
index 870b7ea..ba0a85e 100644
--- a/storage/IA_generator.json
+++ b/storage/IA_generator.json
@@ -38,5 +38,7 @@
"01:25:48": "Be concise, witty, and light-hearted. Tell them. Dont tell them. No prevention. You should have done a #HashtagRaison. Green. Line their eyes. Prev. Subtitle Société Radio-CanadaCette version conserve la structure originale tout en utilisant des mots-clés américains comme witty et light-hearted. Elle maintient également les éléments spécifiques comme le hashtag, la couleur verte, et le sous-titre en français.",
"01:26:08": "Be brief, funny, and light-hearted. So there we have it, all the big weapons equipment and nothing to put in the game. No but were going to make money out of it anyway. Its just like usual. Oh yeah... Do you want a new game? Complete all the missions, oh!Cette traduction conserve le ton humoristique et légère du texte original tout en restant concise. Elle met laccent sur les points clés comme la frustration concernant léquipement, la décision de faire des profits malgré tout, et lidée dun nouveau jeu avec des missions à accomplir.",
"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:55": "Humour et poésie dans la programmation"
}
\ No newline at end of file
diff --git a/templates/index.html b/templates/index.html
index d5df9cc..727949b 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -27,7 +27,7 @@
-
+
Tableau de Bord
@@ -68,7 +68,7 @@
-
+
@@ -81,6 +81,11 @@
Messages
+
+
+
+
+
+
+
+
Gestion des Utilisateurs
+
+
+
+
+
+
+
+
+
+
@@ -213,6 +235,39 @@
+
+
+
+
+
+
Chat du Stream
+
+
+
+
+
+
+
+
+
+
Le chat apparaîtra ici quand un flux sera actif
+
+
+
+
+
+
@@ -244,6 +299,39 @@
+
+
+
+
+
+
Ajouter un Utilisateur
+
+
+
+
+
+
+
+
+
+
+
+
Format: oauth:token_ici
+
+
+
+
+
Emoji ou texte à ajouter avant les messages
+
+
+
+
+
+
+
diff --git a/web_interface.py b/web_interface.py
index cfd3775..7d47673 100644
--- a/web_interface.py
+++ b/web_interface.py
@@ -213,6 +213,113 @@ def update_prompts():
bot_controller.save_config()
return jsonify({'success': True})
+@app.route('/api/config/users', methods=['GET'])
+def get_users():
+ """Récupérer la liste des utilisateurs"""
+ try:
+ with open('config/user.json', 'r') as file:
+ users = json.load(file)
+ return jsonify(users)
+ except FileNotFoundError:
+ return jsonify([])
+ except Exception as e:
+ return jsonify({'error': str(e)}), 500
+
+@app.route('/api/config/users', methods=['POST'])
+def add_user():
+ """Ajouter un nouvel utilisateur"""
+ data = request.json
+ pseudo = data.get('tw_acc_pseudo')
+ token = data.get('tw_acc_token')
+ charactere = data.get('charactere', '😊')
+
+ if not pseudo or not token:
+ return jsonify({'error': 'Pseudo et token requis'}), 400
+
+ try:
+ with open('config/user.json', 'r') as file:
+ users = json.load(file)
+
+ # Vérifier si l'utilisateur existe déjà
+ for user in users:
+ if user['tw_acc_pseudo'] == pseudo:
+ return jsonify({'error': 'Cet utilisateur existe déjà'}), 400
+
+ # Ajouter le nouvel utilisateur
+ new_user = {
+ 'tw_acc_pseudo': pseudo,
+ 'tw_acc_token': token,
+ 'charactere': charactere
+ }
+ users.append(new_user)
+
+ # Sauvegarder
+ with open('config/user.json', 'w') as file:
+ json.dump(users, file, indent=4, ensure_ascii=False)
+
+ return jsonify({'success': True, 'user': new_user})
+ except Exception as e:
+ return jsonify({'error': str(e)}), 500
+
+@app.route('/api/config/users/', methods=['PUT'])
+def update_user(user_id):
+ """Modifier un utilisateur existant"""
+ data = request.json
+ pseudo = data.get('tw_acc_pseudo')
+ token = data.get('tw_acc_token')
+ charactere = data.get('charactere', '😊')
+
+ if not pseudo or not token:
+ return jsonify({'error': 'Pseudo et token requis'}), 400
+
+ try:
+ with open('config/user.json', 'r') as file:
+ users = json.load(file)
+
+ if user_id >= len(users):
+ return jsonify({'error': 'Utilisateur non trouvé'}), 404
+
+ # Vérifier si le pseudo existe déjà (sauf pour l'utilisateur actuel)
+ for i, user in enumerate(users):
+ if i != user_id and user['tw_acc_pseudo'] == pseudo:
+ return jsonify({'error': 'Ce pseudo est déjà utilisé'}), 400
+
+ # Mettre à jour l'utilisateur
+ users[user_id] = {
+ 'tw_acc_pseudo': pseudo,
+ 'tw_acc_token': token,
+ 'charactere': charactere
+ }
+
+ # Sauvegarder
+ with open('config/user.json', 'w') as file:
+ json.dump(users, file, indent=4, ensure_ascii=False)
+
+ return jsonify({'success': True, 'user': users[user_id]})
+ except Exception as e:
+ return jsonify({'error': str(e)}), 500
+
+@app.route('/api/config/users/', methods=['DELETE'])
+def delete_user(user_id):
+ """Supprimer un utilisateur"""
+ try:
+ with open('config/user.json', 'r') as file:
+ users = json.load(file)
+
+ if user_id >= len(users):
+ return jsonify({'error': 'Utilisateur non trouvé'}), 404
+
+ # Supprimer l'utilisateur
+ deleted_user = users.pop(user_id)
+
+ # Sauvegarder
+ with open('config/user.json', 'w') as file:
+ json.dump(users, file, indent=4, ensure_ascii=False)
+
+ return jsonify({'success': True, 'deleted_user': deleted_user})
+ except Exception as e:
+ return jsonify({'error': str(e)}), 500
+
@app.route('/api/subtitles', methods=['GET'])
def get_subtitles():
data = storage.read("subtitle_data")
@@ -252,6 +359,64 @@ def generate_response():
except Exception as e:
return jsonify({'error': str(e)}), 500
+@app.route('/api/chat//messages', methods=['GET'])
+def get_chat_messages(flux_id):
+ """Récupérer les messages de chat d'un flux spécifique"""
+ try:
+ if flux_id not in bot_controller.bots:
+ return jsonify({'error': 'Flux non trouvé'}), 404
+
+ chat_bot = bot_controller.bots[flux_id]['chat_bot']
+ if not chat_bot:
+ return jsonify({'error': 'Bot de chat non disponible'}), 404
+
+ # Récupérer les messages du bot de chat
+ messages = []
+ for msg in chat_bot.messages[-50:]: # Derniers 50 messages
+ messages.append({
+ 'timestamp': msg.timestamp.isoformat(),
+ 'username': msg.username,
+ 'content': msg.content
+ })
+
+ return jsonify({
+ 'success': True,
+ 'flux_id': flux_id,
+ 'messages': messages
+ })
+
+ except Exception as e:
+ return jsonify({'error': str(e)}), 500
+
+@app.route('/api/chat//send', methods=['POST'])
+def send_chat_message(flux_id):
+ """Envoyer un message dans le chat d'un flux spécifique"""
+ data = request.json
+ message = data.get('message', '')
+
+ if not message:
+ return jsonify({'error': 'Message requis'}), 400
+
+ try:
+ # Trouver le flux
+ flux = None
+ for f in bot_controller.flux_list:
+ if f['id'] == flux_id:
+ flux = f
+ break
+
+ if not flux:
+ return jsonify({'error': 'Flux non trouvé'}), 404
+
+ # Envoyer le message
+ msg_bot = messageTwitch("config/user.json", flux['twitchname'])
+ msg_bot.send_message(message)
+
+ return jsonify({'success': True})
+
+ except Exception as e:
+ return jsonify({'error': str(e)}), 500
+
@app.route('/api/status', methods=['GET'])
def get_status():
status = {