HAMMALE commited on
Commit
b816ec3
·
verified ·
1 Parent(s): b22041e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +230 -107
app.py CHANGED
@@ -81,157 +81,280 @@ def synthesize_speech(text, voice_type="male", speed=1.0):
81
  # Gradio imports need to be added
82
  import gradio as gr
83
 
84
- CUSTOM_CSS = """
85
- * { box-sizing: border-box; }
86
- :root {
87
- --brand-red: #c8102e; /* Morocco red vibe */
88
- --brand-blue: #1f60c4;
89
- --bg-1: #f5f7fa;
90
- --bg-2: #c3cfe2;
91
- --card-bg: #ffffff;
92
- --text-1: #1f2937;
93
- --muted: #6b7280;
94
  }
95
- body, html { margin:0; padding:0; height:100%; width:100%; overflow-x:hidden; }
96
- .gradio-container { font-family:'Montserrat','Arial',sans-serif !important; height:100vh; width:100vw;
97
- background: linear-gradient(135deg, var(--bg-1) 0%, var(--bg-2) 100%); display:flex; flex-direction:column; padding:0; margin:0; }
98
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
- .main-header { background: linear-gradient(90deg, var(--brand-red), var(--brand-blue)); color:#fff; padding:2rem 1rem; text-align:center;
101
- box-shadow: 0 6px 12px rgba(0,0,0,0.15); border-bottom: 4px solid #ffffff33; }
102
- .main-header h1 { font-size:2.4rem; margin:0; font-weight:800; letter-spacing:.5px; text-shadow: 1px 1px 3px rgba(0,0,0,.25); }
103
- .main-header p { font-size:1.05rem; margin:.5rem 0 0; opacity:.95; font-weight:400; }
104
- .flag { display:inline-block; width:38px; height:28px; background-image:url('https://flagcdn.com/w40/ma.png'); background-size:cover; border-radius:4px; margin-right:10px; vertical-align:middle; }
 
 
 
105
 
 
 
 
 
 
 
 
106
 
107
- .container { max-width:1150px; margin: 2rem auto; padding: 0 1rem; width:100%; flex:1; }
108
- .card { display:flex; gap:1.5rem; background:var(--card-bg); border-radius:16px; padding:1.5rem; box-shadow:0 8px 16px rgba(0,0,0,.08); margin-bottom:1.5rem; }
109
- .col { flex:1; min-width:0; }
 
 
 
110
 
 
 
 
 
 
 
111
 
112
- .info { background:#fff6f6; border-left:5px solid var(--brand-red); padding:1rem 1.25rem; border-radius:10px; margin-bottom:1rem; color:var(--text-1); line-height:1.6; box-shadow:0 2px 4px rgba(0,0,0,.04); }
113
- .label-tip { font-size:.9rem; color:var(--muted); }
 
 
 
 
 
 
 
114
 
 
 
 
 
115
 
116
- /* Inputs */
117
- .textbox textarea { border:2px solid #e5e7eb !important; border-radius:12px !important; padding:1rem !important; font-size:1.05rem !important; transition:border-color .25s ease !important; }
118
- .textbox textarea:focus { border-color: var(--brand-red) !important; box-shadow:0 0 0 4px rgba(200,16,46,.12) !important; }
 
 
 
 
 
 
 
119
 
 
 
 
 
 
 
 
120
 
121
- .radio-row { display:flex; flex-wrap:wrap; gap:.75rem; }
122
- .radio-row label { background:#f7f7f7; padding:.65rem 1.1rem; border-radius:999px; border:2px solid #e5e7eb; cursor:pointer; transition:all .25s ease; font-weight:600; }
123
- .radio-row input:checked + label { background: var(--brand-red); color:#fff; border-color:var(--brand-red); box-shadow:0 4px 10px rgba(200,16,46,.18); }
 
124
 
 
 
 
 
 
 
125
 
126
- .slider input { accent-color: var(--brand-red) !important; }
 
 
 
 
 
 
 
127
 
 
 
 
 
 
 
128
 
129
- .btn-primary { background: linear-gradient(90deg, var(--brand-red), var(--brand-blue)) !important; color:#fff !important; padding:.9rem 1.6rem !important; border-radius:999px !important; border:none !important; font-size:1.05rem !important; font-weight:700 !important;
130
- transition: transform .15s ease, box-shadow .25s ease !important; box-shadow:0 6px 14px rgba(0,0,0,.12) !important; }
131
- .btn-primary:hover { transform: translateY(-1px) !important; box-shadow:0 10px 18px rgba(0,0,0,.18) !important; }
132
 
 
 
 
133
 
134
- .audio audio { width:100%; border-radius:12px; box-shadow:0 4px 8px rgba(0,0,0,.08); }
 
 
 
 
 
 
 
 
 
 
135
 
 
 
 
 
136
 
137
- .examples { margin-top:1rem; padding:1rem; background:#fafafa; border-radius:12px; box-shadow:0 4px 8px rgba(0,0,0,.05); }
138
- .examples h4 { margin:.25rem 0 .75rem; color: var(--brand-red); }
 
139
 
 
 
 
 
 
140
 
141
- footer { text-align:center; padding:1.2rem; background:#ffffff; color:#4b5563; font-size:.95rem; border-top:1px solid #e5e7eb; margin-top:auto; }
142
- """
 
 
 
 
143
 
 
 
 
 
 
 
 
 
 
144
 
145
- # === UI Composition ===
146
- with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Soft()) as demo:
147
- # Header
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  gr.HTML(
149
  """
150
- <div class="main-header" role="banner">
151
- <h1><span class="flag" aria-hidden="true">🇲🇦</span> Darija Text‑to‑Speech (TTS) — المغرب 🎙️</h1>
152
- <p>7awwel l-kteb b-darija l-sout b-wahd l-mas-hla — Transformez votre texte en parole facilement.</p>
 
 
 
 
 
 
 
 
 
 
 
 
153
  </div>
154
  """
155
  )
156
 
157
- with gr.Group(elem_classes="container"):
158
- with gr.Row(elem_classes="card"):
159
- # Left column — inputs
160
- with gr.Column(elem_classes="col"):
161
- gr.Markdown(
162
- "Kteb b-darija b lli bghiti. <span class='label-tip'>(Accents FR/AR kaynine OK)</span>",
163
- elem_classes=["info"]
164
- )
165
-
166
- text_input = gr.Textbox(
167
- label="✍️Texte en darija",
168
- placeholder="Ex: Salam 3likom, kif dayr?",
169
- lines=4,
170
- elem_classes=["textbox"]
171
- )
172
-
173
  voice_type = gr.Radio(
174
- ["rajil (male)", "mra (female)"],
175
- value="rajil (male)",
176
- label="🎤 No3 dyal sawt (Type de voix)",
177
- elem_classes=["radio-row"]
178
- )
179
-
180
- speed = gr.Slider(
181
- minimum=0.5,
182
- maximum=2.0,
183
- value=1.0,
184
- step=0.1,
185
- label="⏩ Sor3a dyal lhadra (Vitesse)"
186
- )
187
-
188
- generate_btn = gr.Button(
189
- "Générer l'audio",
190
- variant="primary",
191
- elem_classes=["btn-primary"]
192
  )
193
 
194
- # Right column — outputs
195
- with gr.Column(elem_classes="col"):
196
- audio_output = gr.Audio(
197
- label="🔊 Audio généré",
198
- elem_classes=["audio"]
199
- )
200
- error_output = gr.Textbox(
201
- label="⚠️ Khta2 / Erreur",
202
- visible=False
203
- )
 
 
 
 
204
 
205
- with gr.Group(elem_classes="examples"):
206
- gr.HTML("<h4>Exemples b‑darija</h4>")
207
- gr.Examples(
208
- examples=[
209
- ["Lyouma ljaw zwiiin bzzaf.", "mra (female)", 1.0],
210
- ["Lmaghrib a7san blad f l3alam ila hayd AKHANOUCH O LFASAD", "rajil (male)", 1.0],
211
- ["Filistin 77orra mIna ALBARII ILA LbahrII", "mra (female)", 0.9],
212
- ],
213
- inputs=[text_input, voice_type, speed],
214
- outputs=[audio_output, error_output],
215
- fn=synthesize_speech,
216
- cache_examples=False
217
- )
218
 
219
- # Footer
220
  gr.HTML(
221
  """
222
  <footer>
223
- <p>Développé par <strong>HAMMALE</strong> · Données: <em>DODa Audio Dataset</em> · <strong>AtlasAI</strong></p>
224
  </footer>
225
  """
226
  )
227
 
228
- # Events
229
  generate_btn.click(
230
- fn=synthesize_speech,
231
- inputs=[text_input, voice_type, speed],
232
  outputs=[audio_output, error_output]
233
  )
234
 
235
- # === Launch ===
236
  if __name__ == "__main__":
237
  demo.launch()
 
81
  # Gradio imports need to be added
82
  import gradio as gr
83
 
84
+
85
+ custom_css = """
86
+ body, html {
87
+ margin: 0;
88
+ padding: 0;
89
+ height: 100%;
90
+ width: 100%;
91
+ overflow-x: hidden;
 
 
92
  }
 
 
 
93
 
94
+ .gradio-container {
95
+ font-family: 'Montserrat', 'Arial', sans-serif !important;
96
+ height: 100vh;
97
+ width: 100vw;
98
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
99
+ display: flex;
100
+ flex-direction: column;
101
+ padding: 0;
102
+ margin: 0;
103
+ overflow-y: auto;
104
+ }
105
 
106
+ .main-header {
107
+ background: linear-gradient(90deg, #d32f2f, #1976d2);
108
+ color: white;
109
+ padding: 2em;
110
+ text-align: center;
111
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
112
+ border-bottom: 4px solid #ffffff33;
113
+ }
114
 
115
+ .main-header h1 {
116
+ font-size: 2.8em;
117
+ margin: 0;
118
+ font-weight: 700;
119
+ letter-spacing: 1px;
120
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
121
+ }
122
 
123
+ .main-header p {
124
+ font-size: 1.2em;
125
+ margin: 0.5em 0 0;
126
+ opacity: 0.9;
127
+ font-weight: 300;
128
+ }
129
 
130
+ .container {
131
+ max-width: 1200px;
132
+ margin: 2em auto;
133
+ padding: 0 1em;
134
+ flex: 1;
135
+ }
136
 
137
+ .row {
138
+ display: flex;
139
+ gap: 2em;
140
+ background: white;
141
+ border-radius: 15px;
142
+ padding: 2em;
143
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
144
+ margin-bottom: 2em;
145
+ }
146
 
147
+ .column {
148
+ flex: 1;
149
+ padding: 1em;
150
+ }
151
 
152
+ .info-box {
153
+ background: #fef6f6;
154
+ border-left: 5px solid #d32f2f;
155
+ padding: 1.5em;
156
+ border-radius: 8px;
157
+ margin-bottom: 1.5em;
158
+ font-size: 1em;
159
+ line-height: 1.6;
160
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
161
+ }
162
 
163
+ .textbox textarea {
164
+ border: 2px solid #e0e0e0 !important;
165
+ border-radius: 10px !important;
166
+ padding: 1em !important;
167
+ font-size: 1.1em !important;
168
+ transition: border-color 0.3s ease !important;
169
+ }
170
 
171
+ .textbox textarea:focus {
172
+ border-color: #d32f2f !important;
173
+ box-shadow: 0 0 8px rgba(211, 47, 47, 0.2) !important;
174
+ }
175
 
176
+ .radio {
177
+ display: flex;
178
+ justify-content: center;
179
+ gap: 1.5em;
180
+ margin: 1em 0;
181
+ }
182
 
183
+ .radio label {
184
+ background: #f5f5f5;
185
+ padding: 0.8em 1.5em;
186
+ border-radius: 25px;
187
+ border: 2px solid #e0e0e0;
188
+ cursor: pointer;
189
+ transition: all 0.3s ease;
190
+ }
191
 
192
+ .radio input:checked + label {
193
+ background: #d32f2f;
194
+ color: white;
195
+ border-color: #d32f2f;
196
+ box-shadow: 0 4px 8px rgba(211, 47, 47, 0.2);
197
+ }
198
 
199
+ .slider {
200
+ margin: 1.5em 0;
201
+ }
202
 
203
+ .slider input {
204
+ accent-color: #d32f2f !important;
205
+ }
206
 
207
+ .button {
208
+ background: linear-gradient(90deg, #d32f2f, #1976d2) !important;
209
+ color: white !important;
210
+ padding: 1em 2em !important;
211
+ border-radius: 25px !important;
212
+ border: none !important;
213
+ font-size: 1.1em !important;
214
+ font-weight: 600 !important;
215
+ transition: transform 0.2s ease, box-shadow 0.3s ease !important;
216
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15) !important;
217
+ }
218
 
219
+ .button:hover {
220
+ transform: translateY(-2px) !important;
221
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.25) !important;
222
+ }
223
 
224
+ .audio {
225
+ margin-top: 1em;
226
+ }
227
 
228
+ .audio audio {
229
+ width: 100%;
230
+ border-radius: 10px;
231
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
232
+ }
233
 
234
+ .example-header {
235
+ font-weight: 600;
236
+ color: #d32f2f;
237
+ margin: 1.5em 0 0.5em;
238
+ font-size: 1.2em;
239
+ }
240
 
241
+ ul {
242
+ padding-left: 1.5em;
243
+ color: #333;
244
+ }
245
+
246
+ li {
247
+ margin: 0.5em 0;
248
+ font-size: 1em;
249
+ }
250
 
251
+ .examples {
252
+ margin-top: 1.5em;
253
+ padding: 1em;
254
+ background: #f9f9f9;
255
+ border-radius: 10px;
256
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
257
+ }
258
+
259
+ footer {
260
+ text-align: center;
261
+ padding: 1.5em;
262
+ background: #ffffff;
263
+ color: #666;
264
+ font-size: 0.95em;
265
+ border-top: 1px solid #e0e0e0;
266
+ margin-top: auto;
267
+ }
268
+
269
+ .flag-icon {
270
+ width: 30px;
271
+ height: 30px;
272
+ vertical-align: middle;
273
+ margin-right: 10px;
274
+ }
275
+ """
276
+
277
+ # Create Gradio interface with enhanced design
278
+ with gr.Blocks(css=custom_css) as demo:
279
  gr.HTML(
280
  """
281
+ <style>
282
+ .flag {
283
+ display: inline-block;
284
+ width: 40px;
285
+ height: 30px;
286
+ background-image: url('https://flagcdn.com/w40/ma.png');
287
+ background-size: cover;
288
+ border-radius: 4px;
289
+ margin-right: 8px;
290
+ vertical-align: middle;
291
+ }
292
+ </style>
293
+ <div class="main-header">
294
+ <h1><span class="flag"></span>Moroccan Darija Text-to-Speech 🎙️</h1>
295
+ <p>Transform your Darija text into lifelike speech with ease</p>
296
  </div>
297
  """
298
  )
299
 
300
+ with gr.Row(elem_classes="row"):
301
+ with gr.Column(elem_classes="column"):
302
+ text_input = gr.Textbox(
303
+ label="Enter Darija Text",
304
+ placeholder="Kteb chi jomla b darija hna, bhal 'Salam, kifach nta?'...",
305
+ lines=3,
306
+ elem_classes="textbox"
307
+ )
308
+
309
+ with gr.Row(elem_classes="radio"):
 
 
 
 
 
 
310
  voice_type = gr.Radio(
311
+ ["male", "female"],
312
+ label="Voice Type",
313
+ value="male"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
  )
315
 
316
+ speed = gr.Slider(
317
+ minimum=0.5,
318
+ maximum=2.0,
319
+ value=1.0,
320
+ step=0.1,
321
+ label="Speech Speed",
322
+ elem_classes="slider"
323
+ )
324
+
325
+ generate_btn = gr.Button("Generate Speech", variant="primary", elem_classes="button")
326
+
327
+ with gr.Column(elem_classes="column"):
328
+ audio_output = gr.Audio(label="Generated Speech", elem_classes="audio")
329
+ error_output = gr.Textbox(label="Error (if any)", visible=False)
330
 
331
+ gr.Examples(
332
+ examples=[
333
+ ["Ana Nadi Bezzaaf hhh", "male", 1.0],
334
+ ["Lyoum ajwaa zwina bezzaaf.", "female", 1.0],
335
+ ["Lmaghrib ahssan blad fi l3alam", "male", 1.0],
336
+ ["Filistine horaa mina lbari ila lbarri", "female", 0.8],
337
+ ],
338
+ inputs=[text_input, voice_type, speed],
339
+ outputs=[audio_output, error_output],
340
+ fn=synthesize_speech
341
+ )
 
 
342
 
 
343
  gr.HTML(
344
  """
345
  <footer>
346
+ <p>Developed by HAMMALE | Data: DODa Audio Dataset | AtlasAI</p>
347
  </footer>
348
  """
349
  )
350
 
351
+ # Set button click action
352
  generate_btn.click(
353
+ fn=synthesize_speech,
354
+ inputs=[text_input, voice_type, speed],
355
  outputs=[audio_output, error_output]
356
  )
357
 
358
+ # Launch the demo
359
  if __name__ == "__main__":
360
  demo.launch()