alethanhson commited on
Commit
e0668e2
·
1 Parent(s): 04817a7
Files changed (6) hide show
  1. .github/workflows/sync-to-hub.yml +20 -0
  2. .huggingface/space.yml +11 -0
  3. Procfile +1 -0
  4. README.md +32 -0
  5. app.py +194 -119
  6. requirements.txt +2 -2
.github/workflows/sync-to-hub.yml ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Sync to Hugging Face hub
2
+ on:
3
+ push:
4
+ branches: [main]
5
+
6
+ # to run this workflow manually from the Actions tab
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ sync-to-hub:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v3
14
+ with:
15
+ fetch-depth: 0
16
+ lfs: true
17
+ - name: Push to hub
18
+ env:
19
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
20
+ run: git push --force https://USER:[email protected]/spaces/USER/CSM-1B-GRADIO main
.huggingface/space.yml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ title: CSM-1B Gradio Demo
2
+ emoji: 🔊
3
+ colorFrom: indigo
4
+ colorTo: purple
5
+ sdk: gradio
6
+ sdk_version: 4.19.2
7
+ app_file: app.py
8
+ pinned: false
9
+ license: apache-2.0
10
+ models:
11
+ - sesame/csm-1b
Procfile ADDED
@@ -0,0 +1 @@
 
 
1
+ web: python app.py
README.md CHANGED
@@ -10,3 +10,35 @@ pinned: false
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
13
+
14
+ # CSM-1B Gradio Demo
15
+
16
+ Ứng dụng demo cho mô hình CSM-1B (Conversational Speech Model) sử dụng Gradio để tạo giao diện người dùng thân thiện.
17
+
18
+ ## Tính năng
19
+
20
+ - Chuyển đổi văn bản thành giọng nói tự nhiên
21
+ - Hỗ trợ nhiều giọng đọc khác nhau (ID người nói)
22
+ - Tạo giọng nói theo ngữ cảnh hội thoại
23
+ - Tùy chỉnh các tham số như nhiệt độ và độ dài âm thanh
24
+
25
+ ## Sử dụng
26
+
27
+ 1. Nhập văn bản bạn muốn chuyển thành giọng nói
28
+ 2. Chọn ID người nói (từ 0-10)
29
+ 3. Tùy chỉnh các thông số nâng cao (không bắt buộc)
30
+ 4. Thêm ngữ cảnh hội thoại nếu cần
31
+ 5. Nhấn "Tạo âm thanh" để nghe kết quả
32
+
33
+ ## Triển khai trên Hugging Face Spaces
34
+
35
+ Ứng dụng này được thiết kế để chạy trên Hugging Face Spaces. Để triển khai:
36
+
37
+ 1. Tạo một Space mới
38
+ 2. Upload mã nguồn lên Space
39
+ 3. Chọn Gradio là framework
40
+ 4. Chờ ứng dụng được xây dựng và khởi động
41
+
42
+ ## Tài nguyên
43
+
44
+ Mô hình CSM-1B của Sesame AI: [sesame/csm-1b](https://huggingface.co/sesame/csm-1b)
app.py CHANGED
@@ -1,134 +1,209 @@
1
- # import base64
2
- # import io
3
- # import logging
4
- # from typing import List, Optional
5
 
6
- # import torch
7
- # import torchaudio
8
- # import uvicorn
9
- # from fastapi import FastAPI, HTTPException
10
- # from fastapi.middleware.cors import CORSMiddleware
11
- # from pydantic import BaseModel
12
-
13
- # from generator import load_csm_1b, Segment
14
- # import gradio as gr
15
-
16
- # logging.basicConfig(level=logging.INFO)
17
- # logger = logging.getLogger(__name__)
18
-
19
- # app = FastAPI(
20
- # title="CSM 1B API",
21
- # description="API for Sesame's Conversational Speech Model",
22
- # version="1.0.0",
23
- # )
24
-
25
- # app.add_middleware(
26
- # CORSMiddleware,
27
- # allow_origins=["*"],
28
- # allow_credentials=True,
29
- # allow_methods=["*"],
30
- # allow_headers=["*"],
31
- # )
32
-
33
- # generator = None
34
 
35
- # class SegmentRequest(BaseModel):
36
- # speaker: int
37
- # text: str
38
- # audio_base64: Optional[str] = None
39
 
40
- # class GenerateAudioRequest(BaseModel):
41
- # text: str
42
- # speaker: int
43
- # context: List[SegmentRequest] = []
44
- # max_audio_length_ms: float = 10000
45
- # temperature: float = 0.9
46
- # topk: int = 50
47
 
48
- # class AudioResponse(BaseModel):
49
- # audio_base64: str
50
- # sample_rate: int
51
 
52
- # @app.on_event("startup")
53
- # async def startup_event():
54
- # global generator
55
- # logger.info("Loading CSM 1B model...")
56
 
57
- # device = "cuda" if torch.cuda.is_available() else "cpu"
58
- # if device == "cpu":
59
- # logger.info("Loading CSM 1B model...")
60
- # logger.warning("GPU not available. Using CPU, performance may be slow!")
61
- # logger.info(f"Using device: {device}")
62
- # try:
63
- # generator = load_csm_1b(device=device)
64
- # logger.info(f"Model loaded successfully on device: {device}")
65
- # except Exception as e:
66
- # logger.error(f"Could not load model: {str(e)}")
67
- # raise e
68
-
69
- # @app.post("/generate-audio", response_model=AudioResponse)
70
- # async def generate_audio(request: GenerateAudioRequest):
71
- # global generator
72
 
73
- # if generator is None:
74
- # raise HTTPException(status_code=503, detail="Model not loaded. Please try again later.")
 
 
 
 
 
 
 
 
75
 
76
- # try:
77
- # context_segments = []
78
- # for segment in request.context:
79
- # if segment.audio_base64:
80
- # audio_bytes = base64.b64decode(segment.audio_base64)
81
- # audio_buffer = io.BytesIO(audio_bytes)
82
-
83
- # audio_tensor, sample_rate = torchaudio.load(audio_buffer)
84
- # audio_tensor = torchaudio.functional.resample(
85
- # audio_tensor.squeeze(0),
86
- # orig_freq=sample_rate,
87
- # new_freq=generator.sample_rate
88
- # )
89
- # else:
90
- # audio_tensor = torch.zeros(0, dtype=torch.float32)
91
-
92
- # context_segments.append(
93
- # Segment(text=segment.text, speaker=segment.speaker, audio=audio_tensor)
94
- # )
95
 
96
- # audio = generator.generate(
97
- # text=request.text,
98
- # speaker=request.speaker,
99
- # context=context_segments,
100
- # max_audio_length_ms=request.max_audio_length_ms,
101
- # temperature=request.temperature,
102
- # topk=request.topk,
103
- # )
 
104
 
105
- # buffer = io.BytesIO()
106
- # torchaudio.save(buffer, audio.unsqueeze(0).cpu(), generator.sample_rate, format="wav")
107
- # # torchaudio.save("audio.wav", audio.unsqueeze(0).cpu(), generator.sample_rate)
108
- # buffer.seek(0)
109
- # # audio_base64 = base64.b64encode(buffer.read()).decode("utf-8")
110
 
111
- # return AudioResponse(
112
- # content=buffer.read(),
113
- # media_type="audio/wav",
114
- # headers={"Content-Disposition": "attachment; filename=audio.wav"}
115
- # )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
- # except Exception as e:
118
- # logger.error(f"error when building audio: {str(e)}")
119
- # raise HTTPException(status_code=500, detail=f"error when building audio: {str(e)}")
120
-
121
- # @app.get("/health")
122
- # async def health_check():
123
- # if generator is None:
124
- # return {"status": "not_ready", "message": "Model is loading"}
125
- # return {"status": "ready", "message": "API is ready to serve"}
126
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
- import gradio as gr
 
129
 
130
- def greet(name):
131
- return "Hello " + name + "!!"
132
 
133
- demo = gr.Interface(fn=greet, inputs="text", outputs="text")
134
- demo.launch()
 
1
+ import base64
2
+ import io
3
+ import logging
4
+ from typing import List
5
 
6
+ import torch
7
+ import torchaudio
8
+ import gradio as gr
9
+ import numpy as np
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
+ from generator import load_csm_1b, Segment
 
 
 
12
 
13
+ logging.basicConfig(level=logging.INFO)
14
+ logger = logging.getLogger(__name__)
 
 
 
 
 
15
 
16
+ generator = None
 
 
17
 
18
+ def initialize_model():
19
+ global generator
20
+ logger.info("Đang tải mô hình CSM 1B...")
 
21
 
22
+ device = "cuda" if torch.cuda.is_available() else "cpu"
23
+ if device == "cpu":
24
+ logger.warning("GPU không khả dụng. Sử dụng CPU, hiệu suất có thể chậm!")
25
+ logger.info(f"Sử dụng thiết bị: {device}")
 
 
 
 
 
 
 
 
 
 
 
26
 
27
+ try:
28
+ generator = load_csm_1b(device=device)
29
+ logger.info(f"Mô hình đã được tải thành công trên thiết bị: {device}")
30
+ return True
31
+ except Exception as e:
32
+ logger.error(f"Không thể tải mô hình: {str(e)}")
33
+ return False
34
+
35
+ def generate_speech(text, speaker_id, max_audio_length_ms=10000, temperature=0.9, topk=50, context_texts=None, context_speakers=None):
36
+ global generator
37
 
38
+ if generator is None:
39
+ if not initialize_model():
40
+ return None, "Không thể tải mô hình. Vui lòng thử lại sau."
41
+
42
+ try:
43
+ # Xử lý context nếu được cung cấp
44
+ context_segments = []
45
+ if context_texts and context_speakers:
46
+ for ctx_text, ctx_speaker in zip(context_texts, context_speakers):
47
+ if ctx_text and ctx_speaker is not None:
48
+ context_segments.append(
49
+ Segment(text=ctx_text, speaker=int(ctx_speaker), audio=torch.zeros(0, dtype=torch.float32))
50
+ )
 
 
 
 
 
 
51
 
52
+ # Tạo âm thanh từ văn bản
53
+ audio = generator.generate(
54
+ text=text,
55
+ speaker=int(speaker_id),
56
+ context=context_segments,
57
+ max_audio_length_ms=float(max_audio_length_ms),
58
+ temperature=float(temperature),
59
+ topk=int(topk),
60
+ )
61
 
62
+ # Chuyển đổi tensor thành numpy array để Gradio có thể xử lý
63
+ audio_numpy = audio.cpu().numpy()
64
+ sample_rate = generator.sample_rate
 
 
65
 
66
+ return (sample_rate, audio_numpy), None
67
+
68
+ except Exception as e:
69
+ logger.error(f"Lỗi khi tạo âm thanh: {str(e)}")
70
+ return None, f"Lỗi khi tạo âm thanh: {str(e)}"
71
+
72
+ def clear_context():
73
+ return [], []
74
+
75
+ def add_context(text, speaker_id, context_texts, context_speakers):
76
+ if text and speaker_id is not None:
77
+ context_texts.append(text)
78
+ context_speakers.append(int(speaker_id))
79
+ return context_texts, context_speakers
80
+
81
+ # Thiết lập giao diện Gradio
82
+ with gr.Blocks(title="CSM 1B Demo") as demo:
83
+ gr.Markdown("# CSM 1B - Mô hình tạo giọng nói hội thoại")
84
+ gr.Markdown("Nhập văn bản để tạo giọng nói tự nhiên với mô hình CSM 1B")
85
+
86
+ with gr.Row():
87
+ with gr.Column(scale=2):
88
+ text_input = gr.Textbox(
89
+ label="Văn bản để chuyển thành giọng nói",
90
+ placeholder="Nhập văn bản ở đây...",
91
+ lines=3
92
+ )
93
+ speaker_id = gr.Slider(
94
+ label="ID người nói",
95
+ minimum=0,
96
+ maximum=10,
97
+ step=1,
98
+ value=0
99
+ )
100
+
101
+ with gr.Accordion("Tùy chọn nâng cao", open=False):
102
+ max_length = gr.Slider(
103
+ label="Độ dài tối đa (mili giây)",
104
+ minimum=1000,
105
+ maximum=30000,
106
+ step=1000,
107
+ value=10000
108
+ )
109
+ temp = gr.Slider(
110
+ label="Nhiệt độ",
111
+ minimum=0.1,
112
+ maximum=1.5,
113
+ step=0.1,
114
+ value=0.9
115
+ )
116
+ top_k = gr.Slider(
117
+ label="Top K",
118
+ minimum=10,
119
+ maximum=100,
120
+ step=10,
121
+ value=50
122
+ )
123
+
124
+ with gr.Accordion("Ngữ cảnh hội thoại", open=False):
125
+ context_list = gr.State([])
126
+ context_speakers_list = gr.State([])
127
+
128
+ with gr.Row():
129
+ context_text = gr.Textbox(label="Văn bản ngữ cảnh", lines=2)
130
+ context_speaker = gr.Slider(
131
+ label="ID người nói ngữ cảnh",
132
+ minimum=0,
133
+ maximum=10,
134
+ step=1,
135
+ value=0
136
+ )
137
+
138
+ with gr.Row():
139
+ add_ctx_btn = gr.Button("Thêm ngữ cảnh")
140
+ clear_ctx_btn = gr.Button("Xóa tất cả ngữ cảnh")
141
+
142
+ context_display = gr.Dataframe(
143
+ headers=["Văn bản", "ID người nói"],
144
+ label="Ngữ cảnh hiện tại",
145
+ interactive=False
146
+ )
147
+
148
+ generate_btn = gr.Button("Tạo âm thanh", variant="primary")
149
 
150
+ with gr.Column(scale=1):
151
+ audio_output = gr.Audio(label="Âm thanh được tạo", type="numpy")
152
+ error_output = gr.Textbox(label="Thông báo lỗi", visible=False)
153
+
154
+ # Kết nối các sự kiện
155
+ generate_btn.click(
156
+ fn=generate_speech,
157
+ inputs=[
158
+ text_input,
159
+ speaker_id,
160
+ max_length,
161
+ temp,
162
+ top_k,
163
+ context_list,
164
+ context_speakers_list
165
+ ],
166
+ outputs=[audio_output, error_output]
167
+ )
168
+
169
+ add_ctx_btn.click(
170
+ fn=add_context,
171
+ inputs=[
172
+ context_text,
173
+ context_speaker,
174
+ context_list,
175
+ context_speakers_list
176
+ ],
177
+ outputs=[context_list, context_speakers_list]
178
+ )
179
+
180
+ clear_ctx_btn.click(
181
+ fn=clear_context,
182
+ inputs=[],
183
+ outputs=[context_list, context_speakers_list]
184
+ )
185
+
186
+ # Cập nhật hiển thị ngữ cảnh
187
+ def update_context_display(texts, speakers):
188
+ if not texts or not speakers:
189
+ return []
190
+ return [[text, speaker] for text, speaker in zip(texts, speakers)]
191
+
192
+ context_list.change(
193
+ fn=update_context_display,
194
+ inputs=[context_list, context_speakers_list],
195
+ outputs=[context_display]
196
+ )
197
+
198
+ context_speakers_list.change(
199
+ fn=update_context_display,
200
+ inputs=[context_list, context_speakers_list],
201
+ outputs=[context_display]
202
+ )
203
 
204
+ # Khởi động ứng dụng khi tải trang
205
+ initialize_model()
206
 
207
+ # Cấu hình cho Hugging Face Spaces
208
+ demo.launch(share=False)
209
 
 
 
requirements.txt CHANGED
@@ -7,7 +7,7 @@ moshi==0.2.2
7
  torchtune==0.4.0
8
  torchao==0.9.0
9
  silentcipher @ git+https://github.com/SesameAILabs/silentcipher@master
10
- fastapi
11
- uvicorn[standard]
12
  python-multipart==0.0.9
13
  pydantic==2.6.1
 
7
  torchtune==0.4.0
8
  torchao==0.9.0
9
  silentcipher @ git+https://github.com/SesameAILabs/silentcipher@master
10
+ gradio==4.19.2
11
+ numpy>=1.22.0
12
  python-multipart==0.0.9
13
  pydantic==2.6.1