Spaces:
Running
Running
| from logging import error | |
| import gradio as gr | |
| import spaces | |
| import torch | |
| from transformers import AutoTokenizer, VitsModel | |
| import os | |
| import numpy as np | |
| import noisereduce as nr | |
| import torch.nn as nn | |
| from typing import Optional, Iterator | |
| # قراءة التوكن من Secrets | |
| token = os.getenv("acees-token") # تأكد أنك سميته بنفس الاسم في Settings → Repository secrets | |
| # كائن لتخزين النماذج | |
| models = {} | |
| # اختيار الجهاز (CUDA لو متوفر، غير كذا CPU) | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| # دالة إزالة الضوضاء | |
| def remove_noise_nr(audio_data, sr=16000): | |
| return nr.reduce_noise(y=audio_data, hop_length=256, sr=sr) | |
| # دالة inference (streaming / non-streaming) | |
| def _inference_forward_stream( | |
| self, | |
| input_ids: Optional[torch.Tensor] = None, | |
| attention_mask: Optional[torch.Tensor] = None, | |
| speaker_embeddings: Optional[torch.Tensor] = None, | |
| chunk_size: int = 32, | |
| is_streaming: bool = True | |
| ) -> Iterator[torch.Tensor]: | |
| padding_mask = attention_mask.unsqueeze(-1).float() if attention_mask is not None else torch.ones_like(input_ids).unsqueeze(-1).float() | |
| text_encoder_output = self.text_encoder(input_ids=input_ids, padding_mask=padding_mask, attention_mask=attention_mask) | |
| hidden_states = text_encoder_output[0].transpose(1, 2) | |
| input_padding_mask = padding_mask.transpose(1, 2) | |
| log_duration = self.duration_predictor(hidden_states, input_padding_mask, speaker_embeddings) | |
| length_scale = 1.0 / self.speaking_rate | |
| duration = torch.ceil(torch.exp(log_duration) * input_padding_mask * length_scale) | |
| predicted_lengths = torch.clamp_min(torch.sum(duration, [1,2]), 1).long() | |
| indices = torch.arange(predicted_lengths.max(), device=predicted_lengths.device) | |
| output_padding_mask = indices.unsqueeze(0) < predicted_lengths.unsqueeze(1) | |
| output_padding_mask = output_padding_mask.unsqueeze(1).to(input_padding_mask.dtype) | |
| attn_mask = torch.unsqueeze(input_padding_mask, 2) * torch.unsqueeze(output_padding_mask, -1) | |
| batch_size, _, output_length, input_length = attn_mask.shape | |
| cum_duration = torch.cumsum(duration, -1).view(batch_size * input_length, 1) | |
| indices = torch.arange(output_length, device=duration.device) | |
| valid_indices = indices.unsqueeze(0) < cum_duration | |
| valid_indices = valid_indices.to(attn_mask.dtype).view(batch_size, input_length, output_length) | |
| padded_indices = valid_indices - nn.functional.pad(valid_indices, [0,0,1,0,0,0])[:, :-1] | |
| attn = padded_indices.unsqueeze(1).transpose(2,3) * attn_mask | |
| prior_means = text_encoder_output[1] | |
| prior_log_variances = text_encoder_output[2] | |
| prior_latents = prior_means + torch.randn_like(prior_means) * torch.exp(prior_log_variances) * self.noise_scale | |
| latents = self.flow(prior_latents, output_padding_mask, speaker_embeddings, reverse=True) | |
| spectrogram = latents * output_padding_mask | |
| if is_streaming: | |
| for i in range(0, spectrogram.size(-1), chunk_size): | |
| with torch.no_grad(): | |
| wav = self.decoder(spectrogram[:,:,i:i+chunk_size], speaker_embeddings) | |
| yield wav.squeeze().cpu().numpy() | |
| else: | |
| with torch.no_grad(): | |
| wav = self.decoder(spectrogram, speaker_embeddings) | |
| yield wav.squeeze().cpu().numpy() | |
| # تحميل النموذج + التوكن | |
| def get_model(name_model): | |
| global models | |
| if name_model in models: | |
| tokenizer = AutoTokenizer.from_pretrained(name_model, token=token) | |
| return models[name_model], tokenizer | |
| models[name_model] = VitsModel.from_pretrained(name_model, token=token) | |
| models[name_model].decoder.apply_weight_norm() | |
| for flow in models[name_model].flow.flows: | |
| torch.nn.utils.weight_norm(flow.conv_pre) | |
| torch.nn.utils.weight_norm(flow.conv_post) | |
| tokenizer = AutoTokenizer.from_pretrained(name_model, token=token) | |
| return models[name_model], tokenizer | |
| # النص الافتراضي | |
| TXT = "السلام عليكم ورحمة الله وبركاته يا هلا وسهلا ومراحب بالغالي" | |
| # دالة تحويل النص إلى كلام | |
| def modelspeech(text=TXT, name_model="wasmdashai/vits-ar-sa-huba-v2", speaking_rate=16000): | |
| model, tokenizer = get_model(name_model) | |
| inputs = tokenizer(text, return_tensors="pt").to(device) # يشتغل على CPU أو GPU حسب المتوفر | |
| model.speaking_rate = speaking_rate | |
| with torch.no_grad(): | |
| outputs = model(**inputs) | |
| waveform = outputs.waveform[0].cpu().numpy() | |
| return model.config.sampling_rate, remove_noise_nr(waveform) | |
| # واجهة Gradio | |
| model_choices = gr.Dropdown( | |
| choices=[ | |
| "wasmdashai/vits-ar-sa-huba-v1", | |
| "wasmdashai/vits-ar-sa-huba-v2", | |
| "wasmdashai/vits-ar-sa-A", | |
| "wasmdashai/vits-ar-ye-sa", | |
| "wasmdashai/vits-ar-sa-M-v1", | |
| "wasmdashai/vits-en-v1" | |
| ], | |
| label="اختر النموذج", | |
| value="wasmdashai/vits-ar-sa-huba-v2" | |
| ) | |
| demo = gr.Interface( | |
| fn=modelspeech, | |
| inputs=["text", model_choices, gr.Slider(0.1, 1, step=0.1, value=0.8)], | |
| outputs=["audio"] | |
| ) | |
| demo.queue() | |
| demo.launch(server_name="0.0.0.0", server_port=7860) | |