Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -221,8 +221,25 @@ HEADER_HTML = """
|
|
| 221 |
# =====================================================
|
| 222 |
# MAIN APP
|
| 223 |
# =====================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
with gr.Blocks(css=GLOBAL_CSS) as demo:
|
| 225 |
gr.HTML(HEADER_HTML)
|
|
|
|
| 226 |
with gr.Tabs():
|
| 227 |
# ========== CLONE TAB ==========
|
| 228 |
with gr.Tab("Clone Voice"):
|
|
@@ -239,7 +256,7 @@ with gr.Blocks(css=GLOBAL_CSS) as demo:
|
|
| 239 |
|
| 240 |
# === CỘT PHẢI: KẾT QUẢ CLONE ===
|
| 241 |
with gr.Column():
|
| 242 |
-
gr.HTML('''<div class="audio-box" style="display:flex;flex-direction:column;gap:8px;"><div style="display:flex;align-items:center;gap:8px;width:100%;"><span style="flex-shrink:0;font-weight:600;">Kết quả Clone</span><audio controls style="flex-grow:1;height:28px;margin-left:8px;"><source src="result.mp3" type="audio/mpeg"></audio></div><div class="clone-control" style="display:flex;align-items:center;justify-content:space-between;width:100%;margin-top:8px;"><button style="width:
|
| 243 |
|
| 244 |
|
| 245 |
# ========== TTS TAB ==========
|
|
@@ -250,7 +267,7 @@ with gr.Blocks(css=GLOBAL_CSS) as demo:
|
|
| 250 |
gr.HTML("<div>⏳ Hạn sử dụng: 0/30 ngày</div>")
|
| 251 |
with gr.Row(elem_id="tts_cols"):
|
| 252 |
with gr.Column():# <-- đây là CỘT TRÁI (Voice + Tốc độ)
|
| 253 |
-
gr.HTML('''<div class="audio-box" style="position:relative;"><div style="display:flex;align-items:center;justify-content:space-between;"><span style="font-weight:600;">Chọn giọng</span><div id="voice-select" style="border:1px solid #ccc;border-radius:8px;padding:6px 12px;width:60%;display:flex;align-items:center;justify-content:space-between;cursor:pointer;"><span id="selected-voice">Giọng A</span><span style="color:#555;">▸</span></div></div><div id="voice-dropdown" style="display:none;position:absolute;bottom:100%;left:0;width:100%;background:#fff;border:1px solid #ccc;border-radius:8px;box-shadow:0 2px 6px rgba(0,0,0,0.15);margin-bottom:6px;z-index:1000;overflow-y:auto;max-height:220px;padding:4px 0;">''' + ''.join([f"<div class='voice-item' style='display:flex;align-items:center;justify-content:space-between;padding:6px 12px;border-bottom:1px solid #eee;'><span>{v}</span><div style='display:flex;align-items:center;gap:10px;'><button class='voice-play' data-voice='{v}' style='background:#000;color:#fff;border:none;width:26px;height:26px;border-radius:4px;font-weight:bold;cursor:pointer;'>▶</button><div class='voice-radio' data-voice='{v}' style='width:16px;height:16px;border:2px solid #000;border-radius:50%;cursor:pointer;'></div></div></div>" for v in ["Giọng A","Giọng B","Giọng C","Giọng D","Giọng E","Giọng F","Giọng G","Giọng H","Giọng I","Giọng J"]]) + '''</div><div id="file-name" style="font-size:13px;color:#444;margin-top:6px;text-align:left;">Tên file mp3: <i>chưa tải</i></div><div style="display:flex;align-items:center;justify-content:space-between;margin-top:10px;"><span style="flex-shrink:0;">Tốc độ giọng đọc</span><input id="speed-slider" type="range" min="0.5" max="2" step="0.1" value="1" style="width:60%;height:4px;border-radius:4px;background:#555;appearance:none;cursor:pointer;"><span id="speed-value">1.0x</span></div><script>const sel=document.getElementById("voice-select");const drop=document.getElementById("voice-dropdown");const selName=document.getElementById("selected-voice");sel.onclick=()=>{drop.style.display=drop.style.display==="block"?"none":"block";};document.querySelectorAll(".voice-radio").forEach(r=>r.onclick=()=>{document.querySelectorAll(".voice-radio").forEach(x=>x.style.background='transparent');r.style.background='#0078ff';selName.textContent=r.dataset.voice;drop.style.display='none';});document.querySelectorAll(".voice-play").forEach(p=>p.onclick=()=>{const v=p.dataset.voice;if(p.textContent==='▶'){p.textContent='⏸';const a=new Audio('assets/sample_audio.mp3');a.play();a.onended=()=>{p.textContent='▶';};}else{p.textContent='▶';}});const s=document.getElementById('speed-slider');const val=document.getElementById('speed-value');s.oninput=()=>{val.textContent=parseFloat(s.value).toFixed(1)+'x';};</script><style>input[type="range"]::-webkit-slider-thumb{appearance:none;width:9px;height:9px;border-radius:50%;background:#000;cursor:pointer;}input[type="range"]::-moz-range-thumb{width:9px;height:9px;border-radius:50%;background:#000;cursor:pointer;}</style></div>''')
|
| 254 |
with gr.Column():# <-- đây là CỘT PHẢI (Kết quả TTS)
|
| 255 |
gr.HTML('''<div class="audio-box" style="display:flex;flex-direction:column;gap:8px;"><div style="display:flex;align-items:center;gap:8px;width:100%;"><span style="flex-shrink:0;font-weight:600;">Kết quả TTS</span><audio controls style="flex-grow:1;height:28px;margin-left:8px;"><source src="result.mp3" type="audio/mpeg"></audio></div><div class="clone-control" style="display:flex;align-items:center;justify-content:space-between;width:100%;margin-top:8px;"><button style="width:110px;background:#555;color:#fff;border:none;border-radius:20px;padding:6px 0;font-size:14px;cursor:pointer;" onclick="(function(){let a=document.querySelector('audio');let src=a?(a.currentSrc||a.src):null;if(!src){alert('Không có file');return;}let link=document.createElement('a');link.href=src;link.download='tts_result.mp3';document.body.appendChild(link);link.click();document.body.removeChild(link);})()">⬇ Tải xuống</button><div id="tts-status" style="text-align:center;white-space:nowrap;font-weight:500;flex-grow:1;">Chưa bắt đầu</div><button style="width:120px;background:#555;color:#fff;border:none;border-radius:20px;padding:6px 0;font-size:14px;cursor:pointer;" onclick="(function(){let s=document.getElementById('tts-status');s.innerHTML='<div class=\\'loading-spinner\\'></div>';setTimeout(()=>{s.innerText='✅ Đã hoàn thành';},4000);})()">🚀 Bắt đầu TTS</button></div><style>.clone-control input[type=range]{height:4px;background:#000;}</style></div>''')
|
| 256 |
|
|
|
|
| 221 |
# =====================================================
|
| 222 |
# MAIN APP
|
| 223 |
# =====================================================
|
| 224 |
+
GLOBAL_CSS = """
|
| 225 |
+
/* Style cho thanh tốc độ đọc */
|
| 226 |
+
input[type="range"] {
|
| 227 |
+
accent-color: #555 !important;
|
| 228 |
+
height: 4px !important;
|
| 229 |
+
width: 100% !important;
|
| 230 |
+
border-radius: 2px !important;
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
/* Căn giữa thanh slider */
|
| 234 |
+
div.svelte-1ipelgc {
|
| 235 |
+
margin-top: 4px !important;
|
| 236 |
+
margin-bottom: 8px !important;
|
| 237 |
+
width: 100% !important;
|
| 238 |
+
}
|
| 239 |
+
"""
|
| 240 |
with gr.Blocks(css=GLOBAL_CSS) as demo:
|
| 241 |
gr.HTML(HEADER_HTML)
|
| 242 |
+
gr.HTML("<style>#char_usage_row{position:relative;margin:0!important;padding:0!important;height:auto!important;} #char_usage_row>div{display:flex;justify-content:space-between;align-items:center;width:100%;margin:0;padding:0;} #char_usage_row>div>div:first-child{margin:0;padding:0;} #char_usage_row>div>div:nth-child(2){position:absolute;left:50%;transform:translateX(-50%);margin:0;padding:0;} #clone_cols,#tts_cols{margin-top:0!important;padding-top:0!important;} .gradio-tabs .tab-content{padding-top:0!important;margin-top:0!important;} </style>")
|
| 243 |
with gr.Tabs():
|
| 244 |
# ========== CLONE TAB ==========
|
| 245 |
with gr.Tab("Clone Voice"):
|
|
|
|
| 256 |
|
| 257 |
# === CỘT PHẢI: KẾT QUẢ CLONE ===
|
| 258 |
with gr.Column():
|
| 259 |
+
gr.HTML('''<div class="audio-box" style="display:flex;flex-direction:column;gap:8px;"><div style="display:flex;align-items:center;gap:8px;width:100%;"><span style="flex-shrink:0;font-weight:600;">Kết quả Clone</span><audio controls style="flex-grow:1;height:28px;margin-left:8px;"><source src="result.mp3" type="audio/mpeg"></audio></div><div class="clone-control" style="display:flex;align-items:center;justify-content:space-between;width:100%;margin-top:8px;"><button style="width:130px;background:#555;color:#fff;border:none;border-radius:20px;padding:6px 0;font-size:14px;cursor:pointer;" onclick="(function(){let a=document.querySelector('audio');let src=a?(a.currentSrc||a.src):null;if(!src){alert('Không có file để tải');return;}let link=document.createElement('a');link.href=src;link.download='clone_result.mp3';document.body.appendChild(link);link.click();document.body.removeChild(link);})()">⬇ Tải xuống</button><div id="clone-status" style="text-align:center;white-space:nowrap;font-weight:500;flex-grow:1;">Chưa bắt đầu</div><button style="width:110px;background:#555;color:#fff;border:none;border-radius:20px;padding:6px 0;font-size:14px;cursor:pointer;" onclick="(function(){let s=document.getElementById('clone-status');s.innerHTML='<div class=\\'loading-spinner\\'></div>';setTimeout(()=>{s.innerText='✅ Đã hoàn thành';},4000);})()">🚀 Bắt đầu Clone</button></div></div>''')
|
| 260 |
|
| 261 |
|
| 262 |
# ========== TTS TAB ==========
|
|
|
|
| 267 |
gr.HTML("<div>⏳ Hạn sử dụng: 0/30 ngày</div>")
|
| 268 |
with gr.Row(elem_id="tts_cols"):
|
| 269 |
with gr.Column():# <-- đây là CỘT TRÁI (Voice + Tốc độ)
|
| 270 |
+
gr.HTML('''<div class="audio-box" style="position:relative;"><div style="display:flex;align-items:center;justify-content:space-between;"><span style="font-weight:600;">Chọn giọng để Text to Speech</span><div id="voice-select" style="border:1px solid #ccc;border-radius:8px;padding:6px 12px;width:60%;display:flex;align-items:center;justify-content:space-between;cursor:pointer;"><span id="selected-voice">Giọng A</span><span style="color:#555;">▸</span></div></div><div id="voice-dropdown" style="display:none;position:absolute;bottom:100%;left:0;width:100%;background:#fff;border:1px solid #ccc;border-radius:8px;box-shadow:0 2px 6px rgba(0,0,0,0.15);margin-bottom:6px;z-index:1000;overflow-y:auto;max-height:220px;padding:4px 0;">''' + ''.join([f"<div class='voice-item' style='display:flex;align-items:center;justify-content:space-between;padding:6px 12px;border-bottom:1px solid #eee;'><span>{v}</span><div style='display:flex;align-items:center;gap:10px;'><button class='voice-play' data-voice='{v}' style='background:#000;color:#fff;border:none;width:26px;height:26px;border-radius:4px;font-weight:bold;cursor:pointer;'>▶</button><div class='voice-radio' data-voice='{v}' style='width:16px;height:16px;border:2px solid #000;border-radius:50%;cursor:pointer;'></div></div></div>" for v in ["Giọng A","Giọng B","Giọng C","Giọng D","Giọng E","Giọng F","Giọng G","Giọng H","Giọng I","Giọng J"]]) + '''</div><div id="file-name" style="font-size:13px;color:#444;margin-top:6px;text-align:left;">Tên file mp3: <i>chưa tải</i></div><div style="display:flex;align-items:center;justify-content:space-between;margin-top:10px;"><span style="flex-shrink:0;">Tốc độ giọng đọc</span><input id="speed-slider" type="range" min="0.5" max="2" step="0.1" value="1" style="width:60%;height:4px;border-radius:4px;background:#555;appearance:none;cursor:pointer;"><span id="speed-value">1.0x</span></div><script>const sel=document.getElementById("voice-select");const drop=document.getElementById("voice-dropdown");const selName=document.getElementById("selected-voice");sel.onclick=()=>{drop.style.display=drop.style.display==="block"?"none":"block";};document.querySelectorAll(".voice-radio").forEach(r=>r.onclick=()=>{document.querySelectorAll(".voice-radio").forEach(x=>x.style.background='transparent');r.style.background='#0078ff';selName.textContent=r.dataset.voice;drop.style.display='none';});document.querySelectorAll(".voice-play").forEach(p=>p.onclick=()=>{const v=p.dataset.voice;if(p.textContent==='▶'){p.textContent='⏸';const a=new Audio('assets/sample_audio.mp3');a.play();a.onended=()=>{p.textContent='▶';};}else{p.textContent='▶';}});const s=document.getElementById('speed-slider');const val=document.getElementById('speed-value');s.oninput=()=>{val.textContent=parseFloat(s.value).toFixed(1)+'x';};</script><style>input[type="range"]::-webkit-slider-thumb{appearance:none;width:9px;height:9px;border-radius:50%;background:#000;cursor:pointer;}input[type="range"]::-moz-range-thumb{width:9px;height:9px;border-radius:50%;background:#000;cursor:pointer;}</style></div>''')
|
| 271 |
with gr.Column():# <-- đây là CỘT PHẢI (Kết quả TTS)
|
| 272 |
gr.HTML('''<div class="audio-box" style="display:flex;flex-direction:column;gap:8px;"><div style="display:flex;align-items:center;gap:8px;width:100%;"><span style="flex-shrink:0;font-weight:600;">Kết quả TTS</span><audio controls style="flex-grow:1;height:28px;margin-left:8px;"><source src="result.mp3" type="audio/mpeg"></audio></div><div class="clone-control" style="display:flex;align-items:center;justify-content:space-between;width:100%;margin-top:8px;"><button style="width:110px;background:#555;color:#fff;border:none;border-radius:20px;padding:6px 0;font-size:14px;cursor:pointer;" onclick="(function(){let a=document.querySelector('audio');let src=a?(a.currentSrc||a.src):null;if(!src){alert('Không có file');return;}let link=document.createElement('a');link.href=src;link.download='tts_result.mp3';document.body.appendChild(link);link.click();document.body.removeChild(link);})()">⬇ Tải xuống</button><div id="tts-status" style="text-align:center;white-space:nowrap;font-weight:500;flex-grow:1;">Chưa bắt đầu</div><button style="width:120px;background:#555;color:#fff;border:none;border-radius:20px;padding:6px 0;font-size:14px;cursor:pointer;" onclick="(function(){let s=document.getElementById('tts-status');s.innerHTML='<div class=\\'loading-spinner\\'></div>';setTimeout(()=>{s.innerText='✅ Đã hoàn thành';},4000);})()">🚀 Bắt đầu TTS</button></div><style>.clone-control input[type=range]{height:4px;background:#000;}</style></div>''')
|
| 273 |
|