Delete templates/TTS_Input_Proof_of_concept.html
This commit is contained in:
1 parent
7718bfd3ea
commit
2bd7ebc514
1 file changed
-593
@@ -1,593 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>AllTalk TTS Generator</title>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body,
|
|
||||||
textarea,
|
|
||||||
select,
|
|
||||||
input[type="range"],
|
|
||||||
input[type="number"],
|
|
||||||
button {
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 20px;
|
|
||||||
background-color: #f7f7f7;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
color: #333;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-container {
|
|
||||||
max-width: 80%;
|
|
||||||
margin: 50px auto;
|
|
||||||
padding: 20px;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, .2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-section {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: flex-start;
|
|
||||||
/* Align items to the start */
|
|
||||||
align-items: center;
|
|
||||||
/* Align items vertically */
|
|
||||||
gap: 20px;
|
|
||||||
/* This creates a consistent gap between all child elements */
|
|
||||||
}
|
|
||||||
|
|
||||||
.setting {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
/* Space from bottom if wrapped */
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
/* Removed flex property to stop forcing them to grow */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
resize: vertical;
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure select and input elements do not exceed the width of their parent */
|
|
||||||
select,
|
|
||||||
input[type="range"],
|
|
||||||
input[type="number"] {
|
|
||||||
width: 100%;
|
|
||||||
/* They will fill the width of their .setting container */
|
|
||||||
padding: 10px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
|
|
||||||
select,
|
|
||||||
input[type="range"],
|
|
||||||
input[type="number"] {
|
|
||||||
width: auto;
|
|
||||||
/* Only auto width for larger screens */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
button {
|
|
||||||
background-color: #4caf50;
|
|
||||||
color: #fff;
|
|
||||||
padding: 10px 20px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 5px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
background-color: #45a049;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark-mode {
|
|
||||||
background-color: #121212;
|
|
||||||
color: #ffffff;
|
|
||||||
/* Text color for dark mode background */
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark-mode .form-container {
|
|
||||||
background-color: #1e1e1e;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Modify the text color for elements within dark mode */
|
|
||||||
.dark-mode label,
|
|
||||||
.dark-mode textarea,
|
|
||||||
.dark-mode select,
|
|
||||||
.dark-mode input[type="range"],
|
|
||||||
.dark-mode input[type="number"],
|
|
||||||
.dark-mode button,
|
|
||||||
.dark-mode .error {
|
|
||||||
color: #ffffff;
|
|
||||||
/* Text color for dark mode elements */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Modify text color for input elements, textarea, and dropdowns in dark mode */
|
|
||||||
.dark-mode input,
|
|
||||||
.dark-mode textarea,
|
|
||||||
.dark-mode select {
|
|
||||||
color: #000000;
|
|
||||||
/* Text color for input elements, textarea, and dropdowns in dark mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set background color for textarea in dark mode */
|
|
||||||
.dark-mode textarea {
|
|
||||||
background-color: #C0C0C0;
|
|
||||||
/* Light grey background color for textarea in dark mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set background color for option elements within select in dark mode */
|
|
||||||
.dark-mode select {
|
|
||||||
background-color: #C0C0C0;
|
|
||||||
/* Light grey background color for options in dark mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Additional styles if needed for fixed-width dropdowns */
|
|
||||||
.fixed-size-dropdown {
|
|
||||||
width: 130px;
|
|
||||||
/* Adjust the width as needed */
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spinner {
|
|
||||||
border: 5px solid #f3f3f3;
|
|
||||||
border-top: 5px solid #3498db;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
animation: spin 2s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
|
||||||
color: #ff0000;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Add space between sliders */
|
|
||||||
.slider-setting {
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Adjust the thumb appearance for a more standard line slider look */
|
|
||||||
input[type="range"]::-webkit-slider-thumb,
|
|
||||||
input[type="range"]::-moz-range-thumb,
|
|
||||||
input[type="range"]::-ms-thumb {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
width: 16px;
|
|
||||||
/* Smaller width for a more standard thumb size */
|
|
||||||
height: 16px;
|
|
||||||
/* Smaller height for a more standard thumb size */
|
|
||||||
border-radius: 50%;
|
|
||||||
/* Keep it rounded, or set to 0 for square */
|
|
||||||
background: #3071a9;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-top: -7px;
|
|
||||||
/* Adjust if needed to align thumb with the track */
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<h1>AllTalk TTS Generator</h1>
|
|
||||||
|
|
||||||
<div class="form-container">
|
|
||||||
<div class="input-section">
|
|
||||||
<label for="text_input">Text Input:</label>
|
|
||||||
<textarea id="text_input" rows="8"></textarea> <!-- Removed cols attribute -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="settings-section">
|
|
||||||
|
|
||||||
<div class="setting voice-setting">
|
|
||||||
<label for="character_voice_gen">Character Voice:</label>
|
|
||||||
<select id="character_voice_gen"></select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting language-setting">
|
|
||||||
<label for="language">Language:</label>
|
|
||||||
<select id="language" name="language" class="fixed-size-dropdown">
|
|
||||||
<option value="ar">Arabic</option>
|
|
||||||
<option value="zh-cn">Chinese (Simplified)</option>
|
|
||||||
<option value="cs">Czech</option>
|
|
||||||
<option value="nl">Dutch</option>
|
|
||||||
<option value="en" selected>English</option>
|
|
||||||
<option value="fr">French</option>
|
|
||||||
<option value="de">German</option>
|
|
||||||
<option value="hu">Hungarian</option>
|
|
||||||
<option value="it">Italian</option>
|
|
||||||
<option value="ja">Japanese</option>
|
|
||||||
<option value="ko">Korean</option>
|
|
||||||
<option value="pl">Polish</option>
|
|
||||||
<option value="pt">Portuguese</option>
|
|
||||||
<option value="ru">Russian</option>
|
|
||||||
<option value="es">Spanish</option>
|
|
||||||
<option value="tr">Turkish</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="setting play-mode-setting">
|
|
||||||
<label for="playMode">Playback:</label>
|
|
||||||
<select id="playMode" name="playMode" class="fixed-size-dropdown">
|
|
||||||
<option value="local" selected>In Browser</option>
|
|
||||||
<option value="remote">On Server</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting theme-mode-setting">
|
|
||||||
<label for="themeMode">Theme:</label>
|
|
||||||
<select id="themeMode" name="themeMode" class="fixed-size-dropdown">
|
|
||||||
<option value="light" selected>Light</option>
|
|
||||||
<option value="dark">Dark</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting chunk-size-setting">
|
|
||||||
<label for="chunkSize">Sentence Chunk Size:</label>
|
|
||||||
<input type="range" id="chunkSize" name="chunkSize" class="slider-setting" min="1" max="10" value="4"
|
|
||||||
oninput="updateChunkSizeValue(this.value)">
|
|
||||||
<span id="chunkSizeValue">3</span> <!-- Display the value of the slider -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting volume-setting">
|
|
||||||
<label for="volume">Volume:</label>
|
|
||||||
<input type="range" id="volume" name="volume" class="slider-setting" min="0.1" max="1.0" step="0.1"
|
|
||||||
value="0.8" oninput="updateVolumeValue(this.value)">
|
|
||||||
<span id="volumeValue">0.8</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="action-buttons">
|
|
||||||
<button onclick="generateTTS()">Generate TTS</button>
|
|
||||||
<button onclick="togglePausePlayback()">Pause/Resume Playback</button>
|
|
||||||
<button onclick="stopPlayback()">Stop Playback</button>
|
|
||||||
<button onclick="previewVoice()">Preview Voice</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="progressIndicator" class="progress-overlay" style="display: none;">
|
|
||||||
<div class="spinner"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
async function fetchVoices() {
|
|
||||||
try {
|
|
||||||
const response = await fetch("http://127.0.0.1:7851/api/voices");
|
|
||||||
const result = await response.json();
|
|
||||||
const characterVoiceSelect = document.getElementById("character_voice_gen");
|
|
||||||
|
|
||||||
result.voices.forEach(voice => {
|
|
||||||
const option = document.createElement("option");
|
|
||||||
option.value = voice;
|
|
||||||
option.text = voice;
|
|
||||||
characterVoiceSelect.add(option);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateVolumeValue(value) {
|
|
||||||
document.getElementById("volumeValue").innerText = value;
|
|
||||||
|
|
||||||
// Set the volume for browser playback
|
|
||||||
audioElement.volume = parseFloat(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
let stopTTSGeneration = false;
|
|
||||||
let audioQueue = [];
|
|
||||||
let currentlyPlaying = false;
|
|
||||||
const audioElement = new Audio();
|
|
||||||
|
|
||||||
async function generateTTS() {
|
|
||||||
try {
|
|
||||||
// Reset the flag at the start
|
|
||||||
stopTTSGeneration = false;
|
|
||||||
|
|
||||||
const textInput = document.getElementById("text_input").value;
|
|
||||||
const language = document.getElementById("language").value;
|
|
||||||
const characterVoice = document.getElementById("character_voice_gen").value;
|
|
||||||
const volume = parseFloat(document.getElementById("volume").value);
|
|
||||||
const chunkSize = parseInt(document.getElementById("chunkSize").value);
|
|
||||||
// Retrieve the value of the selected option for playMode from the dropdown
|
|
||||||
const playModeValue = document.getElementById("playMode").value;
|
|
||||||
|
|
||||||
// Clean up the textInput
|
|
||||||
let cleanedText = textInput.replace(/ \- | \– /g, ' '); // Replaces " - " and " – " with " "
|
|
||||||
cleanedText = cleanedText.replace(/\.\s'/g, ".'"); // Correctly remove space between a period and a single quote
|
|
||||||
cleanedText = cleanedText.replace(/'/g, ""); // Remove all single quotes
|
|
||||||
|
|
||||||
// Split text into chunks based on the specified number of sentences
|
|
||||||
const sentences = cleanedText.match(/("[^"]+"|[^.!?]+[.!?]+)/g);
|
|
||||||
const chunks = [];
|
|
||||||
for (let i = 0; i < sentences.length; i += chunkSize) {
|
|
||||||
let chunk = sentences.slice(i, i + chunkSize).map(s => s.trim()).join(' ');
|
|
||||||
chunks.push(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use playModeValue for the conditional check
|
|
||||||
if (playModeValue === "remote") {
|
|
||||||
for (const chunk of chunks) {
|
|
||||||
if (stopTTSGeneration) break; // Stop if flag is set
|
|
||||||
await generateAndPlayRemote(chunk, language, characterVoice, volume);
|
|
||||||
}
|
|
||||||
} else if (playModeValue === "local") {
|
|
||||||
generateAndPlayLocal(chunks, 0);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error in generateTTS:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function generateAndPlayLocal(chunks, index) {
|
|
||||||
if (index >= chunks.length || stopTTSGeneration) {
|
|
||||||
return; // Stop if no more chunks or flag is set
|
|
||||||
}
|
|
||||||
if (index >= chunks.length) {
|
|
||||||
// No more chunks to process
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const chunk = chunks[index];
|
|
||||||
const data = new URLSearchParams({
|
|
||||||
text_input: chunk.trim(),
|
|
||||||
text_filtering: "standard",
|
|
||||||
character_voice_gen: document.getElementById("character_voice_gen").value,
|
|
||||||
narrator_enabled: "false",
|
|
||||||
narrator_voice_gen: document.getElementById("character_voice_gen").value,
|
|
||||||
text_not_inside: "character",
|
|
||||||
language: document.getElementById("language").value,
|
|
||||||
output_file_name: "myoutputfile",
|
|
||||||
output_file_timestamp: "true",
|
|
||||||
autoplay: "false",
|
|
||||||
autoplay_volume: document.getElementById("volume").value
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await fetch("http://127.0.0.1:7851/api/tts-generate", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
|
||||||
},
|
|
||||||
body: data,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
if (result.output_file_url) {
|
|
||||||
audioQueue.push(result.output_file_url);
|
|
||||||
if (!currentlyPlaying) {
|
|
||||||
playNextLocalChunk();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively call the function with the next index
|
|
||||||
generateAndPlayLocal(chunks, index + 1);
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error in generateAndPlayLocal with chunk index", index, ":", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function generateAndPlayRemote(chunk, language, characterVoice, volume) {
|
|
||||||
try {
|
|
||||||
if (stopTTSGeneration) {
|
|
||||||
console.log("TTS generation stopped.");
|
|
||||||
return; // Early return if stop flag is set
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = new URLSearchParams({
|
|
||||||
text_input: chunk.trim(),
|
|
||||||
text_filtering: "standard",
|
|
||||||
character_voice_gen: characterVoice,
|
|
||||||
narrator_enabled: "false",
|
|
||||||
narrator_voice_gen: characterVoice,
|
|
||||||
text_not_inside: "character",
|
|
||||||
language: language,
|
|
||||||
output_file_name: "myoutputfile",
|
|
||||||
output_file_timestamp: "true",
|
|
||||||
autoplay: "true",
|
|
||||||
autoplay_volume: volume.toString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await fetch("http://127.0.0.1:7851/api/tts-generate", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
|
||||||
},
|
|
||||||
body: data,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`API error: ${result.detail || 'Unknown error'}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("TTS generation complete for chunk:", chunk);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error in generateAndPlayRemote:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function previewVoice() {
|
|
||||||
const characterVoice = document.getElementById("character_voice_gen").value;
|
|
||||||
try {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("voice", characterVoice);
|
|
||||||
|
|
||||||
const response = await fetch("http://127.0.0.1:7851/api/previewvoice/", {
|
|
||||||
method: "POST",
|
|
||||||
body: formData,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
if (result.status === "generate-success") {
|
|
||||||
// Play the preview audio
|
|
||||||
const audioPreview = new Audio(result.output_file_url);
|
|
||||||
audioPreview.play();
|
|
||||||
} else {
|
|
||||||
throw new Error('Preview generation failed');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error in previewVoice:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function playNextLocalChunk() {
|
|
||||||
if (audioQueue.length > 0) {
|
|
||||||
currentlyPlaying = true;
|
|
||||||
const audioUrl = audioQueue.shift();
|
|
||||||
audioElement.src = audioUrl;
|
|
||||||
audioElement.play();
|
|
||||||
|
|
||||||
audioElement.onended = () => {
|
|
||||||
currentlyPlaying = false;
|
|
||||||
playNextLocalChunk();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function togglePausePlayback() {
|
|
||||||
if (audioElement.paused) {
|
|
||||||
audioElement.play();
|
|
||||||
} else {
|
|
||||||
audioElement.pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleThemeMode() {
|
|
||||||
// Retrieve the value of the selected option for themeMode from the dropdown
|
|
||||||
const themeModeValue = document.getElementById('themeMode').value;
|
|
||||||
|
|
||||||
if (themeModeValue === "dark") {
|
|
||||||
document.body.classList.add('dark-mode');
|
|
||||||
localStorage.setItem('darkMode', 'enabled'); // Assuming saveDarkModePreference sets this
|
|
||||||
} else {
|
|
||||||
document.body.classList.remove('dark-mode');
|
|
||||||
localStorage.setItem('darkMode', 'disabled'); // Assuming saveDarkModePreference sets this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateChunkSizeValue(value) {
|
|
||||||
document.getElementById("chunkSizeValue").innerText = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optionally, save the dark mode preference in localStorage
|
|
||||||
function saveDarkModePreference(isDarkMode) {
|
|
||||||
localStorage.setItem('darkMode', isDarkMode ? 'enabled' : 'disabled');
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopPlayback() {
|
|
||||||
// Stop current audio playback
|
|
||||||
audioElement.pause();
|
|
||||||
audioElement.currentTime = 0;
|
|
||||||
|
|
||||||
// Clear the audio queue, reset playback flag, and stop further TTS generation
|
|
||||||
audioQueue = [];
|
|
||||||
currentlyPlaying = false;
|
|
||||||
stopTTSGeneration = true; // Set flag to stop TTS generation
|
|
||||||
}
|
|
||||||
|
|
||||||
function showProgress() {
|
|
||||||
document.getElementById('progressIndicator').style.display = 'flex';
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideProgress() {
|
|
||||||
document.getElementById('progressIndicator').style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
function displayOutput(result) {
|
|
||||||
const outputContainer = document.getElementById("output");
|
|
||||||
outputContainer.innerHTML = `<p>Status: ${result.status}</p>`;
|
|
||||||
if (result.output_file_path) {
|
|
||||||
outputContainer.innerHTML += `<p>File Path: ${result.output_file_path}</p>`;
|
|
||||||
}
|
|
||||||
if (result.output_file_url) {
|
|
||||||
outputContainer.innerHTML += `<p>File URL: ${result.output_file_url}</p>`;
|
|
||||||
}
|
|
||||||
if (result.error) {
|
|
||||||
outputContainer.innerHTML += `<p class="error">Error: ${result.error}</p>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onload = function() {
|
|
||||||
fetchVoices();
|
|
||||||
|
|
||||||
const isDarkModeEnabled = localStorage.getItem('darkMode') === 'enabled';
|
|
||||||
const themeModeSelect = document.getElementById('themeMode');
|
|
||||||
if (isDarkModeEnabled) {
|
|
||||||
document.body.classList.add('dark-mode');
|
|
||||||
themeModeSelect.value = 'dark';
|
|
||||||
} else {
|
|
||||||
themeModeSelect.value = 'light';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add change event listener to the themeMode dropdown
|
|
||||||
themeModeSelect.addEventListener('change', toggleThemeMode);
|
|
||||||
|
|
||||||
// Initialize other elements if necessary
|
|
||||||
};
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
Reference in new issue
Block a user