Add save progress UI and fix MMS errors
Show a progress bar during MP3 generation, update styles, and improve MMS error messaging.
This commit is contained in:
@@ -5,10 +5,47 @@ const editBtn = document.getElementById("edit-btn");
|
||||
const deleteBtn = document.getElementById("delete-btn");
|
||||
const cancelBtn = document.getElementById("cancel-btn");
|
||||
const downloadLink = document.getElementById("download-link");
|
||||
const progressWrap = document.getElementById("save-progress");
|
||||
const progressBar = document.getElementById("save-progress-bar");
|
||||
|
||||
let items = [];
|
||||
let editMode = false;
|
||||
const selectedIds = new Set();
|
||||
let progressTimer = null;
|
||||
|
||||
function startProgress() {
|
||||
let value = 0;
|
||||
progressWrap.classList.remove("hidden");
|
||||
progressBar.style.width = "0%";
|
||||
progressBar.setAttribute("aria-valuenow", "0");
|
||||
|
||||
if (progressTimer) {
|
||||
clearInterval(progressTimer);
|
||||
}
|
||||
|
||||
progressTimer = setInterval(() => {
|
||||
value = Math.min(value + Math.random() * 8 + 2, 90);
|
||||
progressBar.style.width = `${value}%`;
|
||||
progressBar.setAttribute("aria-valuenow", `${Math.round(value)}`);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function finishProgress(success = true) {
|
||||
if (progressTimer) {
|
||||
clearInterval(progressTimer);
|
||||
progressTimer = null;
|
||||
}
|
||||
|
||||
progressBar.style.width = "100%";
|
||||
progressBar.setAttribute("aria-valuenow", "100");
|
||||
|
||||
const delay = success ? 400 : 1200;
|
||||
setTimeout(() => {
|
||||
progressBar.style.width = "0%";
|
||||
progressBar.setAttribute("aria-valuenow", "0");
|
||||
progressWrap.classList.add("hidden");
|
||||
}, delay);
|
||||
}
|
||||
|
||||
function setEditMode(isEdit) {
|
||||
editMode = isEdit;
|
||||
@@ -69,6 +106,7 @@ async function handleSave() {
|
||||
return;
|
||||
}
|
||||
|
||||
startProgress();
|
||||
const res = await fetch("/api/tts", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -78,12 +116,14 @@ async function handleSave() {
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({}));
|
||||
alert(err.detail || "저장에 실패했습니다.");
|
||||
finishProgress(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const created = await res.json();
|
||||
items.unshift(created);
|
||||
renderList();
|
||||
finishProgress(true);
|
||||
}
|
||||
|
||||
async function handleItemClick(item) {
|
||||
|
||||
@@ -65,6 +65,21 @@ button.danger {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.progress-wrap {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
background: #f1d9a6;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background: #f5a623;
|
||||
transition: width 0.2s ease;
|
||||
}
|
||||
|
||||
.tts-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
|
||||
@@ -12,6 +12,16 @@
|
||||
<div class="panel-header">입력 텍스트</div>
|
||||
<textarea id="text-input" rows="16" placeholder="텍스트를 입력하세요"></textarea>
|
||||
<button id="save-btn" class="primary">mp3 저장</button>
|
||||
<div id="save-progress" class="progress-wrap hidden" aria-label="저장 진행률">
|
||||
<div
|
||||
id="save-progress-bar"
|
||||
class="progress-bar"
|
||||
role="progressbar"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
aria-valuenow="0"
|
||||
></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel right">
|
||||
|
||||
@@ -32,6 +32,10 @@ def _get_mms():
|
||||
def _text_to_wav_mms(text: str, wav_path: str) -> None:
|
||||
try:
|
||||
import torch
|
||||
except Exception as exc:
|
||||
raise RuntimeError("MMS TTS 사용을 위해 torch/numpy가 정상 설치되어야 합니다.") from exc
|
||||
|
||||
try:
|
||||
import soundfile as sf
|
||||
except Exception as exc:
|
||||
raise RuntimeError("MMS TTS 사용을 위해 soundfile 설치가 필요합니다.") from exc
|
||||
|
||||
Reference in New Issue
Block a user