import { client } from "./client.mjs"; import { html, create, styled } from "./misc.mjs"; const sample_texts = [ { text: "天气预报显示,今天会有小雨,请大家出门时记得带伞。降温的天气也提醒我们要适时添衣保暖。", }, { text: "公司的年度总结会议将在下周三举行,请各部门提前准备好相关材料,确保会议顺利进行。", }, { text: "今天的午餐菜单包括烤鸡、沙拉和蔬菜汤,大家可以根据自己的口味选择适合的菜品。", }, { text: "请注意,电梯将在下午两点进行例行维护,预计需要一个小时的时间,请大家在此期间使用楼梯。", }, { text: "图书馆新到了一批书籍,涵盖了文学、科学和历史等多个领域,欢迎大家前来借阅。", }, ]; let history_index = 0; const useStore = create((set, get) => ({ tts: { text: "你好,这里是一段ChatTTS Forge项目的示例文本。", spk: "female2", style: "chat", temperature: 0.3, top_P: 1, top_K: 20, seed: -1, format: "mp3", prompt1: "", prompt2: "", prefix: "", }, styles: [], speakers: [], ui: { loading: false, // 历史生成结果 { audio: Blob, url: string, params: object } history: [], }, async synthesizeTTS() { const params = structuredClone(get().tts); const blob = await client.synthesizeTTS({ ...params, }); const blob_url = URL.createObjectURL(blob); set({ ui: { ...get().ui, history: [ ...get().ui.history, { id: history_index++, audio: blob, url: blob_url, params: params, }, ], }, }); }, setStyles(styles) { set({ styles }); }, setSpeakers(speakers) { set({ speakers }); }, setTTS(tts) { set({ tts: { ...get().tts, ...tts, }, }); }, setUI(ui) { set({ ui: { ...get().ui, ...ui, }, }); }, })); window.addEventListener("load", async () => { const styles = await client.listStyles(); const speakers = await client.listSpeakers(); console.log("styles:", styles); console.log("speakers:", speakers); useStore.get().setStyles(styles.data); useStore.get().setSpeakers(speakers.data); }); const TTSPageContainer = styled.div` h1 { margin-bottom: 1rem; } p { margin-bottom: 1rem; } #app { margin-top: 1rem; } textarea { width: 100%; height: 10rem; margin-bottom: 1rem; min-height: 10rem; resize: vertical; } button { padding: 0.5rem 1rem; background-color: #007bff; color: white; border: none; cursor: pointer; } button:hover { background-color: #0056b3; } button:disabled { background-color: #6c757d; cursor: not-allowed; } fieldset { margin-top: 1rem; padding: 1rem; border: 1px solid #333; } legend { font-weight: bold; } label { display: block; margin-bottom: 0.5rem; } select, input[type="range"], input[type="number"] { width: 100%; margin-top: 0.25rem; } input[type="range"] { width: calc(100% - 2rem); } input[type="number"] { width: calc(100% - 2rem); padding: 0.5rem; } input[type="text"] { width: 100%; padding: 0.5rem; } audio { margin-top: 1rem; } textarea, input, select { background-color: #333; color: white; border: 1px solid #333; border-radius: 0.25rem; padding: 0.5rem; } table { width: 100%; border-collapse: collapse; } th, td { padding: 0.5rem; border: 1px solid #333; } th { background-color: #333; color: white; } th:nth-child(2), td:nth-child(2) { width: 60%; } .content-body { display: flex; gap: 1rem; } .content-left { flex: 1; } .content-right { flex: 4; } h1 small { font-weight: 100; font-size: 0.5em; font-weight: normal; } .btn-synthesize { background-color: #007bff; color: white; border: none; cursor: pointer; padding: 0.5rem 1rem; } .btn-synthesize:hover { background-color: #0056b3; } .btn-synthesize:disabled { background-color: #6c757d; cursor: not-allowed; } .btn-clear { background-color: #dc3545; color: white; border: none; cursor: pointer; padding: 0.5rem 1rem; } .btn-clear:hover { background-color: #bd2130; } .btn-clear:disabled { background-color: #6c757d; cursor: not-allowed; } .btn-random { background-color: #28a745; color: white; border: none; cursor: pointer; padding: 0.5rem 1rem; } .btn-random:hover { background-color: #218838; } pre { white-space: pre-wrap; } .sample-texts { width: unset; display: inline-block; padding: 0.5rem; margin-bottom: 1rem; } `; export const TTSPage = () => { const { tts, setTTS, synthesizeTTS, ui, setUI, speakers, styles } = useStore(); const request = async () => { if (ui.loading) { return; } setUI({ loading: true }); try { await synthesizeTTS(); } catch (error) { console.error("Error synthesizing TTS:", error); } finally { setUI({ loading: false }); } }; return html` <${TTSPageContainer}>