wasmdashai commited on
Commit
b59faa2
·
verified ·
1 Parent(s): ac86053

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>LAHJA AI - Voice Assistant</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=Poppins:wght@300;400;500;600;700&display=swap'); body { font-family: 'Poppins', sans-serif; background: linear-gradient(135deg, #1a1a2e, #16213e); color: #fff; height: 100vh; overflow: hidden; } .chat-container { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border-radius: 20px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.1); } .message-bubble { max-width: 80%; padding: 12px 18px; border-radius: 20px; margin-bottom: 12px; position: relative; animation: fadeIn 0.3s ease-out; } .user-message { background: linear-gradient(135deg, #4e54c8, #8f94fb); align-self: flex-end; border-bottom-right-radius: 5px; } .ai-message { background: rgba(255, 255, 255, 0.15); align-self: flex-start; border-bottom-left-radius: 5px; } .pulse { animation: pulse 1.5s infinite; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .waveform { display: flex; align-items: center; height: 40px; gap: 3px; } .waveform-bar { background: rgba(255, 255, 255, 0.7); width: 4px; border-radius: 2px; animation: equalize 1.5s infinite ease-in-out; } @keyframes equalize { 0%, 100% { height: 10px; } 50% { height: 20px; } } .waveform-bar:nth-child(1) { animation-delay: -0.9s; } .waveform-bar:nth-child(2) { animation-delay: -0.7s; } .waveform-bar:nth-child(3) { animation-delay: -0.5s; } .waveform-bar:nth-child(4) { animation-delay: -0.3s; } .waveform-bar:nth-child(5) { animation-delay: -0.1s; } .typing-indicator { display: flex; align-items: center; gap: 5px; } .typing-dot { width: 8px; height: 8px; background: rgba(255, 255, 255, 0.7); border-radius: 50%; animation: typingAnimation 1.4s infinite ease-in-out; } .typing-dot:nth-child(1) { animation-delay: 0s; } .typing-dot:nth-child(2) { animation-delay: 0.2s; } .typing-dot:nth-child(3) { animation-delay: 0.4s; } @keyframes typingAnimation { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-5px); } } .scrollbar-hide::-webkit-scrollbar { display: none; } .scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; } </style> </head> <body class="flex items-center justify-center p-4"> <div class="chat-container w-full max-w-2xl h-[80vh] flex flex-col"> <!-- Header --> <div class="p-4 border-b border-gray-700 flex items-center justify-between"> <div class="flex items-center gap-3"> <div class="w-10 h-10 rounded-full bg-gradient-to-r from-purple-500 to-blue-500 flex items-center justify-center"> <i class="fas fa-robot text-white"></i> </div> <div> <h2 class="font-semibold">Voice Assistant</h2> <p class="text-xs text-gray-300">Powered by ChatGPT</p> </div> </div> <div class="flex items-center gap-2"> <button id="settings-btn" class="p-2 rounded-full hover:bg-gray-700 transition"> <i class="fas fa-cog text-gray-300"></i> </button> </div> </div> <!-- Chat Messages --> <div id="chat-messages" class="flex-1 p-4 overflow-y-auto scrollbar-hide flex flex-col"> <!-- Initial welcome message --> <div class="message-bubble ai-message"> <p>مرحباً! أنا مساعدك الصوتي الذكي. اضغط على زر الميكروفون لبدء المحادثة معي.</p> </div> </div> <!-- Input Area --> <div class="p-4 border-t border-gray-700"> <div class="flex items-center gap-2"> <button id="voice-btn" class="w-14 h-14 rounded-full bg-gradient-to-r from-purple-600 to-blue-500 flex items-center justify-center text-white hover:from-purple-700 hover:to-blue-600 transition-all shadow-lg pulse"> <i class="fas fa-microphone text-xl"></i> </button> <div class="flex-1 bg-gray-700 rounded-full px-4 py-2 flex items-center justify-between"> <p id="voice-status" class="text-sm text-gray-300">اضغط على الميكروفون للتحدث</p> <div id="waveform" class="waveform hidden"> <div class="waveform-bar"></div> <div class="waveform-bar"></div> <div class="waveform-bar"></div> <div class="waveform-bar"></div> <div class="waveform-bar"></div> </div> </div> </div> </div> </div> <!-- Settings Modal --> <div id="settings-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> <div class="bg-gray-800 rounded-xl p-6 w-full max-w-md"> <div class="flex justify-between items-center mb-4"> <h3 class="text-xl font-semibold">الإعدادات</h3> <button id="close-settings" class="text-gray-400 hover:text-white"> <i class="fas fa-times"></i> </button> </div> <div class="space-y-4"> <div> <label class="block text-sm font-medium mb-1">Voice Model</label> <select id="voiceSelect" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-3 py-2 text-white"> <option value="SA2">Najdi Arabic Haba v2</option> <option value="us">American English</option> <option value="SA1">Najdi Arabic Haba v1</option> <option value="SA3">Najdi Arabic AHmmed v1</option> </select> </div> <div> <label class="block text-sm font-medium mb-1">نبرة الصوت</label> <select class="w-full bg-gray-700 border border-gray-600 rounded-lg px-3 py-2 text-white"> <option>ذكر</option> <option>أنثى</option> </select> </div> <div> <label class="block text-sm font-medium mb-1">سرعة الصوت</label> <input type="range" min="0.5" max="2" step="0.1" value="1" class="w-full"> </div> </div> <div class="mt-6 flex justify-end gap-3"> <button id="save-settings" class="px-4 py-2 bg-blue-600 rounded-lg hover:bg-blue-700 transition"> حفظ الإعدادات </button> </div> </div> </div> <script type="module"> import {Client} from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js"; // DOM Elements const voiceBtn = document.getElementById('voice-btn'); const voiceStatus = document.getElementById('voice-status'); const waveform = document.getElementById('waveform'); const chatMessages = document.getElementById('chat-messages'); const settingsBtn = document.getElementById('settings-btn'); const settingsModal = document.getElementById('settings-modal'); const closeSettings = document.getElementById('close-settings'); const saveSettings = document.getElementById('save-settings'); // Speech recognition setup const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; const recognition = new SpeechRecognition(); recognition.lang = 'ar-SA'; recognition.interimResults = false; recognition.maxAlternatives = 1; // Speech synthesis setup const synth = window.speechSynthesis; // VITS Model Integration const voiceModels = { 'us': 'wasmdashai/vits-en-v1', 'SA1': 'wasmdashai/vits-ar-sa-huba-v1', 'SA2': 'wasmdashai/vits-ar-sa-huba-v2', 'SA3': 'wasmdashai/vits-ar-sa-A', }; // State variables let isListening = false; let conversationHistory = []; // Event Listeners voiceBtn.addEventListener('click', toggleVoiceRecognition); settingsBtn.addEventListener('click', () => settingsModal.classList.remove('hidden')); closeSettings.addEventListener('click', () => settingsModal.classList.add('hidden')); saveSettings.addEventListener('click', saveSettingsHandler); // Functions function toggleVoiceRecognition() { if (isListening) { stopListening(); } else { startListening(); } } function startListening() { isListening = true; voiceBtn.classList.add('animate-pulse'); voiceBtn.innerHTML = '<i class="fas fa-stop text-xl"></i>'; voiceStatus.textContent = 'أنا أستمع لك...'; waveform.classList.remove('hidden'); try { recognition.start(); } catch (e) { console.error('Error starting recognition:', e); stopListening(); } } function stopListening() { isListening = false; voiceBtn.classList.remove('animate-pulse'); voiceBtn.innerHTML = '<i class="fas fa-microphone text-xl"></i>'; voiceStatus.textContent = 'اضغط على الميكروفون للتحدث'; waveform.classList.add('hidden'); try { recognition.stop(); } catch (e) { console.error('Error stopping recognition:', e); } } function saveSettingsHandler() { // In a real app, you would save these settings to localStorage or a backend settingsModal.classList.add('hidden'); showSystemMessage('تم حفظ الإعدادات بنجاح'); } function showSystemMessage(text) { const messageDiv = document.createElement('div'); messageDiv.className = 'text-center text-xs text-gray-400 my-2'; messageDiv.textContent = text; chatMessages.appendChild(messageDiv); chatMessages.scrollTop = chatMessages.scrollHeight; } function addUserMessage(text) { const messageDiv = document.createElement('div'); messageDiv.className = 'message-bubble user-message'; messageDiv.innerHTML = `<p>${text}</p>`; chatMessages.appendChild(messageDiv); chatMessages.scrollTop = chatMessages.scrollHeight; } function addAiMessage(text) { const messageDiv = document.createElement('div'); messageDiv.className = 'message-bubble ai-message'; // Add typing indicator temporarily const typingDiv = document.createElement('div'); typingDiv.className = 'typing-indicator'; typingDiv.innerHTML = ` <div class="typing-dot"></div> <div class="typing-dot"></div> <div class="typing-dot"></div> `; messageDiv.appendChild(typingDiv); chatMessages.appendChild(messageDiv); chatMessages.scrollTop = chatMessages.scrollHeight; // Simulate AI thinking delay setTimeout(() => { typingDiv.remove(); messageDiv.innerHTML = `<p>${text}</p>`; speakResponse(text); }, 1500); } async function speakResponse(text) { const voiceSelect = document.getElementById('voiceSelect'); const voice = voiceSelect.value; try { const client = await Client.connect("wasmdashai/DemoLahja"); const result = await client.predict("/predict", { text: text, name_model: voiceModels[voice], speaking_rate: 1.0 }); const audioUrl = result.data?.[0]?.url; if (audioUrl) { const audio = new Audio(audioUrl); audio.play(); } else { fallbackTTS(text); } } catch (err) { console.error("VITS model error:", err); fallbackTTS(text); } } function fallbackTTS(text) { if (synth.speaking) { synth.cancel(); } const utterance = new SpeechSynthesisUtterance(text); utterance.lang = voiceSelect.value === 'us' ? 'en-US' : 'ar-SA'; utterance.rate = 1.0; synth.speak(utterance); } function processUserInput(text) { addUserMessage(text); conversationHistory.push({ role: 'user', content: text }); // In a real app, you would send this to your backend which connects to ChatGPT API // For this demo, we'll simulate a response simulateChatGPTResponse(text); } function simulateChatGPTResponse(userInput) { // This is a simulation - in a real app, you would call the ChatGPT API const responses = { "مرحبا": "مرحباً بك! كيف يمكنني مساعدتك اليوم؟", "السلام عليكم": "وعليكم السلام ورحمة الله وبركاته 🌹 كيف حالك؟", "كيف حالك": "أنا بخير، شكراً لسؤالك! كيف يمكنني مساعدتك؟", "ما هو اسمك": "أنا مساعدك الذكي الذي يعمل بالذكاء الاصطناعي. يمكنك تسميتي كما تحب!", "من صممك": "تم تطويري باستخدام تقنيات الذكاء الاصطناعي وخوارزميات التعلم الآلي.", "ماذا تستطيع ان تفعل": "أستطيع مساعدتك بالإجابة على أسئلة عامة، تقديم معلومات، ومساعدتك في بعض المهام اليومية.", "شكرا": "على الرحب والسعة! 🌸 هل هناك أي شيء آخر تحتاج مساعدتي فيه؟", "وداعا": "إلى اللقاء! 👋 لا تتردد في العودة إذا كنت بحاجة إلى أي مساعدة.", "ما هو تاريخ اليوم": `اليوم هو: ${new Date().toLocaleDateString("ar-EG")}`, "ما هو الوقت الان": `الوقت الآن هو: ${new Date().toLocaleTimeString("ar-EG")}`, "من اين انت": "أنا موجود في كل مكان 🌍 لأنني مساعد افتراضي على الإنترنت.", "ماهي عاصمه السعوديه": "عاصمة المملكة العربية السعودية هي الرياض.", "ماهي عاصمه اليمن": "عاصمة اليمن هي صنعاء.", "اعطني نصيحه": "✨ لا تؤجل عمل اليوم إلى الغد، وابدأ بخطوات صغيرة نحو هدفك." }; const defaultResponse = "أنا آسف، لم أفهم سؤالك بالكامل. هل يمكنك توضيح ذلك؟"; const response = responses[userInput.toLowerCase()] || defaultResponse; setTimeout(() => { addAiMessage(response); conversationHistory.push({ role: 'assistant', content: response }); }, 2000); } // Recognition event handlers recognition.onresult = (event) => { const speechResult = event.results[0][0].transcript; processUserInput(speechResult); stopListening(); }; recognition.onerror = (event) => { console.error('Speech recognition error', event.error); stopListening(); if (event.error === 'not-allowed') { showSystemMessage('يجب السماح باستخدام الميكروفون لتفعيل هذه الميزة'); } else { showSystemMessage('حدث خطأ في التعرف على الصوت. يرجى المحاولة مرة أخرى'); } }; recognition.onend = () => { if (isListening) { // If we're still supposed to be listening, restart recognition setTimeout(() => { try { recognition.start(); } catch (e) { console.error('Error restarting recognition:', e); stopListening(); } }, 500); } }; // Initialize voices when they become available if (speechSynthesis.onvoiceschanged !== undefined) { speechSynthesis.onvoiceschanged = () => { // Voices are now loaded }; } </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=wasmdashai/wasmdashai-chatlhja" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> </html> تشيغله - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +632 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Wasmdashai Wasmdashai Chatlhja
3
- emoji: 🐨
4
- colorFrom: red
5
- colorTo: yellow
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: wasmdashai-wasmdashai-chatlhja
3
+ emoji: 🐳
4
+ colorFrom: yellow
5
+ colorTo: purple
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,632 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ar" dir="rtl">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>LAHJA AI - مساعد صوتي ذكي</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ @import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@300;400;500;700&display=swap');
11
+
12
+ body {
13
+ font-family: 'Tajawal', sans-serif;
14
+ background: linear-gradient(135deg, #0f172a, #1e293b);
15
+ color: #fff;
16
+ min-height: 100vh;
17
+ }
18
+
19
+ .chat-container {
20
+ background: rgba(15, 23, 42, 0.8);
21
+ backdrop-filter: blur(10px);
22
+ border-radius: 1.5rem;
23
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
24
+ border: 1px solid rgba(255, 255, 255, 0.1);
25
+ }
26
+
27
+ .message-bubble {
28
+ max-width: 85%;
29
+ padding: 0.75rem 1.25rem;
30
+ border-radius: 1.25rem;
31
+ margin-bottom: 0.75rem;
32
+ position: relative;
33
+ animation: fadeIn 0.3s ease-out;
34
+ line-height: 1.6;
35
+ }
36
+
37
+ .user-message {
38
+ background: linear-gradient(135deg, #7c3aed, #6d28d9);
39
+ align-self: flex-end;
40
+ border-bottom-right-radius: 0.5rem;
41
+ color: white;
42
+ }
43
+
44
+ .ai-message {
45
+ background: rgba(255, 255, 255, 0.08);
46
+ align-self: flex-start;
47
+ border-bottom-left-radius: 0.5rem;
48
+ border: 1px solid rgba(255, 255, 255, 0.05);
49
+ }
50
+
51
+ .pulse {
52
+ animation: pulse 1.5s infinite;
53
+ }
54
+
55
+ @keyframes pulse {
56
+ 0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(124, 58, 237, 0.7); }
57
+ 70% { transform: scale(1.05); box-shadow: 0 0 0 10px rgba(124, 58, 237, 0); }
58
+ 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(124, 58, 237, 0); }
59
+ }
60
+
61
+ @keyframes fadeIn {
62
+ from { opacity: 0; transform: translateY(10px); }
63
+ to { opacity: 1; transform: translateY(0); }
64
+ }
65
+
66
+ .waveform {
67
+ display: flex;
68
+ align-items: center;
69
+ height: 2.5rem;
70
+ gap: 0.25rem;
71
+ justify-content: flex-end;
72
+ }
73
+
74
+ .waveform-bar {
75
+ background: rgba(255, 255, 255, 0.7);
76
+ width: 0.25rem;
77
+ border-radius: 0.25rem;
78
+ animation: equalize 1.5s infinite ease-in-out;
79
+ }
80
+
81
+ @keyframes equalize {
82
+ 0%, 100% { height: 0.5rem; }
83
+ 50% { height: 1.5rem; }
84
+ }
85
+
86
+ .waveform-bar:nth-child(1) { animation-delay: -0.9s; }
87
+ .waveform-bar:nth-child(2) { animation-delay: -0.7s; }
88
+ .waveform-bar:nth-child(3) { animation-delay: -0.5s; }
89
+ .waveform-bar:nth-child(4) { animation-delay: -0.3s; }
90
+ .waveform-bar:nth-child(5) { animation-delay: -0.1s; }
91
+
92
+ .typing-indicator {
93
+ display: flex;
94
+ align-items: center;
95
+ gap: 0.5rem;
96
+ padding: 0.5rem 0;
97
+ }
98
+
99
+ .typing-dot {
100
+ width: 0.5rem;
101
+ height: 0.5rem;
102
+ background: rgba(255, 255, 255, 0.7);
103
+ border-radius: 50%;
104
+ animation: typingAnimation 1.4s infinite ease-in-out;
105
+ }
106
+
107
+ .typing-dot:nth-child(1) { animation-delay: 0s; }
108
+ .typing-dot:nth-child(2) { animation-delay: 0.2s; }
109
+ .typing-dot:nth-child(3) { animation-delay: 0.4s; }
110
+
111
+ @keyframes typingAnimation {
112
+ 0%, 60%, 100% { transform: translateY(0); }
113
+ 30% { transform: translateY(-0.25rem); }
114
+ }
115
+
116
+ .scrollbar-hide::-webkit-scrollbar {
117
+ display: none;
118
+ }
119
+
120
+ .scrollbar-hide {
121
+ -ms-overflow-style: none;
122
+ scrollbar-width: none;
123
+ }
124
+
125
+ .modal-overlay {
126
+ background: rgba(0, 0, 0, 0.7);
127
+ }
128
+
129
+ .modal-content {
130
+ animation: modalFadeIn 0.3s ease-out;
131
+ }
132
+
133
+ @keyframes modalFadeIn {
134
+ from { opacity: 0; transform: translateY(20px); }
135
+ to { opacity: 1; transform: translateY(0); }
136
+ }
137
+
138
+ .voice-btn {
139
+ transition: all 0.3s ease;
140
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
141
+ }
142
+
143
+ .voice-btn:hover {
144
+ transform: translateY(-2px);
145
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
146
+ }
147
+
148
+ .voice-btn:active {
149
+ transform: translateY(0);
150
+ }
151
+
152
+ .language-badge {
153
+ font-size: 0.65rem;
154
+ padding: 0.15rem 0.5rem;
155
+ border-radius: 9999px;
156
+ background: rgba(255, 255, 255, 0.1);
157
+ border: 1px solid rgba(255, 255, 255, 0.2);
158
+ }
159
+
160
+ /* RTL specific styles */
161
+ [dir="rtl"] .message-bubble {
162
+ text-align: right;
163
+ }
164
+
165
+ [dir="rtl"] .ai-message {
166
+ margin-right: 1rem;
167
+ }
168
+
169
+ [dir="rtl"] .user-message {
170
+ margin-left: 1rem;
171
+ }
172
+
173
+ /* Dark mode toggle animation */
174
+ .toggle-circle {
175
+ transition: all 0.3s ease;
176
+ }
177
+
178
+ input:checked ~ .toggle-circle {
179
+ transform: translateX(1.25rem);
180
+ }
181
+ </style>
182
+ </head>
183
+ <body class="flex items-center justify-center p-4 md:p-6">
184
+ <div class="chat-container w-full max-w-2xl h-[85vh] md:h-[80vh] flex flex-col">
185
+ <!-- Header -->
186
+ <div class="p-4 border-b border-slate-700 flex items-center justify-between">
187
+ <div class="flex items-center gap-3">
188
+ <div class="w-10 h-10 rounded-full bg-gradient-to-r from-purple-600 to-blue-500 flex items-center justify-center shadow-md">
189
+ <i class="fas fa-robot text-white text-lg"></i>
190
+ </div>
191
+ <div>
192
+ <h2 class="font-bold text-lg">مساعد لُحْجَة الصوتي</h2>
193
+ <div class="flex items-center gap-2">
194
+ <span class="text-xs text-slate-300">مدعوم بالذكاء الاصطناعي</span>
195
+ <span class="language-badge">العربية</span>
196
+ </div>
197
+ </div>
198
+ </div>
199
+ <div class="flex items-center gap-2">
200
+ <button id="dark-mode-toggle" class="p-2 rounded-full hover:bg-slate-700 transition">
201
+ <i class="fas fa-moon text-slate-300"></i>
202
+ </button>
203
+ <button id="settings-btn" class="p-2 rounded-full hover:bg-slate-700 transition">
204
+ <i class="fas fa-cog text-slate-300"></i>
205
+ </button>
206
+ </div>
207
+ </div>
208
+
209
+ <!-- Chat Messages -->
210
+ <div id="chat-messages" class="flex-1 p-4 overflow-y-auto scrollbar-hide flex flex-col">
211
+ <!-- Initial welcome message -->
212
+ <div class="message-bubble ai-message">
213
+ <p>مرحباً بك! 👋 أنا مساعدك الصوتي الذكي "لُحْجَة". يمكنك التحدث معي بالضغط على زر الميكروفون أدناه.</p>
214
+ </div>
215
+ <div class="message-bubble ai-message">
216
+ <p>أنا أستطيع الإجابة على أسئلتك، تقديم المعلومات، وحتى إجراء محادثات ذكية معك. جرب أن تسألني عن أي شيء!</p>
217
+ </div>
218
+ </div>
219
+
220
+ <!-- Input Area -->
221
+ <div class="p-4 border-t border-slate-700">
222
+ <div class="flex items-center gap-2">
223
+ <button id="voice-btn" class="voice-btn w-14 h-14 rounded-full bg-gradient-to-r from-purple-600 to-blue-500 flex items-center justify-center text-white hover:from-purple-700 hover:to-blue-600 transition-all shadow-lg">
224
+ <i class="fas fa-microphone text-xl"></i>
225
+ </button>
226
+ <div class="flex-1 bg-slate-700 rounded-full px-4 py-2 flex items-center justify-between">
227
+ <p id="voice-status" class="text-sm text-slate-300">اضغط على الميكروفون للتحدث</p>
228
+ <div id="waveform" class="waveform hidden">
229
+ <div class="waveform-bar"></div>
230
+ <div class="waveform-bar"></div>
231
+ <div class="waveform-bar"></div>
232
+ <div class="waveform-bar"></div>
233
+ <div class="waveform-bar"></div>
234
+ </div>
235
+ </div>
236
+ <button id="keyboard-btn" class="w-12 h-12 rounded-full bg-slate-700 flex items-center justify-center text-slate-300 hover:bg-slate-600 transition">
237
+ <i class="fas fa-keyboard text-lg"></i>
238
+ </button>
239
+ </div>
240
+ </div>
241
+ </div>
242
+
243
+ <!-- Settings Modal -->
244
+ <div id="settings-modal" class="fixed inset-0 modal-overlay flex items-center justify-center hidden z-50 p-4">
245
+ <div class="bg-slate-800 rounded-xl p-6 w-full max-w-md modal-content">
246
+ <div class="flex justify-between items-center mb-4">
247
+ <h3 class="text-xl font-bold">إعدادات المساعد</h3>
248
+ <button id="close-settings" class="text-slate-400 hover:text-white p-1 rounded-full hover:bg-slate-700">
249
+ <i class="fas fa-times text-lg"></i>
250
+ </button>
251
+ </div>
252
+ <div class="space-y-4">
253
+ <div>
254
+ <label class="block text-sm font-medium mb-2">نموذج الصوت</label>
255
+ <select id="voiceSelect" class="w-full bg-slate-700 border border-slate-600 rounded-lg px-4 py-2 text-white focus:ring-2 focus:ring-purple-500 focus:border-transparent">
256
+ <option value="SA2">اللهجة النجدية - حصة v2</option>
257
+ <option value="us">الإنجليزية الأمريكية</option>
258
+ <option value="SA1">اللهجة النجدية - حصة v1</option>
259
+ <option value="SA3">اللهجة النجدية - أحمد v1</option>
260
+ </select>
261
+ </div>
262
+ <div>
263
+ <label class="block text-sm font-medium mb-2">نوع الصوت</label>
264
+ <select class="w-full bg-slate-700 border border-slate-600 rounded-lg px-4 py-2 text-white focus:ring-2 focus:ring-purple-500 focus:border-transparent">
265
+ <option>ذكر</option>
266
+ <option>أنثى</option>
267
+ </select>
268
+ </div>
269
+ <div>
270
+ <label class="block text-sm font-medium mb-2">سرعة الصوت</label>
271
+ <div class="flex items-center gap-3">
272
+ <span class="text-slate-300 text-sm">بطيء</span>
273
+ <input type="range" min="0.5" max="2" step="0.1" value="1" class="w-full h-2 bg-slate-600 rounded-lg appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-purple-500">
274
+ <span class="text-slate-300 text-sm">سريع</span>
275
+ </div>
276
+ </div>
277
+ <div class="pt-2">
278
+ <label class="inline-flex items-center cursor-pointer">
279
+ <input type="checkbox" value="" class="sr-only peer" checked>
280
+ <div class="relative w-11 h-6 bg-slate-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-purple-600"></div>
281
+ <span class="mr-3 text-sm font-medium text-slate-300">تفعيل الردود الصوتية</span>
282
+ </label>
283
+ </div>
284
+ </div>
285
+ <div class="mt-6 flex justify-end gap-3">
286
+ <button id="cancel-settings" class="px-4 py-2 bg-slate-700 rounded-lg hover:bg-slate-600 transition">
287
+ إلغاء
288
+ </button>
289
+ <button id="save-settings" class="px-4 py-2 bg-purple-600 rounded-lg hover:bg-purple-700 transition font-medium">
290
+ حفظ الإعدادات
291
+ </button>
292
+ </div>
293
+ </div>
294
+ </div>
295
+
296
+ <!-- Keyboard Input Modal -->
297
+ <div id="keyboard-modal" class="fixed inset-0 modal-overlay flex items-center justify-center hidden z-50 p-4">
298
+ <div class="bg-slate-800 rounded-xl p-6 w-full max-w-md modal-content">
299
+ <div class="flex justify-between items-center mb-4">
300
+ <h3 class="text-xl font-bold">اكتب رسالتك</h3>
301
+ <button id="close-keyboard" class="text-slate-400 hover:text-white p-1 rounded-full hover:bg-slate-700">
302
+ <i class="fas fa-times text-lg"></i>
303
+ </button>
304
+ </div>
305
+ <div class="mb-4">
306
+ <textarea id="text-input" class="w-full bg-slate-700 border border-slate-600 rounded-lg px-4 py-3 text-white h-32 focus:ring-2 focus:ring-purple-500 focus:border-transparent" placeholder="اكتب رسالتك هنا..."></textarea>
307
+ </div>
308
+ <div class="flex justify-end gap-3">
309
+ <button id="cancel-keyboard" class="px-4 py-2 bg-slate-700 rounded-lg hover:bg-slate-600 transition">
310
+ إلغاء
311
+ </button>
312
+ <button id="send-text" class="px-4 py-2 bg-purple-600 rounded-lg hover:bg-purple-700 transition font-medium">
313
+ إرسال
314
+ </button>
315
+ </div>
316
+ </div>
317
+ </div>
318
+
319
+ <script type="module">
320
+ import {Client} from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
321
+
322
+ // DOM Elements
323
+ const voiceBtn = document.getElementById('voice-btn');
324
+ const voiceStatus = document.getElementById('voice-status');
325
+ const waveform = document.getElementById('waveform');
326
+ const chatMessages = document.getElementById('chat-messages');
327
+ const settingsBtn = document.getElementById('settings-btn');
328
+ const settingsModal = document.getElementById('settings-modal');
329
+ const closeSettings = document.getElementById('close-settings');
330
+ const saveSettings = document.getElementById('save-settings');
331
+ const cancelSettings = document.getElementById('cancel-settings');
332
+ const keyboardBtn = document.getElementById('keyboard-btn');
333
+ const keyboardModal = document.getElementById('keyboard-modal');
334
+ const closeKeyboard = document.getElementById('close-keyboard');
335
+ const cancelKeyboard = document.getElementById('cancel-keyboard');
336
+ const sendText = document.getElementById('send-text');
337
+ const textInput = document.getElementById('text-input');
338
+ const darkModeToggle = document.getElementById('dark-mode-toggle');
339
+
340
+ // Speech recognition setup
341
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
342
+ const recognition = new SpeechRecognition();
343
+ recognition.lang = 'ar-SA';
344
+ recognition.interimResults = false;
345
+ recognition.maxAlternatives = 1;
346
+
347
+ // Speech synthesis setup
348
+ const synth = window.speechSynthesis;
349
+
350
+ // VITS Model Integration
351
+ const voiceModels = {
352
+ 'us': 'wasmdashai/vits-en-v1',
353
+ 'SA1': 'wasmdashai/vits-ar-sa-huba-v1',
354
+ 'SA2': 'wasmdashai/vits-ar-sa-huba-v2',
355
+ 'SA3': 'wasmdashai/vits-ar-sa-A',
356
+ };
357
+
358
+ // State variables
359
+ let isListening = false;
360
+ let conversationHistory = [];
361
+ let isDarkMode = true;
362
+
363
+ // Event Listeners
364
+ voiceBtn.addEventListener('click', toggleVoiceRecognition);
365
+ settingsBtn.addEventListener('click', () => settingsModal.classList.remove('hidden'));
366
+ closeSettings.addEventListener('click', () => settingsModal.classList.add('hidden'));
367
+ saveSettings.addEventListener('click', saveSettingsHandler);
368
+ cancelSettings.addEventListener('click', () => settingsModal.classList.add('hidden'));
369
+ keyboardBtn.addEventListener('click', () => keyboardModal.classList.remove('hidden'));
370
+ closeKeyboard.addEventListener('click', () => keyboardModal.classList.add('hidden'));
371
+ cancelKeyboard.addEventListener('click', () => keyboardModal.classList.add('hidden'));
372
+ sendText.addEventListener('click', sendTextMessage);
373
+ textInput.addEventListener('keypress', (e) => {
374
+ if (e.key === 'Enter' && !e.shiftKey) {
375
+ e.preventDefault();
376
+ sendTextMessage();
377
+ }
378
+ });
379
+ darkModeToggle.addEventListener('click', toggleDarkMode);
380
+
381
+ // Functions
382
+ function toggleVoiceRecognition() {
383
+ if (isListening) {
384
+ stopListening();
385
+ } else {
386
+ startListening();
387
+ }
388
+ }
389
+
390
+ function startListening() {
391
+ isListening = true;
392
+ voiceBtn.classList.add('pulse');
393
+ voiceBtn.innerHTML = '<i class="fas fa-stop text-xl"></i>';
394
+ voiceStatus.textContent = 'أنا أستمع لك...';
395
+ waveform.classList.remove('hidden');
396
+
397
+ try {
398
+ recognition.start();
399
+ } catch (e) {
400
+ console.error('Error starting recognition:', e);
401
+ stopListening();
402
+ showSystemMessage('حدث خطأ في تشغيل الميكروفون. يرجى التحقق من الإذن.');
403
+ }
404
+ }
405
+
406
+ function stopListening() {
407
+ isListening = false;
408
+ voiceBtn.classList.remove('pulse');
409
+ voiceBtn.innerHTML = '<i class="fas fa-microphone text-xl"></i>';
410
+ voiceStatus.textContent = 'اضغط على الميكروفون للتحدث';
411
+ waveform.classList.add('hidden');
412
+
413
+ try {
414
+ recognition.stop();
415
+ } catch (e) {
416
+ console.error('Error stopping recognition:', e);
417
+ }
418
+ }
419
+
420
+ function saveSettingsHandler() {
421
+ // In a real app, you would save these settings to localStorage or a backend
422
+ settingsModal.classList.add('hidden');
423
+ showSystemMessage('تم حفظ الإعدادات بنجاح');
424
+ }
425
+
426
+ function showSystemMessage(text) {
427
+ const messageDiv = document.createElement('div');
428
+ messageDiv.className = 'text-center text-xs text-slate-400 my-2';
429
+ messageDiv.textContent = text;
430
+ chatMessages.appendChild(messageDiv);
431
+ chatMessages.scrollTop = chatMessages.scrollHeight;
432
+ }
433
+
434
+ function addUserMessage(text) {
435
+ const messageDiv = document.createElement('div');
436
+ messageDiv.className = 'message-bubble user-message';
437
+ messageDiv.innerHTML = `<p>${text}</p>`;
438
+ chatMessages.appendChild(messageDiv);
439
+ chatMessages.scrollTop = chatMessages.scrollHeight;
440
+ }
441
+
442
+ function addAiMessage(text) {
443
+ const messageDiv = document.createElement('div');
444
+ messageDiv.className = 'message-bubble ai-message';
445
+
446
+ // Add typing indicator temporarily
447
+ const typingDiv = document.createElement('div');
448
+ typingDiv.className = 'typing-indicator';
449
+ typingDiv.innerHTML = `
450
+ <div class="typing-dot"></div>
451
+ <div class="typing-dot"></div>
452
+ <div class="typing-dot"></div>
453
+ `;
454
+ messageDiv.appendChild(typingDiv);
455
+ chatMessages.appendChild(messageDiv);
456
+ chatMessages.scrollTop = chatMessages.scrollHeight;
457
+
458
+ // Simulate AI thinking delay
459
+ setTimeout(() => {
460
+ typingDiv.remove();
461
+ messageDiv.innerHTML = `<p>${text}</p>`;
462
+ speakResponse(text);
463
+ }, 1500 + Math.random() * 1000); // Random delay between 1.5-2.5s for more natural feel
464
+ }
465
+
466
+ async function speakResponse(text) {
467
+ const voiceSelect = document.getElementById('voiceSelect');
468
+ const voice = voiceSelect.value;
469
+
470
+ try {
471
+ const client = await Client.connect("wasmdashai/DemoLahja");
472
+ const result = await client.predict("/predict", {
473
+ text: text,
474
+ name_model: voiceModels[voice],
475
+ speaking_rate: 1.0
476
+ });
477
+
478
+ const audioUrl = result.data?.[0]?.url;
479
+ if (audioUrl) {
480
+ const audio = new Audio(audioUrl);
481
+ audio.play();
482
+ } else {
483
+ fallbackTTS(text);
484
+ }
485
+ } catch (err) {
486
+ console.error("VITS model error:", err);
487
+ fallbackTTS(text);
488
+ }
489
+ }
490
+
491
+ function fallbackTTS(text) {
492
+ if (synth.speaking) {
493
+ synth.cancel();
494
+ }
495
+
496
+ const utterance = new SpeechSynthesisUtterance(text);
497
+ utterance.lang = voiceSelect.value === 'us' ? 'en-US' : 'ar-SA';
498
+ utterance.rate = 1.0;
499
+ synth.speak(utterance);
500
+ }
501
+
502
+ function processUserInput(text) {
503
+ if (!text.trim()) return;
504
+
505
+ addUserMessage(text);
506
+ conversationHistory.push({ role: 'user', content: text });
507
+
508
+ // In a real app, you would send this to your backend which connects to ChatGPT API
509
+ // For this demo, we'll simulate a response
510
+ simulateChatGPTResponse(text);
511
+ }
512
+
513
+ function simulateChatGPTResponse(userInput) {
514
+ // Enhanced responses with more natural Arabic
515
+ const responses = {
516
+ "مرحبا": "مرحباً بك! 🌸 كيف يمكنني مساعدتك اليوم؟",
517
+ "السلام عليكم": "وعليكم السلام ورحمة الله وبركاته 🌹 كيف حالك اليوم؟",
518
+ "كيف حالك": "الحمد لله بخير، شكراً لسؤالك! 😊 كيف يمكنني مساعدتك؟",
519
+ "ما هو اسمك": "أنا مساعدك الذكي 'لُحْجَة'، سعيد بتواصلك معي!",
520
+ "من صممك": "تم تطويري باستخدام أحدث تقنيات الذكاء الاصطناعي لخدمتك بشكل أفضل.",
521
+ "ماذا تستطيع ان تفعل": "أستطيع مساعدتك في:\n- الإجابة على أسئلتك\n- تقديم المعلومات\n- إجراء محادثات ذكية\n- وغير ذلك الكثير! جرب أن تسألني 😊",
522
+ "شكرا": "العفو! 🌺 دائماً سعيد بمساعدتك. هل هناك شيء آخر تحتاجه؟",
523
+ "شكراً": "على الرحب والسعة! 💐 لا تتردد في سؤالي عن أي شيء آخر.",
524
+ "وداعا": "إلى اللقاء! 👋 أراك لاحقاً بإذن الله.",
525
+ "مع السلامة": "مع السلامة 🌷 لا تنسى أن تعود إذا احتجت إلى أي مساعدة.",
526
+ "ما هو تاريخ اليوم": `تاريخ اليوم هو: ${new Date().toLocaleDateString("ar-EG", { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}`,
527
+ "ما هو الوقت الان": `الوقت الآن هو: ${new Date().toLocaleTimeString("ar-EG", { hour: 'numeric', minute: 'numeric', second: 'numeric' })}`,
528
+ "من اين انت": "أنا مساعد افتراضي موجود في كل مكان 🌍 حيثما تكون أنت!",
529
+ "ماهي عاصمه السعوديه": "عاصمة المملكة العربية السعودية هي الرياض 🏙️، وهي مدينة جميلة ومزدهرة.",
530
+ "ماهي عاصمه اليمن": "عاصمة اليمن هي صنعاء 🕌، إحدى أقدم المدن المأهولة في العالم.",
531
+ "اعطني نصيحه": "✨ من أفضل النصائح التي يمكنني تقديمها:\n1- لا تؤجل عمل اليوم إلى الغد\n2- ابدأ بخطوات صغيرة نحو أهدافك الكبيرة\n3- حافظ على توازنك بين العمل والحياة الشخصية",
532
+ "كيف اتعلم البرمجة": "لتعلم البرمجة:\n1- ابدأ بلغة سهلة مثل Python\n2- تدرب يومياً ولو قليلاً\n3- انضم لمجتمعات المبرمجين\n4- نفذ مشاريع صغيرة\n5- لا تخف من الأخطاء، فهي جزء من التعلم 💻",
533
+ "ما هو الذكاء الاصطناعي": "الذكاء الاصطناعي هو مجال في علوم الكمبيوتر يهدف إلى جعل الآلات قادرة على أداء مهام تتطلب ذكاءً بشرياً مثل:\n- فهم اللغة\n- التعلم\n- حل المشكلات\n- اتخاذ القرارات",
534
+ "هل يمكنك الغناء": "للأسف لا أستطيع الغناء جيداً ، لكني أستطيع مساعدتك في العثور على الأغاني أو توفير كلماتها!",
535
+ "ما هو الطقس اليوم": "للحصول على معلومات دقيقة عن الطقس، أحتاج إلى معرفة موقعك الجغرافي. يمكنك ذكر المدينة وسأساعدك في ذلك ☀️🌧️",
536
+ "ما هي لغة البرمجة الافضل": "لا توجد لغة برمجة 'أفضل' بشكل مطلق، ولكن:\n- للويب: JavaScript\n- للبيانات: Python\n- للأنظمة: C++\n- للأجهزة المحمولة: Swift/Kotlin\nالاختيار يعتمد على احتياجاتك! 💻"
537
+ };
538
+
539
+ const defaultResponse = "أعتذر، لم أفهم سؤالك بالكامل. هل يمكنك إعادة صياغته بطريقة أخرى؟";
540
+
541
+ // Find the best matching response (case insensitive)
542
+ const normalizedInput = userInput.trim().toLowerCase();
543
+ let response = defaultResponse;
544
+
545
+ for (const [key, value] of Object.entries(responses)) {
546
+ if (normalizedInput.includes(key.toLowerCase())) {
547
+ response = value;
548
+ break;
549
+ }
550
+ }
551
+
552
+ setTimeout(() => {
553
+ addAiMessage(response);
554
+ conversationHistory.push({ role: 'assistant', content: response });
555
+ }, 2000);
556
+ }
557
+
558
+ function sendTextMessage() {
559
+ const text = textInput.value.trim();
560
+ if (text) {
561
+ processUserInput(text);
562
+ textInput.value = '';
563
+ keyboardModal.classList.add('hidden');
564
+ }
565
+ }
566
+
567
+ function toggleDarkMode() {
568
+ isDarkMode = !isDarkMode;
569
+ if (isDarkMode) {
570
+ document.body.classList.add('bg-gradient-to-br', 'from-slate-900', 'to-slate-800');
571
+ darkModeToggle.innerHTML = '<i class="fas fa-moon text-slate-300"></i>';
572
+ } else {
573
+ document.body.classList.remove('bg-gradient-to-br', 'from-slate-900', 'to-slate-800');
574
+ document.body.classList.add('bg-gradient-to-br', 'from-slate-100', 'to-slate-200');
575
+ darkModeToggle.innerHTML = '<i class="fas fa-sun text-yellow-400"></i>';
576
+ }
577
+ }
578
+
579
+ // Recognition event handlers
580
+ recognition.onresult = (event) => {
581
+ const speechResult = event.results[0][0].transcript;
582
+ processUserInput(speechResult);
583
+ stopListening();
584
+ };
585
+
586
+ recognition.onerror = (event) => {
587
+ console.error('Speech recognition error', event.error);
588
+ stopListening();
589
+
590
+ if (event.error === 'not-allowed') {
591
+ showSystemMessage('يجب السماح باستخدام الميكروفون لتفعيل هذه الميزة. يرجى التحقق من إعدادات المتصفح.');
592
+ } else {
593
+ showSystemMessage('حدث خطأ في التعرف على الصوت. يرجى المحاولة مرة أخرى لاحقاً.');
594
+ }
595
+ };
596
+
597
+ recognition.onend = () => {
598
+ if (isListening) {
599
+ // If we're still supposed to be listening, restart recognition
600
+ setTimeout(() => {
601
+ try {
602
+ recognition.start();
603
+ } catch (e) {
604
+ console.error('Error restarting recognition:', e);
605
+ stopListening();
606
+ }
607
+ }, 500);
608
+ }
609
+ };
610
+
611
+ // Initialize voices when they become available
612
+ if (speechSynthesis.onvoiceschanged !== undefined) {
613
+ speechSynthesis.onvoiceschanged = () => {
614
+ // Voices are now loaded
615
+ };
616
+ }
617
+
618
+ // Add some sample messages after a delay to simulate a more interactive experience
619
+ setTimeout(() => {
620
+ if (chatMessages.children.length <= 2) { // Only if no other messages have been added
621
+ addAiMessage('هل لديك أي أسئلة محددة تريد أن أساعدك بها اليوم؟ 😊');
622
+ }
623
+ }, 8000);
624
+ </script>
625
+
626
+ <div 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;">
627
+ 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);">
628
+ <a href="https://enzostvs-deepsite.hf.space" style="color: #fff; text-decoration: underline;" target="_blank">DeepSite</a> - 🧬
629
+ <a href="https://enzostvs-deepsite.hf.space?remix=wasmdashai/wasmdashai-chatlhja" style="color: #fff; text-decoration: underline;" target="_blank">Remix</a>
630
+ </div>
631
+ <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=wasmdashai/wasmdashai-wasmdashai-chatlhja" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
632
+ </html>