Azdeen commited on
Commit
47b193e
·
verified ·
1 Parent(s): 88691fe

import gradio as gr

Browse files

import requests

# Endpoints ثابتة
AZURE_CHAT_ENDPOINT = "https://lahja-dev-resource.cognitiveservices.azure.com/openai/deployments/gpt-4o/chat/completions?api-version=2025-01-01-preview"
AZURE_TTS_ENDPOINT = "https://lahja-dev-resource.cognitiveservices.azure.com/openai/deployments/LAHJA-V1/audio/speech?api-version=2025-03-01-preview"


# --- GPT رد ---
def chat_with_gpt(text, api_key):
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
# system prompt لتعريف الشخصية
messages = [
{
"role": "system",
"content": (
"انت مساعد ذكي اسمه (لهجة)، مطور من قبل شركة (أسس الذكاء الرقمي). "
"رد دايمًا باللهجة النجدية السعودية. "
"خلك مختصر وواضح."
)
},
{"role": "user", "content": text}
]
data = {
"messages": messages,
"max_tokens": 512,
"temperature": 0.8,
"top_p": 1,
"model": "gpt-4o"
}
response = requests.post(AZURE_CHAT_ENDPOINT, json=data, headers=headers)
if response.status_code == 200:
return response.json()["choices"][0]["message"]["content"]
else:
return f"Error: {response.status_code}\n{response.text}"


# --- تحويل نص لصوت ---
def text_to_speech(text, voice, speed, filename, api_key):
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
data = {
"model": "LAHJA-V1",
"input": text,
"voice": voice,
"speed": speed
}
response = requests.post(AZURE_TTS_ENDPOINT, json=data, headers=headers)
if response.status_code == 200:
with open(filename, "wb") as f:
f.write(response.content)
return filename
else:
return None


# --- دالة رئيسية ---
def chat_and_speak(user_input, voice, speed, history, api_key):
reply = chat_with_gpt(user_input, api_key)

# صوت السؤال
q_audio = text_to_speech(user_input, voice, speed, "question.wav", api_key)
# صوت الجواب
a_audio = text_to_speech(reply, voice, speed, "answer.wav", api_key)

# تحديث المحادثة
history = history + [(user_input, reply)]

return history, q_audio, a_audio


# --- التحقق من مفتاح الدخول ---
def check_key(user_key):
if user_key.strip() == "":
return gr.update(visible=True), gr.update(visible=False), None
else:
return gr.update(visible=False), gr.update(visible=True), user_key


# --- واجهة Gradio ---
with gr.Blocks(theme=gr.themes.Soft(), title="لهجة AI") as demo:
# -------- صفحة تسجيل الدخول --------
with gr.Group(visible=True) as login_page:
gr.Markdown(
"""
<div style="text-align:center; padding: 40px;">
<h1 style="color:#8B0000; font-size: 40px;">🔐 دخول إلى لهجة AI</h1>
<p style="font-size:18px; color:#444;">من فضلك أدخل مفتاح API للوصول إلى النظام</p>
</div>
""",
)
key_box = gr.Textbox(
placeholder="ادخل كود الدخول (API KEY)...",
label="API Key",
type="password"
)
login_btn = gr.Button("🚀 دخول", elem_id="login_btn")

api_key_state = gr.State()

# -------- صفحة المحادثة --------
with gr.Group(visible=False) as chat_page:
gr.Markdown(
"""
<div style="text-align:center; padding: 10px;">
<h1 style="color:#8B0000; font-size: 38px;">🤖 لهجة AI</h1>
<p style="font-size:18px; color:#333;">مطور من قبل شركة أسس الذكاء الرقمي | مساعد ذكي باللهجة النجدية</p>
</div>
"""
)

with gr.Row():
# عمود المحادثة
with gr.Column(scale=2):
chatbot = gr.Chatbot(label="المحادثة", height=450, bubble_full_width=False)
user_input = gr.Textbox(
placeholder="💬 اكتب سؤالك هنا...",
label="📌 نص المستخدم"
)
with gr.Row():
voice = gr.Dropdown(choices=["alloy"], value="alloy", label="🎙️ اختر الصوت")
speed = gr.Slider(minimum=0.5, maximum=2.0, value=1.0, step=0.1, label="⚡ سرعة الكلام")

send_btn = gr.Button("📤 أرسل", elem_classes="send-btn")

# عمود الصوت
with gr.Column(scale=1):
gr.Markdown("### 🔊 المخرجات الصوتية")
q_audio = gr.Audio(type="filepath", label="صوت السؤال")
a_audio = gr.Audio(type="filepath", label="صوت الجواب")

state = gr.State([])

send_btn.click(
fn=chat_and_speak,
inputs=[user_input, voice, speed, state, api_key_state],
outputs=[chatbot, q_audio, a_audio],
)

# -------- تحكم بظهور الصفحات --------
login_btn.click(
fn=check_key,
inputs=[key_box],
outputs=[login_page, chat_page, api_key_state],
)

demo.launch()

Files changed (3) hide show
  1. README.md +9 -5
  2. chat.html +203 -0
  3. index.html +343 -19
README.md CHANGED
@@ -1,10 +1,14 @@
1
  ---
2
- title: Undefined
3
- emoji: 📈
4
- colorFrom: pink
5
- colorTo: pink
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: undefined
3
+ colorFrom: red
4
+ colorTo: yellow
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://deepsite.hf.co).
14
+
chat.html ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>لهجة 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@400;500;700&display=swap');
11
+
12
+ body {
13
+ font-family: 'Tajawal', sans-serif;
14
+ background-color: #f8f4e8;
15
+ }
16
+
17
+ .header-bg {
18
+ background: linear-gradient(135deg, #8B0000 0%, #A52A2A 100%);
19
+ }
20
+
21
+ .chat-bubble {
22
+ border-radius: 20px 20px 5px 20px;
23
+ background-color: #f0f0f0;
24
+ }
25
+
26
+ .user-bubble {
27
+ border-radius: 20px 20px 20px 5px;
28
+ background-color: #e3f2fd;
29
+ }
30
+
31
+ .audio-player {
32
+ transition: all 0.3s ease;
33
+ background-color: #fff;
34
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
35
+ }
36
+
37
+ .audio-player:hover {
38
+ transform: translateY(-2px);
39
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
40
+ }
41
+ </style>
42
+ </head>
43
+ <body>
44
+ <div class="min-h-screen flex flex-col">
45
+ <!-- Header -->
46
+ <header class="header-bg text-white py-6 shadow-lg">
47
+ <div class="container mx-auto px-4 text-center">
48
+ <div class="flex items-center justify-center space-x-3">
49
+ <i class="fas fa-comments text-2xl"></i>
50
+ <h1 class="text-2xl font-bold">لهجة AI</h1>
51
+ </div>
52
+ <p class="mt-2 text-sm opacity-90">
53
+ مساعد ذكي باللهجة النجدية | مطور من قبل أسس الذكاء الرقمي
54
+ </p>
55
+ </div>
56
+ </header>
57
+
58
+ <!-- Main Content -->
59
+ <main class="flex-grow container mx-auto px-4 py-8">
60
+ <div class="max-w-4xl mx-auto">
61
+ <!-- Chat Container -->
62
+ <div class="bg-white rounded-xl shadow-lg overflow-hidden">
63
+ <!-- Chat Messages -->
64
+ <div id="chatContainer" class="h-96 p-4 overflow-y-auto space-y-4">
65
+ <!-- Messages will be added here dynamically -->
66
+ </div>
67
+
68
+ <!-- Input Section -->
69
+ <div class="p-4 border-t border-gray-200 bg-gray-50">
70
+ <div class="flex flex-col space-y-4">
71
+ <textarea id="userInput"
72
+ class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-red-600 focus:border-red-600 outline-none transition duration-200 resize-none"
73
+ placeholder="💬 اكتب رسالتك هنا..."
74
+ rows="3"></textarea>
75
+
76
+ <div class="flex flex-col sm:flex-row items-center justify-between space-y-3 sm:space-y-0">
77
+ <div class="flex items-center space-x-3">
78
+ <div class="flex items-center">
79
+ <label for="voiceSelect" class="ml-2 text-sm font-medium text-gray-700">الصوت:</label>
80
+ <select id="voiceSelect" class="border border-gray-300 rounded-md px-3 py-1 text-sm focus:ring-red-600 focus:border-red-600 outline-none">
81
+ <option value="alloy">عادي</option>
82
+ </select>
83
+ </div>
84
+ <div class="flex items-center">
85
+ <label for="speedSelect" class="ml-2 text-sm font-medium text-gray-700">السرعة:</label>
86
+ <select id="speedSelect" class="border border-gray-300 rounded-md px-3 py-1 text-sm focus:ring-red-600 focus:border-red-600 outline-none">
87
+ <option value="0.8">بطيئة</option>
88
+ <option value="1.0" selected>عادية</option>
89
+ <option value="1.2">سريعة</option>
90
+ </select>
91
+ </div>
92
+ </div>
93
+
94
+ <button id="sendBtn" class="bg-red-700 hover:bg-red-800 text-white font-medium py-2 px-6 rounded-lg shadow transition duration-200 flex items-center">
95
+ <i class="fas fa-paper-plane mr-2"></i>
96
+ إرسال
97
+ </button>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ </div>
102
+
103
+ <!-- Audio Players -->
104
+ <div id="audioSection" class="hidden mt-6 grid grid-cols-1 md:grid-cols-2 gap-4">
105
+ <div class="audio-player p-4 rounded-xl">
106
+ <h3 class="font-medium text-gray-800 mb-2">صوت السؤال</h3>
107
+ <audio id="questionAudio" controls class="w-full"></audio>
108
+ </div>
109
+ <div class="audio-player p-4 rounded-xl">
110
+ <h3 class="font-medium text-gray-800 mb-2">صوت الجواب</h3>
111
+ <audio id="answerAudio" controls class="w-full"></audio>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </main>
116
+
117
+ <!-- Footer -->
118
+ <footer class="bg-gray-100 py-4 border-t border-gray-200 mt-auto">
119
+ <div class="container mx-auto px-4 text-center">
120
+ <p class="text-gray-600 text-sm">
121
+ &copy; 2025 لهجة AI. جميع الحقوق محفوظة لشركة أسس الذكاء الرقمي.
122
+ </p>
123
+ </div>
124
+ </footer>
125
+ </div>
126
+
127
+ <script>
128
+ document.addEventListener('DOMContentLoaded', function() {
129
+ const chatContainer = document.getElementById('chatContainer');
130
+ const userInput = document.getElementById('userInput');
131
+ const sendBtn = document.getElementById('sendBtn');
132
+ const voiceSelect = document.getElementById('voiceSelect');
133
+ const speedSelect = document.getElementById('speedSelect');
134
+ const questionAudio = document.getElementById('questionAudio');
135
+ const answerAudio = document.getElementById('answerAudio');
136
+ const audioSection = document.getElementById('audioSection');
137
+
138
+ // Add message to chat
139
+ function addMessage(text, isUser) {
140
+ const messageDiv = document.createElement('div');
141
+ messageDiv.className = `flex ${isUser ? 'justify-start' : 'justify-end'}`;
142
+
143
+ const bubble = document.createElement('div');
144
+ bubble.className = isUser ? 'user-bubble p-4 max-w-xs md:max-w-md' : 'chat-bubble p-4 max-w-xs md:max-w-md';
145
+ bubble.textContent = text;
146
+
147
+ messageDiv.appendChild(bubble);
148
+ chatContainer.appendChild(messageDiv);
149
+ chatContainer.scrollTop = chatContainer.scrollHeight;
150
+ }
151
+
152
+ // Handle send button click
153
+ sendBtn.addEventListener('click', async function() {
154
+ const message = userInput.value.trim();
155
+ if (!message) return;
156
+
157
+ // Add user message
158
+ addMessage(message, true);
159
+ userInput.value = '';
160
+
161
+ // Show loading
162
+ const loadingDiv = document.createElement('div');
163
+ loadingDiv.className = 'flex justify-end';
164
+ const loadingBubble = document.createElement('div');
165
+ loadingBubble.className = 'chat-bubble p-4 max-w-xs';
166
+ loadingBubble.innerHTML = '<i class="fas fa-spinner fa-spin"></i> جاري الرد...';
167
+ loadingDiv.appendChild(loadingBubble);
168
+ chatContainer.appendChild(loadingDiv);
169
+ chatContainer.scrollTop = chatContainer.scrollHeight;
170
+
171
+ // Simulate API call (replace with actual API call)
172
+ setTimeout(() => {
173
+ // Remove loading
174
+ chatContainer.removeChild(loadingDiv);
175
+
176
+ // Add bot response (simulated)
177
+ const responses = [
178
+ "وعليكم السلام، الحمدلله بخير وش اخبارك؟",
179
+ "الله يسعدك، كل شي تمام الحين.",
180
+ "ياهلا والله، وش الجديد عندك؟",
181
+ "الحمدلله على كل حال، عندي اخبار حلوة اليوم."
182
+ ];
183
+ const randomResponse = responses[Math.floor(Math.random() * responses.length)];
184
+ addMessage(randomResponse, false);
185
+
186
+ // Show audio players (simulated)
187
+ questionAudio.src = "https://example.com/question.mp3";
188
+ answerAudio.src = "https://example.com/answer.mp3";
189
+ audioSection.classList.remove('hidden');
190
+ }, 1500);
191
+ });
192
+
193
+ // Allow sending with Enter key
194
+ userInput.addEventListener('keypress', function(e) {
195
+ if (e.key === 'Enter' && !e.shiftKey) {
196
+ e.preventDefault();
197
+ sendBtn.click();
198
+ }
199
+ });
200
+ });
201
+ </script>
202
+ </body>
203
+ </html>
index.html CHANGED
@@ -1,19 +1,343 @@
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="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>LAHJA AI - Advanced Text-to-Speech</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=Inter:wght@300;400;500;600;700&display=swap');
11
+
12
+ body {
13
+ font-family: 'Inter', sans-serif;
14
+ background-color: #f8fafc;
15
+ }
16
+
17
+ .gradient-bg {
18
+ background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #d946ef 100%);
19
+ }
20
+
21
+ .textarea-shadow {
22
+ box-shadow: 0 4px 6px -1px rgba(79, 70, 229, 0.1), 0 2px 4px -1px rgba(79, 70, 229, 0.06);
23
+ }
24
+
25
+ .waveform {
26
+ height: 60px;
27
+ background: linear-gradient(90deg, #6366f1, #8b5cf6, #d946ef);
28
+ opacity: 0.7;
29
+ position: relative;
30
+ overflow: hidden;
31
+ }
32
+
33
+ .waveform::before {
34
+ content: "";
35
+ position: absolute;
36
+ top: 0;
37
+ left: 0;
38
+ right: 0;
39
+ bottom: 0;
40
+ background: linear-gradient(
41
+ 90deg,
42
+ transparent,
43
+ rgba(255, 255, 255, 0.2),
44
+ transparent
45
+ );
46
+ animation: wave 1.5s linear infinite;
47
+ }
48
+
49
+ @keyframes wave {
50
+ 0% {
51
+ transform: translateX(-100%);
52
+ }
53
+ 100% {
54
+ transform: translateX(100%);
55
+ }
56
+ }
57
+
58
+ .audio-player {
59
+ transition: all 0.3s ease;
60
+ }
61
+
62
+ .audio-player:hover {
63
+ transform: translateY(-2px);
64
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
65
+ }
66
+ </style>
67
+ </head>
68
+ <body>
69
+ <div class="min-h-screen flex flex-col">
70
+ <!-- Header -->
71
+ <header class="gradient-bg text-white py-6 shadow-lg">
72
+ <div class="container mx-auto px-4">
73
+ <div class="flex justify-between items-center">
74
+ <div class="flex items-center space-x-2">
75
+ <i class="fas fa-wave-square text-2xl"></i>
76
+ <h1 class="text-2xl font-bold">LAHJA AI</h1>
77
+ </div>
78
+ <div class="hidden md:flex items-center space-x-4">
79
+ <span class="text-sm font-medium bg-white/20 px-3 py-1 rounded-full">VITS Architecture</span>
80
+ <span class="text-sm font-medium bg-white/20 px-3 py-1 rounded-full">Transformers</span>
81
+ <a href="chat.html" class="text-sm font-medium bg-white/20 px-3 py-1 rounded-full hover:bg-white/30 transition">Chat Assistant</a>
82
+ </div>
83
+ </div>
84
+ <p class="mt-2 text-sm opacity-80 max-w-2xl">
85
+ Advanced AI-powered text-to-speech with accent-aware synthesis using cutting-edge VITS architecture and transformer models.
86
+ </p>
87
+ </div>
88
+ </header>
89
+
90
+ <!-- Main Content -->
91
+ <main class="flex-grow container mx-auto px-4 py-8">
92
+ <div class="max-w-4xl mx-auto">
93
+ <div class="bg-white rounded-xl shadow-lg overflow-hidden">
94
+ <!-- Input Section -->
95
+ <div class="p-6 border-b border-gray-100">
96
+ <h2 class="text-xl font-semibold text-gray-800 mb-4">Text Input</h2>
97
+ <div class="relative">
98
+ <textarea id="textInput"
99
+ class="w-full h-48 px-4 py-3 border border-gray-200 rounded-lg textarea-shadow focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition duration-200 resize-none"
100
+ placeholder="Enter the text you want to convert to speech...">السلام عليكم كيف الحال اخبارك علومك وش مسوي بالله وش الجديد </textarea>
101
+ <div class="absolute bottom-3 right-3 flex items-center space-x-2">
102
+ <span id="charCount" class="text-xs text-gray-500">0 characters</span>
103
+ <button id="clearBtn" class="text-gray-400 hover:text-gray-600 transition">
104
+ <i class="fas fa-times"></i>
105
+ </button>
106
+ </div>
107
+ </div>
108
+
109
+ <div class="mt-6 flex flex-col sm:flex-row justify-between items-center space-y-4 sm:space-y-0">
110
+ <div class="flex items-center space-x-4">
111
+ <div class="flex items-center">
112
+ <label for="voiceSelect" class="mr-2 text-sm font-medium text-gray-700">Voice:</label>
113
+ <select id="voiceSelect" class="border border-gray-200 rounded-md px-3 py-1 text-sm focus:ring-indigo-500 focus:border-indigo-500 outline-none">
114
+ <option value="SA2">Najdi Arabic Haba v2</option>
115
+
116
+ <option value="us">American English</option>
117
+ <option value="SA1">Najdi Arabic Haba v1</option>
118
+
119
+ <option value="SA3">Najdi Arabic AHmmed v1</option>
120
+ </select>
121
+ </div>
122
+ <div class="flex items-center">
123
+ <label for="speedSelect" class="mr-2 text-sm font-medium text-gray-700">Speed:</label>
124
+ <select id="speedSelect" class="border border-gray-200 rounded-md px-3 py-1 text-sm focus:ring-indigo-500 focus:border-indigo-500 outline-none">
125
+ <option value="0.8">Slow</option>
126
+ <option value="1.0" selected>Normal</option>
127
+ <option value="1.2">Fast</option>
128
+ </select>
129
+ </div>
130
+ </div>
131
+
132
+ <button id="generateBtn" class="gradient-bg hover:opacity-90 text-white font-medium py-2 px-6 rounded-lg shadow-md transition duration-200 flex items-center">
133
+ <i class="fas fa-play-circle mr-2"></i>
134
+ Generate Voice
135
+ </button>
136
+ </div>
137
+ </div>
138
+
139
+ <!-- Output Section -->
140
+ <div class="p-6">
141
+ <h2 class="text-xl font-semibold text-gray-800 mb-4">Generated Audio</h2>
142
+
143
+ <!-- Loading State -->
144
+ <div id="loadingState" class="hidden">
145
+ <div class="flex flex-col items-center justify-center py-8">
146
+ <div class="waveform w-full rounded-lg mb-4"></div>
147
+ <p class="text-gray-600 font-medium">Processing your request with LAHJA AI...</p>
148
+ <p class="text-sm text-gray-500 mt-1">This may take a few moments</p>
149
+ </div>
150
+ </div>
151
+
152
+ <!-- Audio Player -->
153
+ <div id="audioPlayerContainer" class="hidden">
154
+ <div class="audio-player bg-gradient-to-r from-indigo-50 to-purple-50 rounded-xl p-4 border border-gray-200">
155
+ <div class="flex items-center justify-between mb-3">
156
+ <div class="flex items-center space-x-3">
157
+ <i class="fas fa-headphones text-indigo-600 text-xl"></i>
158
+ <div>
159
+ <h3 class="font-medium text-gray-800">Generated Speech</h3>
160
+ <p class="text-xs text-gray-500" id="audioInfo">American English • Normal speed</p>
161
+ </div>
162
+ </div>
163
+ <button id="downloadBtn" class="text-indigo-600 hover:text-indigo-800 transition">
164
+ <i class="fas fa-download"></i>
165
+ </button>
166
+ </div>
167
+ <audio id="audioPlayer" controls class="w-full"></audio>
168
+ </div>
169
+ </div>
170
+
171
+ <!-- Empty State -->
172
+ <div id="emptyState" class="flex flex-col items-center justify-center py-12 text-center">
173
+ <i class="fas fa-comment-dots text-4xl text-gray-300 mb-4"></i>
174
+ <h3 class="text-lg font-medium text-gray-700">No audio generated yet</h3>
175
+ <p class="text-gray-500 max-w-md mt-1">Enter some text above and click "Generate Voice" to create your speech.</p>
176
+ </div>
177
+ </div>
178
+ </div>
179
+
180
+ <!-- Features Section -->
181
+ <div class="mt-12 grid grid-cols-1 md:grid-cols-3 gap-6">
182
+ <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
183
+ <div class="text-indigo-600 mb-3">
184
+ <i class="fas fa-microchip text-2xl"></i>
185
+ </div>
186
+ <h3 class="font-semibold text-lg mb-2">VITS Architecture</h3>
187
+ <p class="text-gray-600 text-sm">
188
+ Our advanced VITS model synthesizes realistic audio waveforms directly from text with exceptional clarity and naturalness.
189
+ </p>
190
+ </div>
191
+ <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
192
+ <div class="text-purple-600 mb-3">
193
+ <i class="fas fa-language text-2xl"></i>
194
+ </div>
195
+ <h3 class="font-semibold text-lg mb-2">Accent-Aware</h3>
196
+ <p class="text-gray-600 text-sm">
197
+ Captures local vocal characteristics and intonation patterns for authentic regional speech synthesis.
198
+ </p>
199
+ </div>
200
+ <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
201
+ <div class="text-pink-600 mb-3">
202
+ <i class="fas fa-brain text-2xl"></i>
203
+ </div>
204
+ <h3 class="font-semibold text-lg mb-2">Transformer Models</h3>
205
+ <p class="text-gray-600 text-sm">
206
+ Deep linguistic analysis enables context-aware speech generation that reflects natural human expression.
207
+ </p>
208
+ </div>
209
+ </div>
210
+ </div>
211
+ </main>
212
+
213
+ <!-- Footer -->
214
+ <footer class="bg-gray-50 py-6 border-t border-gray-200">
215
+ <div class="container mx-auto px-4 text-center">
216
+ <p class="text-gray-500 text-sm">
217
+ &copy; 2025 LAHJA AI. Advanced text-to-speech powered by VITS architecture and transformer models.
218
+ </p>
219
+ </div>
220
+ </footer>
221
+ </div>
222
+
223
+ <script type="module">
224
+ import {Client} from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
225
+
226
+ document.addEventListener('DOMContentLoaded', async function () {
227
+ // Connect to Gradio client (must be inside async function)
228
+ const client = await Client.connect("wasmdashai/DemoLahja");
229
+
230
+ // DOM Elements
231
+ const textInput = document.getElementById('textInput');
232
+ const charCount = document.getElementById('charCount');
233
+ const clearBtn = document.getElementById('clearBtn');
234
+ const generateBtn = document.getElementById('generateBtn');
235
+ const voiceSelect = document.getElementById('voiceSelect');
236
+ const speedSelect = document.getElementById('speedSelect');
237
+ const loadingState = document.getElementById('loadingState');
238
+ const audioPlayerContainer = document.getElementById('audioPlayerContainer');
239
+ const emptyState = document.getElementById('emptyState');
240
+ const audioPlayer = document.getElementById('audioPlayer');
241
+ const downloadBtn = document.getElementById('downloadBtn');
242
+ const audioInfo = document.getElementById('audioInfo');
243
+
244
+ const voiceLabels = {
245
+ 'us': 'American English',
246
+ 'SA1': 'Najdi Arabic Haba v1',
247
+ 'SA2': 'Najdi Arabic Haba v2',
248
+ 'SA3': 'Najdi Arabic AHmmed v1',
249
+
250
+ };
251
+
252
+ const voiceModels = {
253
+ 'us': 'wasmdashai/vits-en-v1',
254
+ 'SA1': 'wasmdashai/vits-ar-sa-huba-v1',
255
+ 'SA2': 'wasmdashai/vits-ar-sa-huba-v2',
256
+ 'SA3': 'wasmdashai/vits-ar-sa-A',
257
+
258
+
259
+ };
260
+
261
+ const speedLabels = {
262
+ '0.3': 'Slow',
263
+ '1.0': 'Normal',
264
+ '1.2': 'Fast'
265
+ };
266
+
267
+ // Update character count
268
+ textInput.addEventListener('input', function () {
269
+ const count = textInput.value.length;
270
+ charCount.textContent = `${count} characters`;
271
+ clearBtn.classList.toggle('invisible', count === 0);
272
+ });
273
+
274
+ // Clear text input
275
+ clearBtn.addEventListener('click', function () {
276
+ textInput.value = '';
277
+ charCount.textContent = '0 characters';
278
+ clearBtn.classList.add('invisible');
279
+ });
280
+
281
+ // Generate voice
282
+ generateBtn.addEventListener('click', async function () {
283
+ const text = textInput.value.trim();
284
+ if (!text) {
285
+ alert('Please enter some text to convert to speech.');
286
+ return;
287
+ }
288
+
289
+ const voice = voiceSelect.value;
290
+ const speed = parseFloat(speedSelect.value);
291
+
292
+ loadingState.classList.remove('hidden');
293
+ audioPlayerContainer.classList.add('hidden');
294
+ emptyState.classList.add('hidden');
295
+ console.log("start result:", voice);
296
+
297
+ try {
298
+ const result = await client.predict("/predict", {
299
+ text: text,
300
+ name_model: voiceModels[voice],
301
+ speaking_rate: speed
302
+ });
303
+ console.log("Prediction result:", result);
304
+
305
+ const audioUrl = result.data?.[0]?.url;
306
+ if (!audioUrl) throw new Error("No audio URL received");
307
+
308
+ audioPlayer.src = audioUrl;
309
+ audioInfo.textContent = `${voiceLabels[voice]} • ${speedLabels[speed.toFixed(1)]} speed`;
310
+
311
+ loadingState.classList.add('hidden');
312
+ audioPlayerContainer.classList.remove('hidden');
313
+
314
+ // Auto play
315
+ setTimeout(() => {
316
+ audioPlayer.play().catch(e => console.warn('Autoplay failed:', e));
317
+ }, 300);
318
+ } catch (err) {
319
+ console.error("Error during prediction:", err);
320
+ loadingState.classList.add('hidden');
321
+ emptyState.classList.remove('hidden');
322
+ }
323
+ });
324
+
325
+ // Download audio
326
+ downloadBtn.addEventListener('click', function () {
327
+ if (audioPlayer.src) {
328
+ const a = document.createElement('a');
329
+ a.href = audioPlayer.src;
330
+ a.download = `lahja-ai-voice-${Date.now()}.mp3`;
331
+ document.body.appendChild(a);
332
+ a.click();
333
+ document.body.removeChild(a);
334
+ }
335
+ });
336
+
337
+ // Initialize char count
338
+ textInput.dispatchEvent(new Event('input'));
339
+ });
340
+ </script>
341
+
342
+ </body>
343
+ </html>