Files
2026-04-28 21:06:26 +02:00

736 lines
48 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TwitchBot Controller - Interface de Contrôle</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet">
</head>
<body class="bg-dark text-light">
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<i class="fas fa-robot me-2"></i>TwitchBot Controller
</a>
<div class="navbar-nav me-auto ms-3 d-none d-lg-flex">
<a class="nav-link navbar-sitemap-link" data-main-tab="flux-tab" href="#" onclick="activateMainTab('flux-tab'); return false;">
<i class="fas fa-tachometer-alt me-1"></i>Dashboard
</a>
<a class="nav-link navbar-sitemap-link" data-main-tab="users-tab" href="#" onclick="activateMainTab('users-tab'); return false;">
<i class="fas fa-users me-1"></i>Utilisateurs
</a>
<a class="nav-link navbar-sitemap-link" data-main-tab="prompts-tab" href="#" onclick="activateMainTab('prompts-tab'); return false;">
<i class="fas fa-cogs me-1"></i>Prompts IA
</a>
<a class="nav-link navbar-sitemap-link" data-main-tab="subtitles-tab" href="#" onclick="activateMainTab('subtitles-tab'); return false;">
<i class="fas fa-closed-captioning me-1"></i>Sous-titres
</a>
<a class="nav-link navbar-sitemap-link" data-main-tab="interaction-tab" href="#" onclick="activateMainTab('interaction-tab'); return false;">
<i class="fas fa-at me-1"></i>Interaction chat
</a>
<a class="nav-link navbar-sitemap-link" data-main-tab="clips-tab" href="#" onclick="activateMainTab('clips-tab'); return false;">
<i class="fas fa-film me-1"></i>Clips
</a>
<a class="nav-link navbar-sitemap-link" data-main-tab="settings-tab" href="#" onclick="activateMainTab('settings-tab'); return false;">
<i class="fas fa-sliders-h me-1"></i>Paramètres
</a>
</div>
<div class="navbar-nav ms-auto">
<span class="navbar-text">
<i class="fas fa-circle text-success pulse"></i>
<span id="connection-status">Connecté</span>
</span>
</div>
</div>
</nav>
<div class="container-fluid mt-4">
<div class="row">
<!-- Main Content -->
<div class="col-md-9" id="main-content-col">
<!-- Tabs Navigation -->
<ul class="nav nav-tabs d-none" id="mainTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="flux-tab" data-bs-toggle="tab" data-bs-target="#flux" type="button">
<i class="fas fa-tachometer-alt me-2"></i>Dashboard
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="users-tab" data-bs-toggle="tab" data-bs-target="#users" type="button">
<i class="fas fa-users me-2"></i>Utilisateurs
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="prompts-tab" data-bs-toggle="tab" data-bs-target="#prompts" type="button">
<i class="fas fa-cogs me-2"></i>Prompts IA
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="subtitles-tab" data-bs-toggle="tab" data-bs-target="#subtitles" type="button">
<i class="fas fa-closed-captioning me-2"></i>Sous-titres
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="interaction-tab" data-bs-toggle="tab" data-bs-target="#interaction" type="button">
<i class="fas fa-at me-2"></i>Interaction chat
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="clips-tab" data-bs-toggle="tab" data-bs-target="#clips" type="button">
<i class="fas fa-film me-2"></i>Clips
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings" type="button">
<i class="fas fa-sliders-h me-2"></i>Paramètres
</button>
</li>
</ul>
<!-- Tab Content -->
<div class="tab-content mt-3" id="mainTabContent">
<!-- Flux Tab -->
<div class="tab-pane fade show active" id="flux" role="tabpanel">
<!-- Ligne 1: tableau de bord + gestion des flux -->
<div class="row g-3">
<div class="col-lg-4">
<div class="card bg-secondary h-100">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-tachometer-alt me-2"></i>Tableau de Bord</h5>
</div>
<div class="card-body">
<div class="status-item">
<span class="badge bg-info">Flux Actifs</span>
<span class="float-end" id="flux-count">0</span>
</div>
<div class="status-item">
<span class="badge bg-warning">Enregistrements</span>
<span class="float-end" id="recording-count">0</span>
</div>
<div class="status-item">
<span class="badge bg-success">Connexions Chat</span>
<span class="float-end" id="chat-count">0</span>
</div>
<div class="small text-muted mt-3">
Vue rapide de lactivité (flux, enregistrement, connexions chat).
</div>
</div>
</div>
</div>
<div class="col-lg-8">
<div class="card bg-secondary h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="fas fa-stream me-2"></i>Gestion des Flux</h5>
<button class="btn btn-success btn-sm" data-bs-toggle="modal" data-bs-target="#addFluxModal">
<i class="fas fa-plus me-2"></i>Ajouter Flux
</button>
</div>
<div class="card-body">
<div id="flux-list">
<!-- Flux list will be populated here -->
</div>
</div>
</div>
</div>
</div>
<!-- Ligne 2: actions rapides -->
<div class="card bg-secondary mt-3">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-bolt me-2"></i>Actions Rapides</h5>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-md-4">
<button class="btn btn-success btn-sm w-100" onclick="generateResponse()">
<i class="fas fa-magic me-2"></i>Générer Réponse
</button>
<div class="small text-muted mt-1">Déclenche une génération IA à partir du dernier texte (sous-titres).</div>
</div>
<div class="col-md-4">
<button class="btn btn-primary btn-sm w-100" onclick="sendLastGeneration()">
<i class="fas fa-paper-plane me-2"></i>Envoyer Dernière Génération
</button>
<div class="small text-muted mt-1">Envoie sur Twitch la dernière réponse IA disponible.</div>
</div>
<div class="col-md-4">
<button class="btn btn-info btn-sm w-100" onclick="refreshData()">
<i class="fas fa-sync me-2"></i>Actualiser
</button>
<div class="small text-muted mt-1">Recharge l’état et les données (flux, users, sous-titres, etc.).</div>
</div>
</div>
<hr class="border-secondary my-3">
<div class="row g-3">
<div class="col-md-6 col-xl-4">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="fw-semibold">Génération Auto Sous-titres</div>
<div class="small text-muted">Transcrit automatiquement les mp3 (Whisper) et alimente lhistorique.</div>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="autoSubtitleToggle" onchange="toggleAutoSubtitle()">
</div>
</div>
<div class="mt-2 d-flex justify-content-between align-items-center">
<small class="text-muted" id="autoSubtitleStatus">Arrêté</small>
<button class="btn btn-warning btn-sm" onclick="forceStopAutoSubtitle()" title="Forcer l'arrêt en cas de problème">
<i class="fas fa-stop-circle me-1"></i>Force Stop
</button>
</div>
</div>
<div class="col-md-6 col-xl-4">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="fw-semibold">Envoi Auto Messages</div>
<div class="small text-muted">Envoie automatiquement les générations IA disponibles.</div>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="autoMessageToggle" onchange="toggleAutoMessage()">
</div>
</div>
<div class="mt-2 d-flex justify-content-between align-items-center">
<small class="text-muted" id="autoMessageStatus">Arrêté</small>
<button class="btn btn-warning btn-sm" 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>
<div class="col-md-6 col-xl-6">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="fw-semibold">Générateur IA</div>
<div class="small text-muted">Génère périodiquement des réponses (stockées dans `storage/IA_generator.json`).</div>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="iaGeneratorToggle" onchange="toggleIAGenerator()">
</div>
</div>
<div class="mt-2">
<small class="text-muted" id="iaGeneratorStatus">Arrêté</small>
</div>
</div>
<div class="col-md-6 col-xl-6">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="fw-semibold">Contrôleur Twitch</div>
<div class="small text-muted">Envoie automatiquement sur Twitch les générations présentes en file.</div>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="controlTwitchToggle" onchange="toggleControlTwitch()">
</div>
</div>
<div class="mt-2">
<small class="text-muted" id="controlTwitchStatus">Arrêté</small>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Users Tab -->
<div class="tab-pane fade" id="users" role="tabpanel">
<div class="card bg-secondary">
<div class="card-header d-flex justify-content-between align-items-center">
<h5><i class="fas fa-users me-2"></i>Gestion des Utilisateurs</h5>
<button class="btn btn-success btn-sm" onclick="openAddUserModal()">
<i class="fas fa-plus me-2"></i>Ajouter Utilisateur
</button>
</div>
<div class="card-body">
<div id="users-list">
<!-- Users list will be populated here -->
</div>
</div>
</div>
</div>
<!-- Prompts Tab -->
<div class="tab-pane fade" id="prompts" role="tabpanel">
<div class="row g-3">
<div class="col-lg-7">
<div class="card bg-secondary">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="fas fa-cogs me-2"></i>Configuration des Prompts IA</h5>
<button class="btn btn-success btn-sm" onclick="addPrompt()">
<i class="fas fa-plus me-2"></i>Ajouter Prompt
</button>
</div>
<div class="card-body">
<div id="prompts-list">
<!-- Prompts will be populated here -->
</div>
<button class="btn btn-primary mt-3" onclick="savePrompts()">
<i class="fas fa-save me-2"></i>Sauvegarder les Prompts
</button>
</div>
</div>
</div>
<div class="col-lg-5">
<div class="card bg-secondary">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-eye me-2"></i>Prochain Message</h5>
</div>
<div class="card-body">
<div class="alert alert-info" id="next-message">
Aucun message en attente
</div>
<button class="btn btn-primary" onclick="sendNextMessage()">
<i class="fas fa-paper-plane me-2"></i>Envoyer ce Message
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Subtitles Tab -->
<div class="tab-pane fade" id="subtitles" role="tabpanel">
<div class="row">
<div class="col-md-6">
<div class="card bg-secondary">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="fas fa-microphone me-2"></i>Dernier Texte Détecté</h5>
<select class="form-select form-select-sm" id="subtitles-flux-select" style="max-width: 220px;" onchange="onSubtitlesFluxChange()">
<option value="-1">Flux…</option>
</select>
</div>
</div>
<div class="card-body">
<div class="alert alert-warning" id="last-subtitle">
Aucun texte détecté pour le moment
</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()">
<i class="fas fa-robot me-2"></i>Générer Réponse IA
</button>
<button class="btn btn-primary" onclick="processSubtitles()">
<i class="fas fa-cogs me-2"></i>Traitement Manuel
</button>
<button class="btn btn-danger" onclick="clearSubtitlesHistory()">
<i class="fas fa-trash me-2"></i>Nettoyer Historique
</button>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card bg-secondary">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="fas fa-list me-2"></i>Historique des Sous-titres</h5>
<button class="btn btn-outline-light btn-sm" onclick="refreshSubtitlesAll()">
<i class="fas fa-sync me-1"></i>Rafraîchir
</button>
</div>
<div class="card-body">
<div id="subtitles-history" class="subtitle-history">
<!-- Subtitles history will be populated here -->
</div>
</div>
</div>
</div>
</div>
<div class="row mt-3 g-3">
<div class="col-md-7">
<div class="card bg-secondary">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="fas fa-bolt me-2"></i>Règles (sous-titres → actions)</h5>
<div class="d-flex gap-2">
<button class="btn btn-outline-light btn-sm" onclick="refreshSubtitleRules()">
<i class="fas fa-sync me-1"></i>Recharger
</button>
<button class="btn btn-success btn-sm" onclick="saveSubtitleRules()">
<i class="fas fa-save me-1"></i>Sauvegarder
</button>
</div>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-md-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="subtitle-rules-enabled">
<label class="form-check-label" for="subtitle-rules-enabled">Actif</label>
</div>
</div>
</div>
<hr class="border-secondary my-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0"><i class="fas fa-list me-2"></i>Règles</h6>
<button class="btn btn-primary btn-sm" onclick="addSubtitleRule()">
<i class="fas fa-plus me-1"></i>Ajouter règle
</button>
</div>
<div id="subtitle-rules" class="d-flex flex-column gap-2"></div>
<div class="form-text text-muted mt-2">
Déclenche une action quand un sous-titre contient un mot/texte.
</div>
</div>
</div>
</div>
<div class="col-md-5">
<div class="card bg-secondary">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="fas fa-clipboard-list me-2"></i>Logs règles</h5>
<button class="btn btn-outline-light btn-sm" onclick="refreshSubtitleRulesLog()">
<i class="fas fa-sync me-1"></i>Rafraîchir
</button>
</div>
<div class="card-body">
<div id="subtitle-rules-log" class="subtitle-history">
<div class="text-muted text-center">Aucun log</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Interaction Chat Tab -->
<div class="tab-pane fade" id="interaction" role="tabpanel">
<div class="row">
<div class="col-md-7">
<div class="card bg-secondary">
<div class="card-header d-flex justify-content-between align-items-center">
<h5><i class="fas fa-at me-2"></i>Interaction chat</h5>
<div class="d-flex gap-2">
<button class="btn btn-outline-light btn-sm" onclick="refreshInteractionConfig()">
<i class="fas fa-sync me-1"></i>Recharger
</button>
<button class="btn btn-success btn-sm" onclick="saveInteractionConfig()">
<i class="fas fa-save me-1"></i>Sauvegarder
</button>
</div>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-md-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="interaction-enabled">
<label class="form-check-label" for="interaction-enabled">Actif</label>
</div>
</div>
<div class="col-md-4">
<label class="form-label small text-muted" for="interaction-mode">Mode</label>
<select class="form-select form-select-sm" id="interaction-mode">
<option value="predefined">Réponses préenregistrées</option>
<option value="tgpt">TGPT (IA)</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label small text-muted" for="interaction-cooldown">Cooldown (sec)</label>
<input class="form-control form-control-sm" type="number" min="0" max="999" id="interaction-cooldown" value="8">
</div>
</div>
<div class="row g-3 mt-1" id="interaction-tgpt-settings">
<div class="col-md-5">
<label class="form-label small text-muted" for="interaction-tgpt-preprompt">Préprompt TGPT (global)</label>
<textarea class="form-control" id="interaction-tgpt-preprompt" rows="2" placeholder="Ex: Réponds brièvement en français."></textarea>
</div>
<div class="col-md-3">
<label class="form-label small text-muted" for="interaction-tgpt-max-chars">Max caractères TGPT</label>
<input class="form-control form-control-sm" type="number" min="10" max="2000" id="interaction-tgpt-max-chars" value="100">
<div class="form-text text-muted">Au-delà: tronqué avec “...”.</div>
</div>
</div>
<hr class="border-secondary my-3">
<div class="row g-3">
<div class="col-md-8">
<label class="form-label small text-muted" for="interaction-default-responses">Réponses par défaut (1 par ligne)</label>
<textarea class="form-control" id="interaction-default-responses" rows="3" placeholder="salut"></textarea>
<div class="form-text text-muted">Si un message mentionne un compte enregistré et quaucune règle ne match, la 1ère ligne sera utilisée.</div>
</div>
<div class="col-md-4">
<label class="form-label small text-muted">Comptes enregistrés</label>
<div class="border rounded p-2 bg-dark" style="max-height: 140px; overflow:auto;">
<div id="interaction-registered-accounts" class="small text-muted"></div>
</div>
</div>
</div>
<hr class="border-secondary my-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0"><i class="fas fa-list me-2"></i>Règles</h6>
<button class="btn btn-primary btn-sm" onclick="addInteractionRule()">
<i class="fas fa-plus me-1"></i>Ajouter règle
</button>
</div>
<div id="interaction-rules" class="d-flex flex-column gap-2">
<!-- rules injected -->
</div>
<div class="form-text text-muted mt-2">
Ordre: la 1ère règle qui match gagne. Conditions possibles: utilisateur source, compte mentionné, texte contenu.
</div>
</div>
</div>
</div>
<div class="col-md-5">
<div class="card bg-secondary">
<div class="card-header d-flex justify-content-between align-items-center">
<h5><i class="fas fa-clipboard-list me-2"></i>Logs</h5>
<button class="btn btn-outline-light btn-sm" onclick="refreshInteractionLog()">
<i class="fas fa-sync me-1"></i>Rafraîchir
</button>
</div>
<div class="card-body">
<div id="interaction-log" class="subtitle-history">
<div class="text-muted text-center">Aucun log</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Clips Tab -->
<div class="tab-pane fade" id="clips" role="tabpanel">
<div class="row g-3">
<div class="col-lg-7">
<div class="card bg-secondary">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="fas fa-film me-2"></i>Créer un clip</h5>
<button class="btn btn-outline-light btn-sm" onclick="prefillClipChannelFromActiveFlux()" title="Utiliser le flux actif">
<i class="fas fa-wand-magic-sparkles me-1"></i>Auto
</button>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label small text-muted" for="clips-user-select">Utilisateur (token)</label>
<select class="form-select form-select-sm user-selector" id="clips-user-select">
<option value="-1">Sélectionner un utilisateur...</option>
</select>
<div class="form-text text-muted">Le token doit avoir le scope <code>clips:edit</code>.</div>
</div>
<div class="col-md-6">
<label class="form-label small text-muted" for="clips-channel-login">Chaîne Twitch (login)</label>
<input class="form-control form-control-sm" id="clips-channel-login" type="text" placeholder="ex: exoticnaturees">
<div class="form-text text-muted">Entrez le login sans URL. Le @ est accepté.</div>
</div>
<div class="col-md-6">
<div class="form-check form-switch mt-4">
<input class="form-check-input" type="checkbox" id="clips-has-delay">
<label class="form-check-label" for="clips-has-delay">has_delay</label>
</div>
<div class="form-text text-muted">À activer si le stream a un délai (anti-streamsniping).</div>
</div>
<div class="col-12 d-flex gap-2">
<button class="btn btn-success" onclick="createClip()">
<i class="fas fa-scissors me-2"></i>Créer le clip
</button>
<button class="btn btn-outline-light" onclick="clearClipResult()">
<i class="fas fa-eraser me-2"></i>Effacer
</button>
</div>
</div>
<hr class="border-secondary my-3">
<div id="clips-result" class="d-none">
<div class="alert alert-info mb-2">
<div class="fw-semibold mb-1">Résultat</div>
<div class="small">
<div>Clip: <a id="clips-public-url" href="#" target="_blank" rel="noopener noreferrer"></a></div>
<div>Edit: <a id="clips-edit-url" href="#" target="_blank" rel="noopener noreferrer"></a></div>
<div class="text-muted mt-1">ID: <span id="clips-id"></span></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-5">
<div class="card bg-secondary">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-gears me-2"></i>Automatisation (futur)</h5>
</div>
<div class="card-body">
<div class="small text-muted">
Une base est prête côté API pour brancher une automatisation (ex: clip sur mot-clé, intervalle, événement).
Pour linstant, aucune boucle nest lancée automatiquement.
</div>
<div class="mt-3">
<button class="btn btn-outline-light btn-sm" onclick="checkClipAutomationStatus()">
<i class="fas fa-circle-info me-1"></i>Statut
</button>
<div class="mt-2 small text-muted" id="clips-automation-status"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Settings Tab -->
<div class="tab-pane fade" id="settings" role="tabpanel">
<div class="card bg-secondary">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="fas fa-sliders-h me-2"></i>Paramètres</h5>
<button class="btn btn-success btn-sm" onclick="saveSettings()">
<i class="fas fa-save me-1"></i>Sauvegarder
</button>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label small text-muted" for="settings-message-max-chars">Limite caractères message Twitch</label>
<input class="form-control" type="number" min="10" max="500" id="settings-message-max-chars" value="100">
<div class="form-text text-muted">
Si un message dépasse la limite, il est tronqué et “...” est ajouté, puis il est envoyé.
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Chat Column -->
<div class="col-md-3" id="chat-col">
<div class="card bg-secondary chat-container">
<div class="card-header d-flex justify-content-between align-items-center">
<h5><i class="fas fa-comments me-2"></i>Chat du Stream</h5>
<div class="chat-controls">
<button class="btn btn-sm btn-outline-light" onclick="clearChat()">
<i class="fas fa-trash"></i>
</button>
<button class="btn btn-sm btn-outline-light" onclick="toggleChat()">
<i class="fas fa-pause" id="chat-toggle-icon"></i>
</button>
</div>
</div>
<div class="card-body p-0">
<div id="chat-messages" class="chat-messages">
<div class="chat-welcome">
<i class="fas fa-comments text-muted"></i>
<p class="text-muted">Le chat apparaîtra ici quand un flux sera actif</p>
</div>
</div>
</div>
<div class="card-footer">
<div class="mb-2">
<label for="chat-user-select" class="form-label small">Utilisateur</label>
<select class="form-select form-select-sm user-selector" id="chat-user-select">
<option value="-1">Sélectionner un utilisateur...</option>
</select>
</div>
<div class="input-group">
<input type="text" class="form-control" id="chat-input" placeholder="Tapez un message..." disabled>
<button class="btn btn-primary" type="button" onclick="sendChatMessage()" disabled>
<i class="fas fa-paper-plane"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Add Flux Modal -->
<div class="modal fade" id="addFluxModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content bg-dark">
<div class="modal-header">
<h5 class="modal-title">Ajouter un Nouveau Flux</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="channel-name" class="form-label">Nom du Canal</label>
<input type="text" class="form-control" id="channel-name" placeholder="Ex: ocelothfoufure">
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="record-audio" checked>
<label class="form-check-label" for="record-audio">
Enregistrer l'audio du stream
</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input" type="checkbox" id="send-messages" checked>
<label class="form-check-label" for="send-messages">
Autoriser lenvoi de messages sur ce stream
</label>
<div class="form-text text-muted">Contrôle par flux.</div>
</div>
<div class="form-check mt-2">
<input class="form-check-input" type="checkbox" id="enable-ia" checked>
<label class="form-check-label" for="enable-ia">
Activer génération TGPT (IA) à partir des sous-titres
</label>
<div class="form-text text-muted">
Si désactivé: pas de génération TGPT et pas denvoi automatique des messages générés.
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
<button type="button" class="btn btn-primary" onclick="addFlux()">Ajouter</button>
</div>
</div>
</div>
</div>
<!-- Add/Edit User Modal -->
<div class="modal fade" id="addUserModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content bg-dark">
<div class="modal-header">
<h5 class="modal-title" id="userModalTitle">Ajouter un Utilisateur</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<input type="hidden" id="user-edit-id" value="">
<div class="mb-3">
<label for="user-pseudo" class="form-label">Pseudo Twitch</label>
<input type="text" class="form-control" id="user-pseudo" placeholder="Ex: mon_pseudo">
</div>
<div class="mb-3">
<label for="user-token" class="form-label">Token OAuth</label>
<input type="password" class="form-control" id="user-token" placeholder="oauth:token_ici">
<div class="form-text text-muted">Format: oauth:token_ici</div>
</div>
<div class="mb-3">
<label for="user-charactere" class="form-label">Caractère</label>
<input type="text" class="form-control" id="user-charactere" placeholder="😊" value="😊">
<div class="form-text text-muted">Emoji ou texte à ajouter avant les messages</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
<button type="button" class="btn btn-primary" onclick="saveUser()">Sauvegarder</button>
</div>
</div>
</div>
</div>
<!-- Scripts -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
</body>
</html>