lahjabot2 / index.html
wasmdashai's picture
Update index.html
c784037 verified
raw
history blame
23.6 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VoiceBridge - Saudi Dialect Speech Translator</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>
@import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&family=Poppins:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Poppins', 'Tajawal', sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
}
.gradient-bg {
background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%);
}
.wave-animation {
position: relative;
overflow: hidden;
}
.wave-animation::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 20px;
background: url('data:image/svg+xml;utf8,<svg viewBox="0 0 1200 120" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none"><path d="M0,0V46.29c47.79,22.2,103.59,32.17,158,28,70.36-5.37,136.33-33.31,206.8-37.5C438.64,32.43,512.34,53.67,583,72.05c69.27,18,138.3,24.88,209.4,13.08,36.15-6,69.85-17.84,104.45-29.34C989.49,25,1113-14.29,1200,52.47V0Z" fill="%23ffffff" opacity=".25"/><path d="M0,0V15.81C13,36.92,27.64,56.86,47.69,72.05,99.41,111.27,165,111,224.58,91.58c31.15-10.15,60.09-26.07,89.67-39.8,40.92-19,84.73-46,130.83-49.67,36.26-2.85,70.9,9.42,98.6,31.56,31.77,25.39,62.32,62,103.63,73,40.44,10.79,81.35-6.69,119.13-24.28s75.16-39,116.92-43.05c59.73-5.85,113.28,22.88,168.9,38.84,30.2,8.66,59,6.17,87.09-7.5,22.43-10.89,48-26.93,60.65-49.24V0Z" fill="%23ffffff" opacity=".5"/><path d="M0,0V5.63C149.93,59,314.09,71.32,475.83,42.57c43-7.64,84.23-20.12,127.61-26.46,59-8.63,112.48,12.24,165.56,35.4C827.93,77.22,886,95.24,951.2,90c86.53-7,172.46-45.71,248.8-84.81V0Z" fill="%23ffffff"/></svg>');
background-size: cover;
z-index: 10;
}
.pulse {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba(30, 58, 138, 0.7);
}
70% {
transform: scale(1);
box-shadow: 0 0 0 10px rgba(30, 58, 138, 0);
}
100% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba(30, 58, 138, 0);
}
}
.language-selector {
transition: all 0.3s ease;
}
.language-selector:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.voice-visualizer {
height: 60px;
display: flex;
align-items: flex-end;
justify-content: center;
gap: 3px;
}
.voice-bar {
width: 4px;
background-color: #1e3a8a;
border-radius: 3px;
animation: equalize 1.5s infinite ease-in-out;
}
@keyframes equalize {
0%, 100% { height: 10%; }
50% { height: 100%; }
}
.voice-bar:nth-child(1) { animation-delay: -0.9s; }
.voice-bar:nth-child(2) { animation-delay: -0.6s; }
.voice-bar:nth-child(3) { animation-delay: -0.3s; }
.voice-bar:nth-child(4) { animation-delay: -0.6s; }
.voice-bar:nth-child(5) { animation-delay: -0.9s; }
.result-card {
transition: all 0.3s ease;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.result-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
}
.rtl-text {
direction: rtl;
text-align: right;
font-family: 'Tajawal', sans-serif;
}
.dialect-badge {
background-color: #fef3c7;
color: #92400e;
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
border-radius: 9999px;
margin-left: 0.5rem;
}
</style>
</head>
<body class="min-h-screen flex flex-col">
<!-- Header -->
<header class="gradient-bg text-white wave-animation">
<div class="container mx-auto px-4 py-8">
<div class="flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fas fa-language text-3xl"></i>
<h1 class="text-2xl md:text-3xl font-bold">VoiceBridge</h1>
</div>
<div class="flex items-center space-x-4">
<button class="bg-white text-blue-900 px-4 py-2 rounded-full font-medium hover:bg-blue-50 transition">
<i class="fas fa-cog mr-2"></i>Settings
</button>
</div>
</div>
<div class="mt-12 mb-16 text-center">
<h2 class="text-3xl md:text-4xl font-bold mb-4">Saudi Dialect Speech Translator</h2>
<p class="text-xl opacity-90 max-w-2xl mx-auto">AI-powered translation with support for Saudi dialects and regional accents</p>
</div>
</div>
</header>
<!-- Main Content -->
<main class="flex-grow container mx-auto px-4 py-8 -mt-10">
<div class="bg-white rounded-xl shadow-xl overflow-hidden">
<div class="grid md:grid-cols-2 gap-6 p-6">
<!-- Input Section -->
<div class="space-y-6">
<div class="flex justify-between items-center">
<h3 class="text-xl font-semibold text-gray-800">Speak Now</h3>
<div class="flex items-center space-x-2">
<span class="text-sm text-gray-500">Input Language:</span>
<select id="inputLanguage" class="border rounded px-3 py-1 text-sm">
<option value="ar-SA">Arabic (Standard)</option>
<option value="ar-SA-najdi">Arabic (Najdi)</option>
<option value="ar-SA-hejazi">Arabic (Hejazi)</option>
<option value="ar-SA-gulf">Arabic (Gulf)</option>
<option value="en-US">English</option>
<option value="fr-FR">French</option>
<option value="es-ES">Spanish</option>
</select>
</div>
</div>
<div class="bg-gray-50 rounded-lg p-6 text-center">
<div id="voiceInputVisualizer" class="voice-visualizer mb-6">
<div class="voice-bar"></div>
<div class="voice-bar"></div>
<div class="voice-bar"></div>
<div class="voice-bar"></div>
<div class="voice-bar"></div>
</div>
<button id="startListening" class="bg-blue-900 text-white rounded-full p-4 pulse hover:bg-blue-800 transition">
<i class="fas fa-microphone text-2xl"></i>
</button>
<p id="listeningStatus" class="mt-4 text-gray-600">Press the microphone to start speaking</p>
</div>
<div class="result-card bg-gray-50 rounded-lg p-4">
<h4 class="font-medium text-gray-700 mb-2">Your Speech</h4>
<div id="inputText" class="min-h-20 p-3 bg-white rounded border border-gray-200">
<p class="text-gray-500 italic">Recognized text will appear here...</p>
</div>
</div>
</div>
<!-- Output Section -->
<div class="space-y-6">
<div class="flex justify-between items-center">
<h3 class="text-xl font-semibold text-gray-800">Translation</h3>
<div class="flex items-center space-x-2">
<span class="text-sm text-gray-500">Output Language:</span>
<select id="outputLanguage" class="border rounded px-3 py-1 text-sm">
<option value="ar-SA">Arabic (Standard)</option>
<option value="ar-SA-najdi">Arabic (Najdi)</option>
<option value="ar-SA-hejazi">Arabic (Hejazi)</option>
<option value="ar-SA-gulf">Arabic (Gulf)</option>
<option value="en-US">English</option>
<option value="fr-FR">French</option>
<option value="es-ES">Spanish</option>
</select>
</div>
</div>
<div class="result-card bg-gray-50 rounded-lg p-4">
<h4 class="font-medium text-gray-700 mb-2">Translated Text</h4>
<div id="outputText" class="min-h-20 p-3 bg-white rounded border border-gray-200">
<p class="text-gray-500 italic">Translation will appear here...</p>
</div>
</div>
<div class="bg-gray-50 rounded-lg p-6 text-center">
<div id="voiceOutputVisualizer" class="voice-visualizer mb-6 opacity-0">
<div class="voice-bar bg-blue-700"></div>
<div class="voice-bar bg-blue-700"></div>
<div class="voice-bar bg-blue-700"></div>
<div class="voice-bar bg-blue-700"></div>
<div class="voice-bar bg-blue-700"></div>
</div>
<button id="playTranslation" class="bg-blue-900 text-white rounded-full px-6 py-3 hover:bg-blue-800 transition disabled:opacity-50" disabled>
<i class="fas fa-volume-up mr-2"></i> Play Translation
</button>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="bg-gray-100 px-6 py-4 border-t border-gray-200 flex justify-between items-center">
<button id="clearAll" class="text-gray-600 hover:text-gray-800 transition">
<i class="fas fa-trash-alt mr-2"></i> Clear All
</button>
<div class="flex space-x-3">
<button id="copyTranslation" class="bg-white border border-gray-300 rounded-full px-4 py-2 text-sm hover:bg-gray-50 transition">
<i class="fas fa-copy mr-2"></i> Copy
</button>
<button id="saveSession" class="bg-white border border-gray-300 rounded-full px-4 py-2 text-sm hover:bg-gray-50 transition">
<i class="fas fa-save mr-2"></i> Save
</button>
<button id="shareTranslation" class="bg-blue-900 text-white rounded-full px-4 py-2 text-sm hover:bg-blue-800 transition">
<i class="fas fa-share-alt mr-2"></i> Share
</button>
</div>
</div>
</div>
<!-- Recent Translations -->
<div class="mt-10">
<h3 class="text-xl font-semibold text-gray-800 mb-4">Recent Translations</h3>
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
<div class="bg-white rounded-lg p-4 shadow border border-gray-100">
<div class="flex justify-between items-start mb-2">
<span class="text-sm font-medium text-blue-900 bg-blue-50 px-2 py-1 rounded">Najdi → English <span class="dialect-badge">Saudi</span></span>
<span class="text-xs text-gray-500">2 min ago</span>
</div>
<p class="rtl-text text-gray-700 mb-2">وش السالفة؟</p>
<p class="text-gray-900 font-medium">What's up?</p>
</div>
<div class="bg-white rounded-lg p-4 shadow border border-gray-100">
<div class="flex justify-between items-start mb-2">
<span class="text-sm font-medium text-blue-900 bg-blue-50 px-2 py-1 rounded">Hejazi → French <span class="dialect-badge">Saudi</span></span>
<span class="text-xs text-gray-500">15 min ago</span>
</div>
<p class="rtl-text text-gray-700 mb-2">وين المحل هذا؟</p>
<p class="text-gray-900 font-medium">Où est ce magasin?</p>
</div>
<div class="bg-white rounded-lg p-4 shadow border border-gray-100 hidden md:block">
<div class="flex justify-between items-start mb-2">
<span class="text-sm font-medium text-blue-900 bg-blue-50 px-2 py-1 rounded">English → Gulf <span class="dialect-badge">Saudi</span></span>
<span class="text-xs text-gray-500">1 hour ago</span>
</div>
<p class="text-gray-700 mb-2">How much does this cost?</p>
<p class="rtl-text text-gray-900 font-medium">بكم هذا؟</p>
</div>
</div>
</div>
<!-- Dialect Information -->
<div class="mt-10 bg-white rounded-xl shadow-md p-6">
<h3 class="text-xl font-semibold text-gray-800 mb-4">Supported Saudi Dialects</h3>
<div class="grid md:grid-cols-3 gap-6">
<div class="border border-gray-200 rounded-lg p-4">
<div class="flex items-center mb-2">
<div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-3">
<i class="fas fa-map-marker-alt text-blue-900"></i>
</div>
<h4 class="font-medium text-gray-800">Najdi Dialect</h4>
</div>
<p class="text-gray-600 text-sm">Spoken in central Saudi Arabia including Riyadh. Characterized by its distinctive pronunciation and vocabulary.</p>
</div>
<div class="border border-gray-200 rounded-lg p-4">
<div class="flex items-center mb-2">
<div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-3">
<i class="fas fa-umbrella-beach text-blue-900"></i>
</div>
<h4 class="font-medium text-gray-800">Hejazi Dialect</h4>
</div>
<p class="text-gray-600 text-sm">Spoken in western Saudi Arabia (Jeddah, Mecca, Medina). Influenced by historical trade routes and diverse populations.</p>
</div>
<div class="border border-gray-200 rounded-lg p-4">
<div class="flex items-center mb-2">
<div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-3">
<i class="fas fa-water text-blue-900"></i>
</div>
<h4 class="font-medium text-gray-800">Gulf Dialect</h4>
</div>
<p class="text-gray-600 text-sm">Spoken in eastern Saudi Arabia (Dammam, Khobar). Shares similarities with dialects from neighboring Gulf countries.</p>
</div>
</div>
</div>
</main>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-8">
<div class="container mx-auto px-4">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="mb-4 md:mb-0">
<div class="flex items-center space-x-2">
<i class="fas fa-language text-2xl"></i>
<h2 class="text-xl font-bold">VoiceBridge</h2>
</div>
<p class="text-gray-400 mt-2">Specialized in Saudi dialects and regional accents</p>
</div>
<div class="flex space-x-6">
<a href="#" class="text-gray-400 hover:text-white transition">
<i class="fab fa-twitter"></i>
</a>
<a href="#" class="text-gray-400 hover:text-white transition">
<i class="fab fa-instagram"></i>
</a>
<a href="#" class="text-gray-400 hover:text-white transition">
<i class="fab fa-youtube"></i>
</a>
</div>
</div>
<div class="border-t border-gray-700 mt-8 pt-8 text-center text-gray-400 text-sm">
<p>© 2023 VoiceBridge Saudi. All rights reserved.</p>
</div>
</div>
</footer>
<script>
// DOM Elements
const startListeningBtn = document.getElementById('startListening');
const listeningStatus = document.getElementById('listeningStatus');
const inputText = document.getElementById('inputText');
const outputText = document.getElementById('outputText');
const playTranslationBtn = document.getElementById('playTranslation');
const voiceInputVisualizer = document.getElementById('voiceInputVisualizer');
const voiceOutputVisualizer = document.getElementById('voiceOutputVisualizer');
const inputLanguage = document.getElementById('inputLanguage');
const outputLanguage = document.getElementById('outputLanguage');
const clearAllBtn = document.getElementById('clearAll');
const copyTranslationBtn = document.getElementById('copyTranslation');
const saveSessionBtn = document.getElementById('saveSession');
const shareTranslationBtn = document.getElementById('shareTranslation');
// Speech Recognition and Synthesis
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const synth = window.speechSynthesis;
let recognition;
let isListening = false;
// Initialize Speech Recognition
if (SpeechRecognition) {
recognition = new SpeechRecognition();
recognition.continuous = false;
recognition.interimResults = true;
recognition.onstart = () => {
isListening = true;
startListeningBtn.classList.add('bg-red-600', 'pulse');
startListeningBtn.classList.remove('bg-blue-900');
listeningStatus.textContent = "Listening... Speak now";
voiceInputVisualizer.classList.add('opacity-100');
};
recognition.onend = () => {
isListening = false;
startListeningBtn.classList.remove('bg-red-600', 'pulse');
startListeningBtn.classList.add('bg-blue-900');
listeningStatus.textContent = "Press the microphone to start speaking";
voiceInputVisualizer.classList.remove('opacity-100');
};
recognition.onresult = (event) => {
const transcript = Array.from(event.results)
.map(result => result[0])
.map(result => result.transcript)
.join('');
// Check if Arabic dialect is selected
const isArabicDialect = inputLanguage.value.includes('ar-SA');
if (isArabicDialect) {
inputText.innerHTML = `<p class="rtl-text text-gray-800">${transcript}</p>`;
} else {
inputText.innerHTML = `<p class="text-gray-800">${transcript}</p>`;
}
if (event.results[0].isFinal) {
// Simulate translation (in a real app, this would call a translation API)
const translatedText = simulateTranslation(transcript, inputLanguage.value, outputLanguage.value);
// Check if output is Arabic dialect
const isOutputArabic = outputLanguage.value.includes('ar-SA');
if (isOutputArabic) {
outputText.innerHTML = `<p class="rtl-text text-gray-800 font-medium">${translatedText}</p>`;
} else {
outputText.innerHTML = `<p class="text-gray-800 font-medium">${translatedText}</p>`;
}
playTranslationBtn.disabled = false;
}
};
recognition.onerror = (event) => {
console.error('Speech recognition error', event.error);
listeningStatus.textContent = `Error: ${event.error}`;
};
} else {
listeningStatus.textContent = "Speech recognition not supported in your browser";
startListeningBtn.disabled = true;
}
// Event Listeners
startListeningBtn.addEventListener('click', () => {
if (!isListening) {
// Set language for recognition (standard Arabic for all dialects)
recognition.lang = 'ar-SA';
recognition.start();
} else {
recognition.stop();
}
});
playTranslationBtn.addEventListener('click', () => {
if (outputText.textContent && outputText.textContent !== "Translation will appear here...") {
const utterance = new SpeechSynthesisUtterance(outputText.textContent);
// Set language for synthesis (standard Arabic for all dialects)
utterance.lang = outputLanguage.value.includes('ar-SA') ? 'ar-SA' : outputLanguage.value;
// Show visualizer while speaking
voiceOutputVisualizer.classList.remove('opacity-0');
voiceOutputVisualizer.classList.add('opacity-100');
utterance.onend = () => {
voiceOutputVisualizer.classList.add('opacity-0');
voiceOutputVisualizer.classList.remove('opacity-100');
};
synth.speak(utterance);
}
});
clearAllBtn.addEventListener('click', () => {
inputText.innerHTML = '<
</html>