1import gradio as gr
2import torch
3from unsloth import FastLanguageModel
4from IPython.display import display, Audio
5import numpy as np
6
7# Global model variables
8model = None
9tokenizer = None
10snac_model = None
11device = None
12
13def load_models():
14 """Initialize and load all required models for Sanskrit TTS inference."""
15 global model, tokenizer, snac_model, device
16 device = "cuda" if torch.cuda.is_available() else "cpu"
17 print(f"Loading models on: {device}")
18
19 # Load the fine-tuned Sanskrit TTS model
20 model, tokenizer = FastLanguageModel.from_pretrained(
21 "rverma0631/Sanskrit_TTS",
22 max_seq_length=2048,
23 dtype=None,
24 load_in_4bit=False,
25 )
26
27 model = model.to(device)
28 FastLanguageModel.for_inference(model)
29
30 # Load SNAC model for audio generation
31 try:
32 from snac import SNAC
33 snac_model = SNAC.from_pretrained("hubertsiuzdak/snac_24khz").eval()
34 except ImportError:
35 print("Warning: SNAC model import failed. Make sure SNAC is installed.")
36
37 snac_model.to("cpu")
38
39 print("Models loaded successfully!")
40
41def redistribute_codes(code_list):
42 """Redistribute generated codes into hierarchical layers for audio synthesis."""
43 layer_1 = []
44 layer_2 = []
45 layer_3 = []
46
47 for i in range((len(code_list)+1)//7):
48 layer_1.append(code_list[7*i])
49 layer_2.append(code_list[7*i+1]-4096)
50 layer_3.append(code_list[7*i+2]-(2*4096))
51 layer_3.append(code_list[7*i+3]-(3*4096))
52 layer_2.append(code_list[7*i+4]-(4*4096))
53 layer_3.append(code_list[7*i+5]-(5*4096))
54 layer_3.append(code_list[7*i+6]-(6*4096))
55
56 codes = [torch.tensor(layer_1).unsqueeze(0),
57 torch.tensor(layer_2).unsqueeze(0),
58 torch.tensor(layer_3).unsqueeze(0)]
59
60 audio_hat = snac_model.decode(codes)
61 return audio_hat
62
63def sanskrit_tts_inference(sanskrit_text, chosen_voice=""):
64 """
65 Generate Sanskrit speech from input text using the fine-tuned model.
66
67 Args:
68 sanskrit_text (str): Input Sanskrit text in Devanagari script
69 chosen_voice (str): Voice selection parameter (optional)
70
71 Returns:
72 tuple: (audio_data, status_message)
73 """
74 if not sanskrit_text.strip():
75 return None, "Please enter some Sanskrit text."
76
77 try:
78 prompts = [sanskrit_text]
79 chosen_voice = 1070
80
81 # Prepare prompts with voice selection
82 prompts_ = [(f"{chosen_voice}: " + p) if chosen_voice else p for p in prompts]
83
84 # Tokenize input prompts
85 all_input_ids = []
86 for prompt in prompts_:
87 input_ids = tokenizer(prompt, return_tensors="pt").input_ids
88 all_input_ids.append(input_ids)
89
90 # Define special tokens
91 start_token = torch.tensor([[ 128259]], dtype=torch.int64)
92 end_tokens = torch.tensor([[128009, 128260]], dtype=torch.int64)
93
94 # Construct modified input sequences
95 all_modified_input_ids = []
96 for input_ids in all_input_ids:
97 modified_input_ids = torch.cat([start_token, input_ids, end_tokens], dim=1)
98 all_modified_input_ids.append(modified_input_ids)
99
100 # Apply padding and create attention masks
101 all_padded_tensors = []
102 all_attention_masks = []
103 max_length = max([modified_input_ids.shape[1] for modified_input_ids in all_modified_input_ids])
104
105 for modified_input_ids in all_modified_input_ids:
106 padding = max_length - modified_input_ids.shape[1]
107 padded_tensor = torch.cat([torch.full((1, padding), 128263, dtype=torch.int64), modified_input_ids], dim=1)
108 attention_mask = torch.cat([torch.zeros((1, padding), dtype=torch.int64), torch.ones((1, modified_input_ids.shape[1]), dtype=torch.int64)], dim=1)
109 all_padded_tensors.append(padded_tensor)
110 all_attention_masks.append(attention_mask)
111
112 # Batch tensors for inference
113 all_padded_tensors = torch.cat(all_padded_tensors, dim=0)
114 all_attention_masks = torch.cat(all_attention_masks, dim=0)
115
116 input_ids = all_padded_tensors.to(device)
117 attention_mask = all_attention_masks.to(device)
118
119 # Generate audio codes using the model
120 generated_ids = model.generate(
121 input_ids=input_ids,
122 attention_mask=attention_mask,
123 max_new_tokens=1200,
124 do_sample=True,
125 temperature=0.6,
126 top_p=0.95,
127 repetition_penalty=1.1,
128 num_return_sequences=1,
129 eos_token_id=128258,
130 use_cache=True
131 )
132
133 # Post-process generated tokens
134 token_to_find = 128257
135 token_to_remove = 128258
136
137 token_indices = (generated_ids == token_to_find).nonzero(as_tuple=True)
138
139 if len(token_indices[1]) > 0:
140 last_occurrence_idx = token_indices[1][-1].item()
141 cropped_tensor = generated_ids[:, last_occurrence_idx+1:]
142 else:
143 cropped_tensor = generated_ids
144
145 mask = cropped_tensor != token_to_remove
146
147 processed_rows = []
148 for row in cropped_tensor:
149 masked_row = row[row != token_to_remove]
150 processed_rows.append(masked_row)
151
152 # Convert tokens to audio codes
153 code_lists = []
154 for row in processed_rows:
155 row_length = row.size(0)
156 new_length = (row_length // 7) * 7
157 trimmed_row = row[:new_length]
158 trimmed_row = [t - 128266 for t in trimmed_row]
159 code_lists.append(trimmed_row)
160
161 # Generate audio samples
162 my_samples = []
163 for code_list in code_lists:
164 samples = redistribute_codes(code_list)
165 my_samples.append(samples)
166
167 if len(my_samples) > 0:
168 audio_sample = my_samples[0].detach().squeeze().to("cpu").numpy()
169 return (24000, audio_sample), f"✅ Generated audio for: {sanskrit_text}"
170 else:
171 return None, "❌ Failed to generate audio - no valid codes produced."
172
173 except Exception as e:
174 return None, f"❌ Error during inference: {str(e)}"
175
176# Initialize models
177print("Loading models... This may take a moment.")
178load_models()
179
180# Create Gradio interface
181with gr.Blocks(title="Sanskrit Text-to-Speech") as demo:
182 gr.Markdown("""
183 # 🕉️ Sanskrit Text-to-Speech
184
185 Enter Sanskrit text in Devanagari script and generate speech using your fine-tuned model.
186 """)
187
188 with gr.Row():
189 with gr.Column():
190 sanskrit_input = gr.Textbox(
191 label="Sanskrit Text",
192 placeholder="Enter Sanskrit text in Devanagari script...",
193 lines=3,
194 value="नमस्ते"
195 )
196
197 generate_btn = gr.Button("🎵 Generate Speech", variant="primary")
198
199 with gr.Column():
200 audio_output = gr.Audio(
201 label="Generated Sanskrit Speech",
202 type="numpy"
203 )
204
205 status_output = gr.Textbox(
206 label="Status",
207 lines=2,
208 interactive=False
209 )
210
211 # Example inputs for demonstration
212 gr.Examples(
213 examples=[
214 ["नमस्ते"],
215 ["संस्कृत एक प्राचीन भाषा है"],
216 ["ॐ शान्ति शान्ति शान्तिः"],
217 ["सर्वे भवन्तु सुखिनः"],
218 ],
219 inputs=[sanskrit_input],
220 outputs=[audio_output, status_output],
221 fn=sanskrit_tts_inference,
222 cache_examples=False
223 )
224
225 # Connect interface components
226 generate_btn.click(
227 fn=sanskrit_tts_inference,
228 inputs=[sanskrit_input],
229 outputs=[audio_output, status_output]
230 )
231
232# Launch the application
233if __name__ == "__main__":
234 demo.launch(
235 share=True,
236 server_name="0.0.0.0",
237 server_port=7860,
238 show_error=True
239 )