Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
| window.allStyleEmbs = {} | |
| window.styleEmbsMenuState = { | |
| embeddingsDir: `${window.path}/embeddings`, | |
| hasChangedEmb: false, // For clearing the use of the editor state when re-generating a line with a different embedding | |
| selectedEmb: undefined, | |
| activatedEmbeddings: {} | |
| } | |
| window.loadStyleEmbsFromDisk = () => { | |
| window.allStyleEmbs = {} | |
| // Read the activated embeddings file | |
| window.styleEmbsMenuState.activatedEmbeddings = {} | |
| if (fs.existsSync(`./embeddings.txt`)) { | |
| const embeddingsEnabled = fs.readFileSync(`./embeddings.txt`, "utf8").split("\n") | |
| embeddingsEnabled.forEach(emb => { | |
| window.styleEmbsMenuState.activatedEmbeddings[emb.replace("*","")] = emb.includes("*") | |
| }) | |
| } | |
| // Read all the embedding files | |
| fs.mkdirSync(window.styleEmbsMenuState.embeddingsDir, {recursive: true}) | |
| const embFiles = fs.readdirSync(window.styleEmbsMenuState.embeddingsDir) | |
| embFiles.forEach(jsonFName => { | |
| const jsonData = JSON.parse(fs.readFileSync(`${window.styleEmbsMenuState.embeddingsDir}/${jsonFName}`)) | |
| jsonData.fileName = `${window.styleEmbsMenuState.embeddingsDir}/${jsonFName}` | |
| if (!Object.keys(window.styleEmbsMenuState.activatedEmbeddings).includes(jsonData.emb_id)) { | |
| window.styleEmbsMenuState.activatedEmbeddings[jsonData.emb_id] = true | |
| } | |
| jsonData.enabled = window.styleEmbsMenuState.activatedEmbeddings[jsonData.emb_id] | |
| window.allStyleEmbs[jsonData.voiceId] = window.allStyleEmbs[jsonData.voiceId] || [] | |
| window.allStyleEmbs[jsonData.voiceId].push(jsonData) | |
| }) | |
| window.saveEnabledStyleEmbs() | |
| } | |
| window.saveEnabledStyleEmbs = () => { | |
| fs.writeFileSync(`./embeddings.txt`, Object.keys(window.styleEmbsMenuState.activatedEmbeddings).map(key => { | |
| return `${window.styleEmbsMenuState.activatedEmbeddings[key]?"*":""}${key}` | |
| }).join("\n"), "utf8") | |
| } | |
| window.loadStyleEmbsFromDisk() | |
| window.resetStyleEmbFields = () => { | |
| styleEmbAuthorInput.value = "" | |
| styleEmbGameIdInput.value = "" | |
| styleEmbVoiceIdInput.value = "" | |
| styleEmbNameInput.value = "" | |
| styleEmbDescriptionInput.value = "" | |
| styleEmbIdInput.value = "" | |
| wavFilepathForEmbComputeInput.value = "" | |
| styleEmbValuesInput.value = "" | |
| styleEmbGameIdInput.value = window.currentGame.gameId | |
| if (window.currentModel) { | |
| styleEmbVoiceIdInput.value = window.currentModel.voiceId | |
| } | |
| } | |
| window.refreshStyleEmbsTable = () => { | |
| styleembsRecordsContainer.innerHTML = "" | |
| window.styleEmbsMenuState.selectedEmb = undefined | |
| styleEmbDelete.disabled = true | |
| window.resetStyleEmbFields() | |
| Object.keys(window.allStyleEmbs).sort().forEach(key => { | |
| window.allStyleEmbs[key].forEach((emb,ei) => { | |
| const record = createElem("div") | |
| const enabledCkbx = createElem("input", {type: "checkbox"}) | |
| enabledCkbx.checked = emb.enabled | |
| record.appendChild(createElem("div", enabledCkbx)) | |
| const embName = createElem("div", emb["embeddingName"]) | |
| embName.title = emb["embeddingName"] | |
| record.appendChild(embName) | |
| const embGameID = createElem("div", emb["gameId"]) | |
| embGameID.title = emb["gameId"] | |
| record.appendChild(embGameID) | |
| const embVoiceID = createElem("div", emb["voiceId"]) | |
| embVoiceID.title = emb["voiceId"] | |
| record.appendChild(embVoiceID) | |
| const embDescription = createElem("div", emb["description"]||"") | |
| embDescription.title = emb["description"]||"" | |
| record.appendChild(embDescription) | |
| const embID = createElem("div", emb["emb_id"]) | |
| embID.title = emb["emb_id"] | |
| record.appendChild(embID) | |
| const embVersion = createElem("div", emb["version"]||"1.0") | |
| embVersion.title = emb["version"]||"1.0" | |
| record.appendChild(embVersion) | |
| enabledCkbx.addEventListener("click", () => { | |
| window.allStyleEmbs[key][ei].enabled = !window.allStyleEmbs[key][ei].enabled | |
| window.styleEmbsMenuState.activatedEmbeddings[emb["emb_id"]] = window.allStyleEmbs[key][ei].enabled | |
| window.saveEnabledStyleEmbs() | |
| if (window.currentModel) { | |
| window.loadStyleEmbsForVoice(window.currentModel) | |
| } | |
| }) | |
| record.addEventListener("click", (e) => { | |
| if (e.target==enabledCkbx || e.target.nodeName=="BUTTON") { | |
| return | |
| } | |
| // Clear visual selection of the old selected item, if there was already an item selected before | |
| if (window.styleEmbsMenuState.selectedEmb) { | |
| window.styleEmbsMenuState.selectedEmb[0].style.background = "none" | |
| Array.from(window.styleEmbsMenuState.selectedEmb[0].children).forEach(child => child.style.color = "white") | |
| } | |
| window.styleEmbsMenuState.selectedEmb = [record, emb] | |
| // Visually show that this row is selected | |
| window.styleEmbsMenuState.selectedEmb[0].style.background = "white" | |
| Array.from(window.styleEmbsMenuState.selectedEmb[0].children).forEach(child => child.style.color = "black") | |
| styleEmbDelete.disabled = false | |
| // Populate the edit fields | |
| styleEmbAuthorInput.value = emb.author||"" | |
| styleEmbGameIdInput.value = emb.gameId||"" | |
| styleEmbVoiceIdInput.value = emb.voiceId||"" | |
| styleEmbNameInput.value = emb.embeddingName||"" | |
| styleEmbDescriptionInput.value = emb.description||"" | |
| styleEmbIdInput.value = emb.emb_id||"" | |
| wavFilepathForEmbComputeInput.value = "" | |
| styleEmbValuesInput.value = emb.emb||"" | |
| }) | |
| styleembsRecordsContainer.appendChild(record) | |
| }) | |
| }) | |
| } | |
| styleembs_main.addEventListener("click", (e) => { | |
| if (e.target == styleembs_main) { | |
| window.refreshStyleEmbsTable() | |
| } | |
| }) | |
| styleEmbSave.addEventListener("click", () => { | |
| const missingFieldsValues = [] | |
| if (!styleEmbAuthorInput.value.trim().length) { | |
| missingFieldsValues.push(window.i18n.AUTHOR) | |
| } | |
| if (!styleEmbGameIdInput.value.trim().length) { | |
| missingFieldsValues.push(window.i18n.GAME_ID) | |
| } | |
| if (!styleEmbVoiceIdInput.value.trim().length) { | |
| missingFieldsValues.push(window.i18n.VOICE_ID) | |
| } | |
| if (!styleEmbNameInput.value.trim().length) { | |
| missingFieldsValues.push(window.i18n.EMB_NAME) | |
| } | |
| if (!styleEmbIdInput.value.trim().length) { | |
| missingFieldsValues.push(window.i18n.EMB_ID) | |
| } | |
| if (!styleEmbValuesInput.value.trim().length) { | |
| missingFieldsValues.push(window.i18n.STYLE_EMB_VALUES) | |
| } | |
| if (missingFieldsValues.length) { | |
| window.errorModal(window.i18n.ERROR_MISSING_FIELDS.replace("_1", missingFieldsValues.join(", "))) | |
| } else { | |
| let outputFilename | |
| if (window.styleEmbsMenuState.selectedEmb) { | |
| outputFilename = window.styleEmbsMenuState.selectedEmb[1].fileName | |
| } else { | |
| outputFilename = `${window.styleEmbsMenuState.embeddingsDir}/${styleEmbVoiceIdInput.value.trim().toLowerCase()}.${styleEmbGameIdInput.value.trim().toLowerCase()}.${styleEmbIdInput.value.trim().toLowerCase()}.${styleEmbAuthorInput.value.trim().toLowerCase()}.json` | |
| } | |
| const jsonData = { | |
| "author": styleEmbAuthorInput.value.trim(), | |
| "version": "1.0", // Should I make this editable in the UI? | |
| "gameId": styleEmbGameIdInput.value.trim().toLowerCase(), | |
| "voiceId": styleEmbVoiceIdInput.value.trim().toLowerCase(), | |
| "description": styleEmbDescriptionInput.value.trim()||"", | |
| "embeddingName": styleEmbNameInput.value.trim(), | |
| "emb": styleEmbValuesInput.value.trim().split(",").map(v=>parseFloat(v)), | |
| "emb_id": styleEmbIdInput.value.trim() | |
| } | |
| fs.writeFileSync(outputFilename, JSON.stringify(jsonData, null, 4), "utf8") | |
| window.loadStyleEmbsFromDisk() | |
| window.refreshStyleEmbsTable() | |
| } | |
| if (window.currentModel) { | |
| window.loadStyleEmbsForVoice(window.currentModel) | |
| } | |
| }) | |
| styleEmbDelete.addEventListener("click", () => { | |
| window.confirmModal(window.i18n.CONFIRM_DELETE_STYLE_EMB).then(response => { | |
| if (response) { | |
| fs.unlinkSync(window.styleEmbsMenuState.selectedEmb[1].fileName) | |
| window.loadStyleEmbsFromDisk() | |
| window.refreshStyleEmbsTable() | |
| if (window.currentModel) { | |
| window.loadStyleEmbsForVoice(window.currentModel) | |
| } | |
| } | |
| }) | |
| }) | |
| // Return the default embedding, plus any other ones | |
| window.loadStyleEmbsForVoice = (currentModel) => { | |
| const embeddings = {} | |
| // Add the default option from the model json | |
| embeddings["default"] = [window.i18n.DEFAULT, currentModel.games[0].base_speaker_emb] // TODO, specialize to specific game? | |
| // Load any other style embeddings available | |
| if (Object.keys(window.allStyleEmbs).includes(currentModel.voiceId)) { | |
| window.allStyleEmbs[currentModel.voiceId].forEach(loadedStyleEmb => { | |
| if (loadedStyleEmb.enabled) { | |
| embeddings[loadedStyleEmb.emb_id] = [loadedStyleEmb.embeddingName, loadedStyleEmb.emb] | |
| } | |
| }) | |
| } | |
| // Add every option to the embeddings selection dropdown | |
| style_emb_select.innerHTML = "" | |
| Array.from(seq_edit_edit_select.children).forEach(option => { | |
| if (option.value.startsWith("style_")) { | |
| seq_edit_edit_select.removeChild(option) | |
| } | |
| }) | |
| // Add Default first | |
| const opt = createElem("option", embeddings["default"][0]) | |
| opt.value = embeddings["default"][1].join(",") | |
| style_emb_select.appendChild(opt) | |
| Object.keys(embeddings).forEach(key => { | |
| if (key=="default") { | |
| return | |
| } | |
| const opt = createElem("option", embeddings[key][0]) | |
| opt.value = embeddings[key][1].join(",") | |
| style_emb_select.appendChild(opt) | |
| }) | |
| // First remove all existing styles from the dropdown | |
| Array.from(seq_edit_view_select.children).forEach(elem => { | |
| if (elem.value.startsWith("style")) { | |
| seq_edit_view_select.removeChild(elem) | |
| } | |
| }) | |
| // Add every option (except Default) to the sliders viewing/editing dropdowns | |
| Object.keys(embeddings).forEach(key => { | |
| if (key=="default") { | |
| return | |
| } | |
| const opt = createElem("option", `${window.i18n.STYLE_EMB_IS} ${embeddings[key][0]}`) | |
| opt.value = `style_${key}` | |
| seq_edit_view_select.appendChild(opt) | |
| const opt2 = createElem("option", `${window.i18n.STYLE_EMB_IS} ${embeddings[key][0]}`) | |
| opt2.value = `style_${key}` | |
| seq_edit_edit_select.appendChild(opt2) | |
| }) | |
| window.appState.currentModelEmbeddings = embeddings | |
| } | |
| style_emb_select.addEventListener("change", () => window.styleEmbsMenuState.hasChangedEmb) | |
| window.styleEmbsModalOpenCallback = () => { | |
| styleEmbGameIdInput.value = window.currentGame.gameId | |
| if (window.currentModel) { | |
| styleEmbVoiceIdInput.value = window.currentModel.voiceId | |
| } | |
| window.refreshStyleEmbsTable() | |
| } | |
| window.dragDropWavForEmbComputeFilepathInput = (eType, event) => { | |
| if (["dragenter", "dragover"].includes(eType)) { | |
| wavFileDragDropArea.style.background = "#5b5b5b" | |
| wavFileDragDropArea.style.color = "white" | |
| } | |
| if (["dragleave", "drop"].includes(eType)) { | |
| wavFileDragDropArea.style.background = "rgba(0,0,0,0)" | |
| wavFileDragDropArea.style.color = "white" | |
| } | |
| event.preventDefault() | |
| event.stopPropagation() | |
| const dataLines = [] | |
| if (eType=="drop") { | |
| const dataTransfer = event.dataTransfer | |
| const files = Array.from(dataTransfer.files) | |
| if (files[0].path.endsWith(".wav")) { | |
| wavFilepathForEmbComputeInput.value = String(files[0].path).replaceAll(/\\/g, "/") | |
| } else { | |
| window.errorModal(window.i18n.ERROR_FILE_MUST_BE_WAV) | |
| } | |
| } | |
| } | |
| wavFileDragDropArea.addEventListener("dragenter", event => window.dragDropWavForEmbComputeFilepathInput("dragenter", event), false) | |
| wavFileDragDropArea.addEventListener("dragleave", event => window.dragDropWavForEmbComputeFilepathInput("dragleave", event), false) | |
| wavFileDragDropArea.addEventListener("dragover", event => window.dragDropWavForEmbComputeFilepathInput("dragover", event), false) | |
| wavFileDragDropArea.addEventListener("drop", event => window.dragDropWavForEmbComputeFilepathInput("drop", event), false) | |
| getStyleEmbeddingBtn.addEventListener("click", async () => { | |
| if (!wavFilepathForEmbComputeInput.value.trim().length) { | |
| window.errorModal(window.i18n.ERROR_NEED_WAV_FILE) | |
| } else { | |
| const embedding = await window.getSpeakerEmbeddingFromFilePath(wavFilepathForEmbComputeInput.value) | |
| styleEmbValuesInput.value = embedding | |
| } | |
| }) | |