File size: 13,340 Bytes
6d75162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
955241f
 
 
 
 
 
6d75162
 
 
 
 
 
 
 
 
 
 
 
955241f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6d75162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
955241f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6d75162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
955241f
6d75162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
955241f
 
 
 
 
 
6d75162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
import os
import tempfile
import time
from typing import List, Tuple

import gradio as gr
import torch
import torchaudio
import spaces
from dataclasses import dataclass
from generator import Segment, load_csm_1b
from huggingface_hub import login

# Kiểm tra xem có GPU không và cấu hình thiết bị phù hợp
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Sử dụng thiết bị: {device}")

# Đăng nhập vào Hugging Face Hub nếu có token
def login_huggingface():
    hf_token = os.environ.get("HF_TOKEN")
    if hf_token:
        print("Đang đăng nhập vào Hugging Face Hub...")
        login(token=hf_token)
        print("Đã đăng nhập thành công!")
    else:
        print("Không tìm thấy HF_TOKEN trong biến môi trường. Một số mô hình có thể không truy cập được.")

# Đăng nhập khi khởi động
login_huggingface()

# Tải mô hình CSM-1B
generator = None

def load_model():
    global generator
    if generator is None:
        print("Đang tải mô hình CSM-1B...")
        generator = load_csm_1b(device=device)
        print("Đã tải xong mô hình!")
    return generator

# Hàm chuyển đổi âm thanh thành tensor
def audio_to_tensor(audio_path: str) -> Tuple[torch.Tensor, int]:
    waveform, sample_rate = torchaudio.load(audio_path)
    waveform = waveform.mean(dim=0)  # Chuyển stereo thành mono nếu cần
    return waveform, sample_rate

# Hàm lưu tensor âm thanh thành file
def save_audio(audio_tensor: torch.Tensor, sample_rate: int) -> str:
    temp_dir = tempfile.gettempdir()
    output_path = os.path.join(temp_dir, f"csm1b_output_{int(time.time())}.wav")
    torchaudio.save(output_path, audio_tensor.unsqueeze(0), sample_rate)
    return output_path

# Hàm tạo âm thanh từ văn bản sử dụng ZeroGPU
@spaces.GPU
def generate_speech(
    text: str,
    speaker_id: int,
    context_audio_path1: str = None,
    context_text1: str = None,
    context_speaker1: int = 0,
    context_audio_path2: str = None,
    context_text2: str = None,
    context_speaker2: int = 1,
    max_duration_ms: float = 30000,
    temperature: float = 0.9,
    top_k: int = 50,
    progress=gr.Progress()
) -> str:
    # Tải mô hình nếu chưa tải
    generator = load_model()
    
    # Chuẩn bị ngữ cảnh (context)
    context = []
    progress(0.1, "Đang xử lý ngữ cảnh...")
    
    # Xử lý ngữ cảnh 1
    if context_audio_path1 and context_text1:
        waveform, sample_rate = audio_to_tensor(context_audio_path1)
        # Resample nếu cần
        if sample_rate != generator.sample_rate:
            waveform = torchaudio.functional.resample(waveform, orig_freq=sample_rate, new_freq=generator.sample_rate)
        context.append(Segment(speaker=context_speaker1, text=context_text1, audio=waveform))
    
    # Xử lý ngữ cảnh 2
    if context_audio_path2 and context_text2:
        waveform, sample_rate = audio_to_tensor(context_audio_path2)
        # Resample nếu cần
        if sample_rate != generator.sample_rate:
            waveform = torchaudio.functional.resample(waveform, orig_freq=sample_rate, new_freq=generator.sample_rate)
        context.append(Segment(speaker=context_speaker2, text=context_text2, audio=waveform))
    
    progress(0.3, "Đang tạo âm thanh...")
    # Tạo âm thanh từ văn bản
    audio = generator.generate(
        text=text,
        speaker=speaker_id,
        context=context,
        max_audio_length_ms=max_duration_ms,
        temperature=temperature,
        topk=top_k
    )
    
    progress(0.8, "Đang lưu âm thanh...")
    # Lưu âm thanh thành file
    output_path = save_audio(audio, generator.sample_rate)
    
    progress(1.0, "Hoàn thành!")
    return output_path

# Hàm tạo âm thanh đơn giản không có ngữ cảnh
@spaces.GPU
def generate_speech_simple(
    text: str,
    speaker_id: int,
    max_duration_ms: float = 30000,
    temperature: float = 0.9,
    top_k: int = 50,
    progress=gr.Progress()
) -> str:
    # Tải mô hình nếu chưa tải
    generator = load_model()
    
    progress(0.3, "Đang tạo âm thanh...")
    # Tạo âm thanh từ văn bản
    audio = generator.generate(
        text=text,
        speaker=speaker_id,
        context=[],  # Không có ngữ cảnh
        max_audio_length_ms=max_duration_ms,
        temperature=temperature,
        topk=top_k
    )
    
    progress(0.8, "Đang lưu âm thanh...")
    # Lưu âm thanh thành file
    output_path = save_audio(audio, generator.sample_rate)
    
    progress(1.0, "Hoàn thành!")
    return output_path

# Tạo giao diện Gradio
def create_demo():
    with gr.Blocks(title="CSM-1B Text-to-Speech") as demo:
        gr.Markdown("# CSM-1B Text-to-Speech Demo")
        gr.Markdown("Mô hình CSM-1B (Collaborative Speech Model) là một mô hình text-to-speech tiên tiến có khả năng tạo giọng nói tự nhiên từ văn bản.")
        
        with gr.Tab("Tạo âm thanh đơn giản"):
            with gr.Row():
                with gr.Column():
                    text_input = gr.Textbox(
                        label="Văn bản cần chuyển thành giọng nói",
                        placeholder="Nhập văn bản bạn muốn chuyển thành giọng nói...",
                        lines=5
                    )
                    speaker_id = gr.Number(
                        label="ID người nói",
                        value=0,
                        precision=0,
                        minimum=0,
                        maximum=10
                    )
                    
                    with gr.Row():
                        max_duration = gr.Slider(
                            label="Thời lượng tối đa (ms)",
                            minimum=1000,
                            maximum=90000,
                            value=30000,
                            step=1000
                        )
                        temperature = gr.Slider(
                            label="Temperature",
                            minimum=0.1,
                            maximum=1.5,
                            value=0.9,
                            step=0.1
                        )
                        top_k = gr.Slider(
                            label="Top-K",
                            minimum=1,
                            maximum=100,
                            value=50,
                            step=1
                        )
                    
                    generate_btn = gr.Button("Tạo âm thanh")
                
                with gr.Column():
                    output_audio = gr.Audio(label="Âm thanh đầu ra", type="filepath")
        
        with gr.Tab("Tạo âm thanh với ngữ cảnh"):
            gr.Markdown("Tính năng này cho phép bạn cung cấp các đoạn âm thanh và văn bản làm ngữ cảnh để mô hình tạo ra âm thanh phù hợp hơn.")
            
            with gr.Row():
                with gr.Column():
                    context_text1 = gr.Textbox(label="Văn bản ngữ cảnh 1", lines=2)
                    context_audio1 = gr.Audio(label="Âm thanh ngữ cảnh 1", type="filepath")
                    context_speaker1 = gr.Number(label="ID người nói 1", value=0, precision=0)
                    
                    context_text2 = gr.Textbox(label="Văn bản ngữ cảnh 2", lines=2)
                    context_audio2 = gr.Audio(label="Âm thanh ngữ cảnh 2", type="filepath")
                    context_speaker2 = gr.Number(label="ID người nói 2", value=1, precision=0)
                    
                    text_input_context = gr.Textbox(
                        label="Văn bản cần chuyển thành giọng nói",
                        placeholder="Nhập văn bản bạn muốn chuyển thành giọng nói...",
                        lines=3
                    )
                    speaker_id_context = gr.Number(
                        label="ID người nói",
                        value=0,
                        precision=0
                    )
                    
                    with gr.Row():
                        max_duration_context = gr.Slider(
                            label="Thời lượng tối đa (ms)",
                            minimum=1000,
                            maximum=90000,
                            value=30000,
                            step=1000
                        )
                        temperature_context = gr.Slider(
                            label="Temperature",
                            minimum=0.1,
                            maximum=1.5,
                            value=0.9,
                            step=0.1
                        )
                        top_k_context = gr.Slider(
                            label="Top-K",
                            minimum=1,
                            maximum=100,
                            value=50,
                            step=1
                        )
                    
                    generate_context_btn = gr.Button("Tạo âm thanh với ngữ cảnh")
                
                with gr.Column():
                    output_audio_context = gr.Audio(label="Âm thanh đầu ra", type="filepath")
        
        # Thêm tab cấu hình Hugging Face
        with gr.Tab("Cấu hình"):
            gr.Markdown("### Cấu hình Hugging Face Token")
            gr.Markdown("""
            Để sử dụng mô hình CSM-1B, bạn cần có quyền truy cập vào mô hình trên Hugging Face.
            
            Bạn có thể cấu hình token của mình bằng cách:
            1. Tạo token tại [Hugging Face Settings](https://huggingface.co/settings/tokens)
            2. Đặt biến môi trường `HF_TOKEN` với giá trị là token của bạn
            
            Lưu ý: Trong Hugging Face Spaces, bạn có thể đặt biến môi trường trong phần Cài đặt của Space.
            """)
            
            hf_token_input = gr.Textbox(
                label="Hugging Face Token (Chỉ sử dụng trong phiên này)",
                placeholder="Nhập token của bạn...",
                type="password"
            )
            
            def set_token(token):
                if token:
                    os.environ["HF_TOKEN"] = token
                    login(token=token)
                    return "Đã đặt token thành công! Bạn có thể tải mô hình bây giờ."
                return "Token không hợp lệ. Vui lòng nhập token hợp lệ."
            
            set_token_btn = gr.Button("Đặt Token")
            token_status = gr.Textbox(label="Trạng thái", interactive=False)
            
            set_token_btn.click(fn=set_token, inputs=hf_token_input, outputs=token_status)
            
        # Thêm tab thông tin về ZeroGPU
        with gr.Tab("Thông tin GPU"):
            gr.Markdown("### Thông tin về ZeroGPU")
            gr.Markdown("""
            Ứng dụng này sử dụng ZeroGPU của Hugging Face Spaces để tối ưu việc sử dụng GPU.
            
            ZeroGPU giúp giải phóng bộ nhớ GPU khi không sử dụng, giúp tiết kiệm tài nguyên và cải thiện hiệu suất.
            
            Khi bạn tạo âm thanh, GPU sẽ được sử dụng tự động và giải phóng sau khi hoàn thành.
            """)
            
            def check_gpu():
                if torch.cuda.is_available():
                    gpu_name = torch.cuda.get_device_name(0)
                    gpu_memory = torch.cuda.get_device_properties(0).total_memory / (1024**3)
                    return f"GPU: {gpu_name}\nBộ nhớ: {gpu_memory:.2f} GB"
                else:
                    return "Không tìm thấy GPU. Ứng dụng sẽ chạy trên CPU."
            
            check_gpu_btn = gr.Button("Kiểm tra GPU")
            gpu_info = gr.Textbox(label="Thông tin GPU", interactive=False)
            
            check_gpu_btn.click(fn=check_gpu, inputs=None, outputs=gpu_info)
        
        # Kết nối các thành phần
        generate_btn.click(
            fn=generate_speech_simple,
            inputs=[
                text_input,
                speaker_id,
                max_duration,
                temperature,
                top_k
            ],
            outputs=output_audio
        )
        
        generate_context_btn.click(
            fn=generate_speech,
            inputs=[
                text_input_context,
                speaker_id_context,
                context_audio1,
                context_text1,
                context_speaker1,
                context_audio2,
                context_text2,
                context_speaker2,
                max_duration_context,
                temperature_context,
                top_k_context
            ],
            outputs=output_audio_context
        )
        
        # Tải mô hình khi khởi động
        demo.load(fn=load_model)
    
    return demo

# Khởi chạy ứng dụng
if __name__ == "__main__":
    demo = create_demo()
    demo.queue().launch()