wami / demo.html
Bgk Injector SqLi
Add interactive live demo page
9df0966
<!DOCTYPE html>
<html lang="fr" class="h-full">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wami - Demo Live</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="h-full bg-gradient-to-br from-slate-900 via-blue-900 to-slate-900">
<div class="min-h-full">
<!-- Header -->
<header class="bg-slate-800/50 backdrop-blur-sm border-b border-slate-700">
<div class="max-w-7xl mx-auto px-4 py-6 sm:px-6 lg:px-8">
<div class="flex items-center justify-between">
<div>
<h1 class="text-3xl font-bold text-white">🎙️ Wami - Demo Live</h1>
<p class="text-slate-300 mt-1">API Dioula STT, TTS & Traduction</p>
</div>
<a href="/docs" target="_blank" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition">
📖 API Docs
</a>
</div>
</div>
</header>
<!-- Main Content -->
<main class="max-w-7xl mx-auto px-4 py-8 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- STT Card -->
<div class="bg-slate-800/50 backdrop-blur-sm rounded-xl shadow-xl p-6 border border-slate-700">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center">
<span class="text-3xl mr-2">🎤</span> Speech-to-Text
</h2>
<p class="text-slate-300 mb-4">Enregistrez votre voix en Dioula</p>
<div class="space-y-4">
<button id="sttBtn" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-4 px-6 rounded-lg transition transform hover:scale-105 flex items-center justify-center gap-2">
<span id="sttBtnIcon">🎙️</span>
<span id="sttBtnText">Cliquer pour enregistrer</span>
</button>
<div id="sttStatus" class="text-sm text-slate-400 text-center min-h-6"></div>
<div id="sttResult" class="bg-slate-900/50 rounded-lg p-4 min-h-24 text-white hidden">
<div class="text-sm text-slate-400 mb-2">Transcription :</div>
<div id="sttText" class="text-lg"></div>
</div>
</div>
</div>
<!-- TTS Card -->
<div class="bg-slate-800/50 backdrop-blur-sm rounded-xl shadow-xl p-6 border border-slate-700">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center">
<span class="text-3xl mr-2">🔊</span> Text-to-Speech
</h2>
<p class="text-slate-300 mb-4">Générez un audio en Dioula</p>
<div class="space-y-4">
<textarea id="ttsInput" class="w-full bg-slate-900/50 text-white rounded-lg p-4 border border-slate-600 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 transition" rows="3" placeholder="Tapez du texte en Dioula..."></textarea>
<button id="ttsBtn" class="w-full bg-green-600 hover:bg-green-700 text-white font-semibold py-3 px-6 rounded-lg transition transform hover:scale-105">
🔊 Générer la voix
</button>
<div id="ttsStatus" class="text-sm text-slate-400 text-center min-h-6"></div>
<audio id="ttsAudio" controls class="w-full rounded-lg hidden"></audio>
</div>
</div>
<!-- Translation DYU→FR Card -->
<div class="bg-slate-800/50 backdrop-blur-sm rounded-xl shadow-xl p-6 border border-slate-700">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center">
<span class="text-3xl mr-2">🇲🇱</span> Dioula → Français
</h2>
<p class="text-slate-300 mb-4">Traduisez du Dioula vers le Français</p>
<div class="space-y-4">
<textarea id="dyuInput" class="w-full bg-slate-900/50 text-white rounded-lg p-4 border border-slate-600 focus:border-purple-500 focus:ring-2 focus:ring-purple-500 transition" rows="3" placeholder="Texte en Dioula..."></textarea>
<button id="dyuBtn" class="w-full bg-purple-600 hover:bg-purple-700 text-white font-semibold py-3 px-6 rounded-lg transition transform hover:scale-105">
→ Traduire en Français
</button>
<div id="dyuStatus" class="text-sm text-slate-400 text-center min-h-6"></div>
<div id="dyuResult" class="bg-slate-900/50 rounded-lg p-4 min-h-20 text-white hidden">
<div class="text-sm text-slate-400 mb-2">🇫🇷 Traduction française :</div>
<div id="dyuText" class="text-lg"></div>
</div>
</div>
</div>
<!-- Translation FR→DYU Card -->
<div class="bg-slate-800/50 backdrop-blur-sm rounded-xl shadow-xl p-6 border border-slate-700">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center">
<span class="text-3xl mr-2">🇫🇷</span> Français → Dioula
</h2>
<p class="text-slate-300 mb-4">Traduisez du Français vers le Dioula</p>
<div class="space-y-4">
<textarea id="frInput" class="w-full bg-slate-900/50 text-white rounded-lg p-4 border border-slate-600 focus:border-orange-500 focus:ring-2 focus:ring-orange-500 transition" rows="3" placeholder="Texte en Français..."></textarea>
<button id="frBtn" class="w-full bg-orange-600 hover:bg-orange-700 text-white font-semibold py-3 px-6 rounded-lg transition transform hover:scale-105">
→ Traduire en Dioula
</button>
<div id="frStatus" class="text-sm text-slate-400 text-center min-h-6"></div>
<div id="frResult" class="bg-slate-900/50 rounded-lg p-4 min-h-20 text-white hidden">
<div class="text-sm text-slate-400 mb-2">🇲🇱 Traduction dioula :</div>
<div id="frText" class="text-lg"></div>
</div>
</div>
</div>
</div>
<!-- Examples Section -->
<div class="mt-8 bg-slate-800/50 backdrop-blur-sm rounded-xl shadow-xl p-6 border border-slate-700">
<h3 class="text-xl font-bold text-white mb-4">💡 Exemples de phrases</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="bg-slate-900/50 p-4 rounded-lg">
<div class="text-sm text-slate-400 mb-1">Dioula:</div>
<div class="text-white">Sanji bɛna kɛ bi</div>
<div class="text-sm text-green-400 mt-2">→ Il pleuvra demain</div>
</div>
<div class="bg-slate-900/50 p-4 rounded-lg">
<div class="text-sm text-slate-400 mb-1">Dioula:</div>
<div class="text-white">Aw ka séné ninnge ma</div>
<div class="text-sm text-green-400 mt-2">→ Protégez vos récoltes</div>
</div>
<div class="bg-slate-900/50 p-4 rounded-lg">
<div class="text-sm text-slate-400 mb-1">Français:</div>
<div class="text-white">Bonjour, comment allez-vous?</div>
<div class="text-sm text-green-400 mt-2">→ I ni sɔgɔma, i ka kɛnɛya?</div>
</div>
<div class="bg-slate-900/50 p-4 rounded-lg">
<div class="text-sm text-slate-400 mb-1">Français:</div>
<div class="text-white">Le temps est beau aujourd'hui</div>
<div class="text-sm text-green-400 mt-2">→ Tile ka di bi</div>
</div>
</div>
</div>
</main>
</div>
<script>
// ========== STT ==========
const sttBtn = document.getElementById('sttBtn');
const sttBtnIcon = document.getElementById('sttBtnIcon');
const sttBtnText = document.getElementById('sttBtnText');
const sttStatus = document.getElementById('sttStatus');
const sttResult = document.getElementById('sttResult');
const sttText = document.getElementById('sttText');
let mediaRecorder = null;
let audioChunks = [];
let isRecording = false;
sttBtn.addEventListener('click', async () => {
if (!isRecording) {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' });
audioChunks = [];
mediaRecorder.ondataavailable = e => {
if (e.data.size > 0) audioChunks.push(e.data);
};
mediaRecorder.onstop = async () => {
stream.getTracks().forEach(t => t.stop());
const blob = new Blob(audioChunks, { type: 'audio/webm' });
await sendAudioToSTT(blob);
};
mediaRecorder.start();
isRecording = true;
sttBtn.classList.remove('bg-blue-600', 'hover:bg-blue-700');
sttBtn.classList.add('bg-red-600', 'hover:bg-red-700', 'animate-pulse');
sttBtnIcon.textContent = '🔴';
sttBtnText.textContent = 'Enregistrement... Cliquez pour arrêter';
} catch (err) {
sttStatus.textContent = '❌ Erreur : accès micro refusé';
sttStatus.classList.add('text-red-400');
}
} else {
mediaRecorder.stop();
isRecording = false;
sttBtn.classList.remove('bg-red-600', 'hover:bg-red-700', 'animate-pulse');
sttBtn.classList.add('bg-blue-600', 'hover:bg-blue-700');
sttBtnIcon.textContent = '🎙️';
sttBtnText.textContent = 'Cliquer pour enregistrer';
}
});
async function sendAudioToSTT(blob) {
sttStatus.textContent = '⏳ Transcription en cours...';
sttStatus.classList.remove('text-red-400');
sttStatus.classList.add('text-blue-400');
sttResult.classList.add('hidden');
const formData = new FormData();
formData.append('audio', blob, 'recording.wav');
try {
const res = await fetch('/api/stt', { method: 'POST', body: formData });
const data = await res.json();
sttText.textContent = data.transcription || 'Aucun résultat';
sttResult.classList.remove('hidden');
sttStatus.textContent = '✅ Transcription terminée';
sttStatus.classList.remove('text-blue-400');
sttStatus.classList.add('text-green-400');
} catch (err) {
sttStatus.textContent = '❌ Erreur : ' + err.message;
sttStatus.classList.remove('text-blue-400');
sttStatus.classList.add('text-red-400');
}
}
// ========== TTS ==========
const ttsBtn = document.getElementById('ttsBtn');
const ttsInput = document.getElementById('ttsInput');
const ttsStatus = document.getElementById('ttsStatus');
const ttsAudio = document.getElementById('ttsAudio');
ttsBtn.addEventListener('click', async () => {
const text = ttsInput.value.trim();
if (!text) {
ttsStatus.textContent = '⚠️ Veuillez entrer du texte';
ttsStatus.classList.add('text-yellow-400');
return;
}
ttsBtn.disabled = true;
ttsStatus.textContent = '⏳ Génération en cours...';
ttsStatus.classList.remove('text-yellow-400', 'text-red-400');
ttsStatus.classList.add('text-blue-400');
ttsAudio.classList.add('hidden');
const formData = new FormData();
formData.append('text', text);
try {
const res = await fetch('/api/tts', { method: 'POST', body: formData });
const blob = await res.blob();
const url = URL.createObjectURL(blob);
ttsAudio.src = url;
ttsAudio.classList.remove('hidden');
ttsAudio.play();
ttsStatus.textContent = '✅ Audio généré';
ttsStatus.classList.remove('text-blue-400');
ttsStatus.classList.add('text-green-400');
} catch (err) {
ttsStatus.textContent = '❌ Erreur : ' + err.message;
ttsStatus.classList.remove('text-blue-400');
ttsStatus.classList.add('text-red-400');
} finally {
ttsBtn.disabled = false;
}
});
// ========== Translation DYU→FR ==========
const dyuBtn = document.getElementById('dyuBtn');
const dyuInput = document.getElementById('dyuInput');
const dyuStatus = document.getElementById('dyuStatus');
const dyuResult = document.getElementById('dyuResult');
const dyuText = document.getElementById('dyuText');
dyuBtn.addEventListener('click', async () => {
const text = dyuInput.value.trim();
if (!text) {
dyuStatus.textContent = '⚠️ Veuillez entrer du texte';
dyuStatus.classList.add('text-yellow-400');
return;
}
dyuBtn.disabled = true;
dyuStatus.textContent = '⏳ Traduction en cours...';
dyuStatus.classList.remove('text-yellow-400', 'text-red-400');
dyuStatus.classList.add('text-blue-400');
dyuResult.classList.add('hidden');
const formData = new FormData();
formData.append('text', text);
try {
const res = await fetch('/api/translate/dyu-fr', { method: 'POST', body: formData });
const data = await res.json();
dyuText.textContent = data.texte_traduit;
dyuResult.classList.remove('hidden');
dyuStatus.textContent = '✅ Traduction terminée';
dyuStatus.classList.remove('text-blue-400');
dyuStatus.classList.add('text-green-400');
} catch (err) {
dyuStatus.textContent = '❌ Erreur : ' + err.message;
dyuStatus.classList.remove('text-blue-400');
dyuStatus.classList.add('text-red-400');
} finally {
dyuBtn.disabled = false;
}
});
// ========== Translation FR→DYU ==========
const frBtn = document.getElementById('frBtn');
const frInput = document.getElementById('frInput');
const frStatus = document.getElementById('frStatus');
const frResult = document.getElementById('frResult');
const frText = document.getElementById('frText');
frBtn.addEventListener('click', async () => {
const text = frInput.value.trim();
if (!text) {
frStatus.textContent = '⚠️ Veuillez entrer du texte';
frStatus.classList.add('text-yellow-400');
return;
}
frBtn.disabled = true;
frStatus.textContent = '⏳ Traduction en cours...';
frStatus.classList.remove('text-yellow-400', 'text-red-400');
frStatus.classList.add('text-blue-400');
frResult.classList.add('hidden');
const formData = new FormData();
formData.append('text', text);
try {
const res = await fetch('/api/translate/fr-dyu', { method: 'POST', body: formData });
const data = await res.json();
frText.textContent = data.texte_traduit;
frResult.classList.remove('hidden');
frStatus.textContent = '✅ Traduction terminée';
frStatus.classList.remove('text-blue-400');
frStatus.classList.add('text-green-400');
} catch (err) {
frStatus.textContent = '❌ Erreur : ' + err.message;
frStatus.classList.remove('text-blue-400');
frStatus.classList.add('text-red-400');
} finally {
frBtn.disabled = false;
}
});
</script>
</body>
</html>