classifications / index.html
simondh's picture
Add 2 files
5bc350f verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Système de Classification Textuelle</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.dropzone {
border: 2px dashed #cbd5e0;
transition: all 0.3s ease;
}
.dropzone.active {
border-color: #4f46e5;
background-color: #eef2ff;
}
.progress-bar {
transition: width 0.3s ease;
}
.category-chip {
transition: all 0.2s ease;
}
.category-chip:hover {
transform: translateY(-2px);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
.fade-in {
animation: fadeIn 0.5s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="mb-8 text-center">
<h1 class="text-3xl font-bold text-indigo-700 mb-2">
<i class="fas fa-project-diagram mr-2"></i>Système de Classification Textuelle
</h1>
<p class="text-gray-600 max-w-2xl mx-auto">
Un outil simple et transparent pour classifier automatiquement vos données textuelles
</p>
</header>
<!-- Main Content -->
<div class="bg-white rounded-xl shadow-md overflow-hidden">
<!-- Process Steps -->
<div class="flex justify-between px-6 py-4 border-b">
<div class="step flex-1 text-center relative" data-step="1">
<div class="w-10 h-10 mx-auto rounded-full bg-indigo-600 text-white flex items-center justify-center font-bold mb-2">
1
</div>
<p class="text-sm font-medium text-indigo-600">Import des données</p>
<div class="absolute bottom-0 left-0 right-0 h-1 bg-indigo-600"></div>
</div>
<div class="step flex-1 text-center relative" data-step="2">
<div class="w-10 h-10 mx-auto rounded-full bg-gray-200 text-gray-600 flex items-center justify-center font-bold mb-2">
2
</div>
<p class="text-sm font-medium text-gray-500">Configuration</p>
<div class="absolute bottom-0 left-0 right-0 h-1 bg-gray-200"></div>
</div>
<div class="step flex-1 text-center relative" data-step="3">
<div class="w-10 h-10 mx-auto rounded-full bg-gray-200 text-gray-600 flex items-center justify-center font-bold mb-2">
3
</div>
<p class="text-sm font-medium text-gray-500">Classification</p>
<div class="absolute bottom-0 left-0 right-0 h-1 bg-gray-200"></div>
</div>
<div class="step flex-1 text-center relative" data-step="4">
<div class="w-10 h-10 mx-auto rounded-full bg-gray-200 text-gray-600 flex items-center justify-center font-bold mb-2">
4
</div>
<p class="text-sm font-medium text-gray-500">Résultats</p>
<div class="absolute bottom-0 left-0 right-0 h-1 bg-gray-200"></div>
</div>
</div>
<!-- Step 1 Content -->
<div id="step-1" class="p-6 fade-in">
<h2 class="text-xl font-semibold mb-4 text-gray-800">
<i class="fas fa-file-import mr-2 text-indigo-500"></i>Importez vos données
</h2>
<div class="mb-6">
<div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer">
<div class="mx-auto w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mb-4">
<i class="fas fa-cloud-upload-alt text-indigo-500 text-2xl"></i>
</div>
<h3 class="text-lg font-medium text-gray-700 mb-1">Glissez-déposez votre fichier</h3>
<p class="text-gray-500 mb-4">ou cliquez pour sélectionner</p>
<input type="file" id="fileInput" class="hidden" accept=".csv,.xlsx,.xls">
<button id="selectFileBtn" class="px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 transition">
<i class="fas fa-folder-open mr-2"></i>Sélectionner un fichier
</button>
<p class="text-xs text-gray-400 mt-3">Formats supportés: CSV, XLSX, XLS</p>
</div>
</div>
<div id="filePreview" class="hidden border rounded-lg overflow-hidden">
<div class="bg-gray-50 px-4 py-3 border-b flex justify-between items-center">
<div>
<span id="fileName" class="font-medium"></span>
<span id="fileSize" class="text-sm text-gray-500 ml-2"></span>
</div>
<button id="removeFileBtn" class="text-red-500 hover:text-red-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-100">
<tr>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Colonnes détectées</th>
</tr>
</thead>
<tbody id="columnsList" class="bg-white divide-y divide-gray-200">
<!-- Columns will be added here by JS -->
</tbody>
</table>
</div>
</div>
<div class="flex justify-end mt-6">
<button id="nextStep1" class="px-6 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 transition disabled:opacity-50 disabled:cursor-not-allowed" disabled>
Suivant <i class="fas fa-arrow-right ml-2"></i>
</button>
</div>
</div>
<!-- Step 2 Content -->
<div id="step-2" class="hidden p-6">
<h2 class="text-xl font-semibold mb-4 text-gray-800">
<i class="fas fa-cog mr-2 text-indigo-500"></i>Configurez la classification
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Colonne à classifier</label>
<select id="textColumnSelect" class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
<option value="">Sélectionnez une colonne</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Méthode de classification</label>
<select id="classificationMethod" class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
<option value="keywords">Mots-clés</option>
<option value="ai">IA (recommandé)</option>
<option value="regex">Expressions régulières</option>
</select>
</div>
</div>
<div id="keywordsConfig" class="mb-6">
<div class="flex justify-between items-center mb-2">
<label class="block text-sm font-medium text-gray-700">Catégories et mots-clés</label>
<button id="addCategoryBtn" class="text-sm text-indigo-600 hover:text-indigo-800 flex items-center">
<i class="fas fa-plus-circle mr-1"></i> Ajouter une catégorie
</button>
</div>
<div id="categoriesContainer" class="space-y-3">
<div class="category-group border rounded-lg p-4 bg-gray-50">
<div class="flex justify-between items-center mb-3">
<input type="text" placeholder="Nom de la catégorie" class="category-name flex-1 border-b border-gray-300 focus:border-indigo-500 focus:outline-none bg-transparent py-1">
<button class="remove-category text-red-500 hover:text-red-700 ml-2">
<i class="fas fa-trash"></i>
</button>
</div>
<div class="flex flex-wrap gap-2">
<div class="keyword-chip flex items-center bg-white px-3 py-1 rounded-full text-sm shadow-sm">
<span>exemple</span>
<button class="remove-keyword ml-1 text-gray-400 hover:text-red-500">
<i class="fas fa-times text-xs"></i>
</button>
</div>
<input type="text" placeholder="Ajouter un mot-clé" class="keyword-input flex-1 min-w-[100px] border-b border-gray-300 focus:border-indigo-500 focus:outline-none bg-transparent py-1">
</div>
</div>
</div>
</div>
<div id="aiConfig" class="hidden mb-6">
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-robot text-blue-500 text-xl"></i>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-blue-800">Classification par IA</h3>
<div class="mt-2 text-sm text-blue-700">
<p>Notre système d'IA analysera automatiquement le contenu textuel et proposera des catégories pertinentes. Vous pourrez ajuster les résultats après la classification initiale.</p>
</div>
</div>
</div>
</div>
</div>
<div id="regexConfig" class="hidden mb-6">
<div class="bg-purple-50 border border-purple-200 rounded-lg p-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-code text-purple-500 text-xl"></i>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-purple-800">Expressions régulières</h3>
<div class="mt-2 text-sm text-purple-700">
<p>Définissez des motifs complexes pour classifier vos données. Requiert une connaissance des expressions régulières.</p>
</div>
</div>
</div>
</div>
<div class="mt-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Ajouter une règle Regex</label>
<div class="flex space-x-2">
<input type="text" placeholder="Nom de la catégorie" class="flex-1 border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
<input type="text" placeholder="Expression régulière" class="flex-1 border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
<button class="px-3 py-1 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">
<i class="fas fa-plus"></i>
</button>
</div>
</div>
</div>
<div class="flex justify-between mt-6">
<button id="prevStep2" class="px-6 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 transition">
<i class="fas fa-arrow-left mr-2"></i> Précédent
</button>
<button id="nextStep2" class="px-6 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 transition disabled:opacity-50 disabled:cursor-not-allowed" disabled>
Suivant <i class="fas fa-arrow-right ml-2"></i>
</button>
</div>
</div>
<!-- Step 3 Content -->
<div id="step-3" class="hidden p-6">
<h2 class="text-xl font-semibold mb-4 text-gray-800">
<i class="fas fa-tasks mr-2 text-indigo-500"></i>Classification en cours
</h2>
<div class="bg-gray-50 rounded-lg p-6 text-center">
<div class="w-24 h-24 mx-auto mb-6 relative">
<div class="absolute inset-0 flex items-center justify-center">
<i class="fas fa-cog text-indigo-400 text-4xl animate-spin"></i>
</div>
<svg class="w-full h-full" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="45" fill="none" stroke="#e5e7eb" stroke-width="10"/>
<circle id="progressCircle" cx="50" cy="50" r="45" fill="none" stroke="#4f46e5" stroke-width="10" stroke-dasharray="283" stroke-dashoffset="283" stroke-linecap="round" transform="rotate(-90 50 50)"/>
</svg>
</div>
<h3 id="progressText" class="text-lg font-medium text-gray-700 mb-2">Préparation de la classification...</h3>
<p id="progressSubtext" class="text-gray-500 mb-4">Veuillez patienter pendant le traitement de vos données</p>
<div class="w-full bg-gray-200 rounded-full h-2.5 mb-6">
<div id="progressBar" class="bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div>
</div>
<div id="progressDetails" class="hidden text-left bg-white p-4 rounded-lg border mb-4">
<div class="flex justify-between mb-2">
<span class="text-sm font-medium">Lignes traitées</span>
<span id="processedRows" class="text-sm">0/0</span>
</div>
<div class="flex justify-between mb-2">
<span class="text-sm font-medium">Catégories identifiées</span>
<span id="identifiedCategories" class="text-sm">0</span>
</div>
<div class="flex justify-between">
<span class="text-sm font-medium">Confiance moyenne</span>
<span id="averageConfidence" class="text-sm">0%</span>
</div>
</div>
<button id="cancelProcessBtn" class="px-4 py-2 bg-red-100 text-red-600 rounded-md hover:bg-red-200 transition">
<i class="fas fa-stop-circle mr-2"></i>Annuler
</button>
</div>
</div>
<!-- Step 4 Content -->
<div id="step-4" class="hidden p-6">
<h2 class="text-xl font-semibold mb-4 text-gray-800">
<i class="fas fa-chart-bar mr-2 text-indigo-500"></i>Résultats de la classification
</h2>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
<div class="bg-white border rounded-lg p-4 shadow-sm">
<h3 class="text-sm font-medium text-gray-500 mb-2">Résumé</h3>
<div class="space-y-3">
<div>
<p class="text-xs text-gray-400">Fichier analysé</p>
<p id="resultFileName" class="font-medium">donnees.csv</p>
</div>
<div>
<p class="text-xs text-gray-400">Lignes classifiées</p>
<p id="resultTotalRows" class="font-medium">1,245</p>
</div>
<div>
<p class="text-xs text-gray-400">Catégories identifiées</p>
<p id="resultTotalCategories" class="font-medium">8</p>
</div>
</div>
</div>
<div class="bg-white border rounded-lg p-4 shadow-sm">
<h3 class="text-sm font-medium text-gray-500 mb-2">Distribution des catégories</h3>
<div id="categoryDistributionChart" class="h-40">
<!-- Chart will be rendered here -->
<div class="flex items-center justify-center h-full text-gray-400">
<i class="fas fa-chart-pie text-3xl mr-2"></i>
<span>Graphique de distribution</span>
</div>
</div>
</div>
<div class="bg-white border rounded-lg p-4 shadow-sm">
<h3 class="text-sm font-medium text-gray-500 mb-2">Actions</h3>
<div class="space-y-2">
<button id="exportResultsBtn" class="w-full flex items-center justify-between px-3 py-2 bg-indigo-50 text-indigo-600 rounded hover:bg-indigo-100">
<span><i class="fas fa-file-export mr-2"></i>Exporter les résultats</span>
<i class="fas fa-chevron-right"></i>
</button>
<button id="adjustCategoriesBtn" class="w-full flex items-center justify-between px-3 py-2 bg-blue-50 text-blue-600 rounded hover:bg-blue-100">
<span><i class="fas fa-edit mr-2"></i>Ajuster les catégories</span>
<i class="fas fa-chevron-right"></i>
</button>
<button id="newClassificationBtn" class="w-full flex items-center justify-between px-3 py-2 bg-gray-100 text-gray-700 rounded hover:bg-gray-200">
<span><i class="fas fa-redo mr-2"></i>Nouvelle classification</span>
<i class="fas fa-chevron-right"></i>
</button>
</div>
</div>
</div>
<div class="bg-white border rounded-lg overflow-hidden mb-6">
<div class="bg-gray-50 px-4 py-3 border-b flex justify-between items-center">
<div class="flex items-center">
<span class="font-medium">Résultats détaillés</span>
<span class="ml-2 text-xs bg-indigo-100 text-indigo-800 px-2 py-1 rounded-full">1,245 éléments</span>
</div>
<div class="flex space-x-2">
<div class="relative">
<input type="text" placeholder="Rechercher..." class="pl-8 pr-3 py-1 border rounded-md text-sm focus:ring-indigo-500 focus:border-indigo-500">
<i class="fas fa-search absolute left-2.5 top-1/2 transform -translate-y-1/2 text-gray-400"></i>
</div>
<select class="border rounded-md text-sm focus:ring-indigo-500 focus:border-indigo-500">
<option>Trier par catégorie</option>
<option>Trier par confiance</option>
</select>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-100">
<tr>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Texte original</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Catégorie</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Confiance</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Actions</th>
</tr>
</thead>
<tbody id="resultsTable" class="bg-white divide-y divide-gray-200">
<!-- Sample row -->
<tr>
<td class="px-4 py-3 text-sm max-w-xs truncate">Ceci est un exemple de texte qui a été classifié dans la catégorie "Exemple"</td>
<td class="px-4 py-3">
<span class="px-2 py-1 bg-indigo-100 text-indigo-800 text-xs rounded-full">Exemple</span>
</td>
<td class="px-4 py-3">
<div class="flex items-center">
<div class="w-16 bg-gray-200 rounded-full h-1.5 mr-2">
<div class="bg-green-500 h-1.5 rounded-full" style="width: 95%"></div>
</div>
<span class="text-xs">95%</span>
</div>
</td>
<td class="px-4 py-3 text-sm">
<button class="text-indigo-600 hover:text-indigo-900 mr-2">
<i class="fas fa-edit"></i>
</button>
<button class="text-red-600 hover:text-red-900">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
<!-- More rows will be added here -->
</tbody>
</table>
</div>
<div class="bg-gray-50 px-4 py-3 border-t flex items-center justify-between">
<div class="text-sm text-gray-500">
Affichage de <span class="font-medium">1</span> à <span class="font-medium">10</span> sur <span class="font-medium">1,245</span> résultats
</div>
<div class="flex space-x-1">
<button class="px-3 py-1 border rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50">
Précédent
</button>
<button class="px-3 py-1 border rounded-md text-sm font-medium bg-indigo-600 text-white">
1
</button>
<button class="px-3 py-1 border rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50">
2
</button>
<button class="px-3 py-1 border rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50">
Suivant
</button>
</div>
</div>
</div>
<div class="flex justify-end mt-6">
<button id="finishBtn" class="px-6 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 transition">
Terminer <i class="fas fa-check ml-2"></i>
</button>
</div>
</div>
</div>
<!-- Help Section -->
<div class="mt-8 bg-indigo-50 rounded-xl p-6">
<div class="flex items-start">
<div class="flex-shrink-0">
<i class="fas fa-question-circle text-indigo-500 text-2xl"></i>
</div>
<div class="ml-4">
<h3 class="text-lg font-medium text-indigo-800">Besoin d'aide ?</h3>
<p class="mt-1 text-sm text-indigo-700">
Consultez notre <a href="#" class="font-medium underline">guide d'utilisation</a> ou contactez notre <a href="#" class="font-medium underline">support technique</a> pour toute question sur le processus de classification.
</p>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const steps = document.querySelectorAll('.step');
const stepContents = {
1: document.getElementById('step-1'),
2: document.getElementById('step-2'),
3: document.getElementById('step-3'),
4: document.getElementById('step-4')
};
const dropzone = document.getElementById('dropzone');
const fileInput = document.getElementById('fileInput');
const selectFileBtn = document.getElementById('selectFileBtn');
const filePreview = document.getElementById('filePreview');
const fileName = document.getElementById('fileName');
const fileSize = document.getElementById('fileSize');
const columnsList = document.getElementById('columnsList');
const removeFileBtn = document.getElementById('removeFileBtn');
const nextStep1 = document.getElementById('nextStep1');
const prevStep2 = document.getElementById('prevStep2');
const nextStep2 = document.getElementById('nextStep2');
const textColumnSelect = document.getElementById('textColumnSelect');
const classificationMethod = document.getElementById('classificationMethod');
const keywordsConfig = document.getElementById('keywordsConfig');
const aiConfig = document.getElementById('aiConfig');
const regexConfig = document.getElementById('regexConfig');
const categoriesContainer = document.getElementById('categoriesContainer');
const addCategoryBtn = document.getElementById('addCategoryBtn');
const progressText = document.getElementById('progressText');
const progressSubtext = document.getElementById('progressSubtext');
const progressBar = document.getElementById('progressBar');
const progressCircle = document.getElementById('progressCircle');
const progressDetails = document.getElementById('progressDetails');
const cancelProcessBtn = document.getElementById('cancelProcessBtn');
// Variables
let currentStep = 1;
let file = null;
// Initialize
updateStepIndicator();
// Event Listeners
selectFileBtn.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', handleFileSelect);
removeFileBtn.addEventListener('click', () => {
file = null;
filePreview.classList.add('hidden');
nextStep1.disabled = true;
fileInput.value = '';
});
dropzone.addEventListener('dragover', (e) => {
e.preventDefault();
dropzone.classList.add('active');
});
dropzone.addEventListener('dragleave', () => {
dropzone.classList.remove('active');
});
dropzone.addEventListener('drop', (e) => {
e.preventDefault();
dropzone.classList.remove('active');
if (e.dataTransfer.files.length) {
fileInput.files = e.dataTransfer.files;
handleFileSelect({ target: fileInput });
}
});
nextStep1.addEventListener('click', () => navigateToStep(2));
prevStep2.addEventListener('click', () => navigateToStep(1));
nextStep2.addEventListener('click', () => navigateToStep(3));
classificationMethod.addEventListener('change', updateClassificationMethodUI);
addCategoryBtn.addEventListener('click', addNewCategory);
// Delegated event listeners for dynamic elements
categoriesContainer.addEventListener('click', (e) => {
// Remove category
if (e.target.closest('.remove-category')) {
e.target.closest('.category-group').remove();
checkStep2Completion();
}
// Remove keyword
if (e.target.closest('.remove-keyword')) {
e.target.closest('.keyword-chip').remove();
}
});
categoriesContainer.addEventListener('keydown', (e) => {
// Add keyword on Enter
if (e.target.classList.contains('keyword-input') && e.key === 'Enter' && e.target.value.trim()) {
const keyword = e.target.value.trim();
const keywordChip = document.createElement('div');
keywordChip.className = 'keyword-chip flex items-center bg-white px-3 py-1 rounded-full text-sm shadow-sm';
keywordChip.innerHTML = `
<span>${keyword}</span>
<button class="remove-keyword ml-1 text-gray-400 hover:text-red-500">
<i class="fas fa-times text-xs"></i>
</button>
`;
e.target.before(keywordChip);
e.target.value = '';
checkStep2Completion();
}
// Check completion on category name change
if (e.target.classList.contains('category-name')) {
setTimeout(checkStep2Completion, 0);
}
});
// Functions
function handleFileSelect(event) {
file = event.target.files[0];
if (!file) return;
fileName.textContent = file.name;
fileSize.textContent = formatFileSize(file.size);
// Simulate reading file columns (in a real app, you'd parse the file)
const simulatedColumns = ['ID', 'Texte', 'Date', 'Auteur', 'Référence'];
columnsList.innerHTML = simulatedColumns.map(col => `
<tr>
<td class="px-4 py-2 whitespace-nowrap text-sm font-medium text-gray-900">${col}</td>
</tr>
`).join('');
filePreview.classList.remove('hidden');
nextStep1.disabled = false;
// Populate column select for step 2
textColumnSelect.innerHTML = '<option value="">Sélectionnez une colonne</option>' +
simulatedColumns.map(col => `<option value="${col}">${col}</option>`).join('');
}
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
function navigateToStep(step) {
// Validation before leaving current step
if (currentStep === 2 && step === 3 && !validateStep2()) {
return;
}
// Special handling for step 3 (processing)
if (step === 3) {
startProcessing();
}
// Hide current step
stepContents[currentStep].classList.add('hidden');
// Show new step
stepContents[step].classList.remove('hidden');
stepContents[step].classList.add('fade-in');
// Update current step
currentStep = step;
updateStepIndicator();
}
function updateStepIndicator() {
steps.forEach(step => {
const stepNum = parseInt(step.dataset.step);
const circle = step.querySelector('div');
const text = step.querySelector('p');
const line = step.querySelector('.absolute');
if (stepNum < currentStep) {
// Completed step
circle.classList.remove('bg-gray-200', 'text-gray-600');
circle.classList.add('bg-indigo-600', 'text-white');
text.classList.remove('text-gray-500');
text.classList.add('text-indigo-600');
line.classList.remove('bg-gray-200');
line.classList.add('bg-indigo-600');
} else if (stepNum === currentStep) {
// Current step
circle.classList.remove('bg-gray-200', 'text-gray-600');
circle.classList.add('bg-indigo-600', 'text-white');
text.classList.remove('text-gray-500');
text.classList.add('text-indigo-600');
line.classList.remove('bg-indigo-600');
line.classList.add('bg-gray-200');
} else {
// Future step
circle.classList.remove('bg-indigo-600', 'text-white');
circle.classList.add('bg-gray-200', 'text-gray-600');
text.classList.remove('text-indigo-600');
text.classList.add('text-gray-500');
line.classList.remove('bg-indigo-600');
line.classList.add('bg-gray-200');
}
});
}
function updateClassificationMethodUI() {
const method = classificationMethod.value;
keywordsConfig.classList.add('hidden');
aiConfig.classList.add('hidden');
regexConfig.classList.add('hidden');
if (method === 'keywords') {
keywordsConfig.classList.remove('hidden');
} else if (method === 'ai') {
aiConfig.classList.remove('hidden');
} else if (method === 'regex') {
regexConfig.classList.remove('hidden');
}
checkStep2Completion();
}
function addNewCategory() {
const categoryGroup = document.createElement('div');
categoryGroup.className = 'category-group border rounded-lg p-4 bg-gray-50';
categoryGroup.innerHTML = `
<div class="flex justify-between items-center mb-3">
<input type="text" placeholder="Nom de la catégorie" class="category-name flex-1 border-b border-gray-300 focus:border-indigo-500 focus:outline-none bg-transparent py-1">
<button class="remove-category text-red-500 hover:text-red-700 ml-2">
<i class="fas fa-trash"></i>
</button>
</div>
<div class="flex flex-wrap gap-2">
<input type="text" placeholder="Ajouter un mot-clé" class="keyword-input flex-1 min-w-[100px] border-b border-gray-300 focus:border-indigo-500 focus:outline-none bg-transparent py-1">
</div>
`;
categoriesContainer.appendChild(categoryGroup);
// Focus on the new category name input
categoryGroup.querySelector('.category-name').focus();
}
function checkStep2Completion() {
let isComplete = true;
// Check if text column is selected
if (!textColumnSelect.value) {
isComplete = false;
}
// Check if categories are properly defined (for keyword method)
if (classificationMethod.value === 'keywords') {
const categoryGroups = categoriesContainer.querySelectorAll('.category-group');
if (categoryGroups.length === 0) {
isComplete = false;
} else {
categoryGroups.forEach(group => {
const name = group.querySelector('.category-name').value.trim();
const keywords = group.querySelectorAll('.keyword-chip');
if (!name || keywords.length === 0) {
isComplete = false;
}
});
}
}
nextStep2.disabled = !isComplete;
}
function validateStep2() {
// In a real app, this would do more thorough validation
return !nextStep2.disabled;
}
function startProcessing() {
progressText.textContent = "Classification en cours...";
progressSubtext.textContent = "Analyse des données textuelles";
progressDetails.classList.add('hidden');
let progress = 0;
const interval = setInterval(() => {
progress += Math.random() * 5;
if (progress > 100) progress = 100;
progressBar.style.width = `${progress}%`;
progressCircle.style.strokeDashoffset = 283 * (1 - progress/100);
// Update progress details
if (progress > 30 && progress < 70) {
progressText.textContent = "Identification des catégories...";
progressSubtext.textContent = "Analyse des motifs récurrents";
} else if (progress >= 70) {
progressText.textContent = "Finalisation des résultats...";
progressSubtext.textContent = "Préparation des données pour l'affichage";
progressDetails.classList.remove('hidden');
document.getElementById('processedRows').textContent =
`${Math.floor(progress * 12.45)}/1245`;
document.getElementById('identifiedCategories').textContent =
`${Math.floor(progress / 15)}`;
document.getElementById('averageConfidence').textContent =
`${Math.min(95, Math.floor(70 + progress / 3))}%`;
}
if (progress === 100) {
clearInterval(interval);
setTimeout(() => {
navigateToStep(4);
}, 1000);
}
}, 300);
cancelProcessBtn.addEventListener('click', () => {
clearInterval(interval);
navigateToStep(2);
}, { once: true });
}
// Initialize step 2 validation
textColumnSelect.addEventListener('change', checkStep2Completion);
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=simondh/classifications" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>