Added settings to allow control of exaggeration, cfg_weight, and temperature on each line.
This commit is contained in:
parent
26f1d98b46
commit
f9e952286d
|
@ -147,7 +147,7 @@ main {
|
||||||
width: 110px;
|
width: 110px;
|
||||||
min-width: 90px;
|
min-width: 90px;
|
||||||
max-width: 130px;
|
max-width: 130px;
|
||||||
text-align: center;
|
text-align: left;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ main {
|
||||||
}
|
}
|
||||||
|
|
||||||
#dialog-items-table td.actions {
|
#dialog-items-table td.actions {
|
||||||
text-align: center;
|
text-align: left;
|
||||||
min-width: 110px;
|
min-width: 110px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
@ -514,3 +514,159 @@ footer {
|
||||||
outline: 2px solid var(--primary-blue);
|
outline: 2px solid var(--primary-blue);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TTS Settings Modal */
|
||||||
|
.modal {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 1000;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
background: var(--bg-white);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: var(--shadow-strong);
|
||||||
|
max-width: 500px;
|
||||||
|
width: 90%;
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px 24px 16px;
|
||||||
|
border-bottom: 1px solid var(--border-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-close {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
font-size: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-close:hover {
|
||||||
|
background-color: var(--bg-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding: 20px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-group input[type="range"] {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-group span {
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 40px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--primary-blue);
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-group small {
|
||||||
|
display: block;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
margin-top: 4px;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 16px 24px 20px;
|
||||||
|
border-top: 1px solid var(--border-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary, .btn-secondary {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: var(--primary-blue);
|
||||||
|
color: var(--text-white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: var(--primary-blue-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background-color: var(--bg-light);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border: 1px solid var(--border-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary:hover {
|
||||||
|
background-color: var(--border-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Settings button styling */
|
||||||
|
.settings-line-btn {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: none;
|
||||||
|
background-color: var(--bg-light);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 0 2px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-line-btn:hover {
|
||||||
|
background-color: var(--primary-blue);
|
||||||
|
color: var(--text-white);
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-line-btn:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
|
@ -101,6 +101,40 @@
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- TTS Settings Modal -->
|
||||||
|
<div id="tts-settings-modal" class="modal" style="display: none;">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3>TTS Settings</h3>
|
||||||
|
<button class="modal-close" id="tts-modal-close">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="settings-group">
|
||||||
|
<label for="tts-exaggeration">Exaggeration:</label>
|
||||||
|
<input type="range" id="tts-exaggeration" min="0" max="2" step="0.1" value="0.5">
|
||||||
|
<span id="tts-exaggeration-value">0.5</span>
|
||||||
|
<small>Controls expressiveness. Higher values = more exaggerated speech.</small>
|
||||||
|
</div>
|
||||||
|
<div class="settings-group">
|
||||||
|
<label for="tts-cfg-weight">CFG Weight:</label>
|
||||||
|
<input type="range" id="tts-cfg-weight" min="0" max="2" step="0.1" value="0.5">
|
||||||
|
<span id="tts-cfg-weight-value">0.5</span>
|
||||||
|
<small>Alignment with prompt. Higher values = more aligned with speaker characteristics.</small>
|
||||||
|
</div>
|
||||||
|
<div class="settings-group">
|
||||||
|
<label for="tts-temperature">Temperature:</label>
|
||||||
|
<input type="range" id="tts-temperature" min="0" max="2" step="0.1" value="0.8">
|
||||||
|
<span id="tts-temperature-value">0.8</span>
|
||||||
|
<small>Randomness. Lower values = more deterministic, higher = more varied.</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button id="tts-settings-save" class="btn-primary">Save Settings</button>
|
||||||
|
<button id="tts-settings-cancel" class="btn-secondary">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="js/api.js" type="module"></script>
|
<script src="js/api.js" type="module"></script>
|
||||||
<script src="js/app.js" type="module" defer></script>
|
<script src="js/app.js" type="module" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -111,12 +111,21 @@ let availableSpeakersCache = []; // To populate speaker dropdown
|
||||||
|
|
||||||
// Utility: ensure each dialog item has audioUrl, isGenerating, error
|
// Utility: ensure each dialog item has audioUrl, isGenerating, error
|
||||||
function normalizeDialogItem(item) {
|
function normalizeDialogItem(item) {
|
||||||
return {
|
const normalized = {
|
||||||
...item,
|
...item,
|
||||||
audioUrl: item.audioUrl || null,
|
audioUrl: item.audioUrl || null,
|
||||||
isGenerating: item.isGenerating || false,
|
isGenerating: item.isGenerating || false,
|
||||||
error: item.error || null
|
error: item.error || null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add TTS settings for speech items with defaults
|
||||||
|
if (item.type === 'speech') {
|
||||||
|
normalized.exaggeration = item.exaggeration ?? 0.5;
|
||||||
|
normalized.cfg_weight = item.cfg_weight ?? 0.5;
|
||||||
|
normalized.temperature = item.temperature ?? 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function initializeDialogEditor() {
|
async function initializeDialogEditor() {
|
||||||
|
@ -332,6 +341,18 @@ async function initializeDialogEditor() {
|
||||||
};
|
};
|
||||||
actionsTd.appendChild(playBtn);
|
actionsTd.appendChild(playBtn);
|
||||||
|
|
||||||
|
// --- NEW: Settings button for speech items ---
|
||||||
|
if (item.type === 'speech') {
|
||||||
|
const settingsBtn = document.createElement('button');
|
||||||
|
settingsBtn.innerHTML = '⚙️';
|
||||||
|
settingsBtn.title = 'TTS Settings';
|
||||||
|
settingsBtn.className = 'settings-line-btn';
|
||||||
|
settingsBtn.onclick = () => {
|
||||||
|
showTTSSettingsModal(item, index);
|
||||||
|
};
|
||||||
|
actionsTd.appendChild(settingsBtn);
|
||||||
|
}
|
||||||
|
|
||||||
// Show error if present
|
// Show error if present
|
||||||
if (item.error) {
|
if (item.error) {
|
||||||
const errorSpan = document.createElement('span');
|
const errorSpan = document.createElement('span');
|
||||||
|
@ -709,6 +730,88 @@ async function initializeDialogEditor() {
|
||||||
|
|
||||||
console.log('Dialog Editor Initialized');
|
console.log('Dialog Editor Initialized');
|
||||||
renderDialogItems(); // Initial render (empty)
|
renderDialogItems(); // Initial render (empty)
|
||||||
|
|
||||||
|
// Add a function to show TTS settings modal
|
||||||
|
function showTTSSettingsModal(item, index) {
|
||||||
|
const modal = document.getElementById('tts-settings-modal');
|
||||||
|
const exaggerationSlider = document.getElementById('tts-exaggeration');
|
||||||
|
const exaggerationValue = document.getElementById('tts-exaggeration-value');
|
||||||
|
const cfgWeightSlider = document.getElementById('tts-cfg-weight');
|
||||||
|
const cfgWeightValue = document.getElementById('tts-cfg-weight-value');
|
||||||
|
const temperatureSlider = document.getElementById('tts-temperature');
|
||||||
|
const temperatureValue = document.getElementById('tts-temperature-value');
|
||||||
|
const saveBtn = document.getElementById('tts-settings-save');
|
||||||
|
const cancelBtn = document.getElementById('tts-settings-cancel');
|
||||||
|
const closeBtn = document.getElementById('tts-modal-close');
|
||||||
|
|
||||||
|
// Set current values
|
||||||
|
exaggerationSlider.value = item.exaggeration || 0.5;
|
||||||
|
exaggerationValue.textContent = exaggerationSlider.value;
|
||||||
|
cfgWeightSlider.value = item.cfg_weight || 0.5;
|
||||||
|
cfgWeightValue.textContent = cfgWeightSlider.value;
|
||||||
|
temperatureSlider.value = item.temperature || 0.8;
|
||||||
|
temperatureValue.textContent = temperatureSlider.value;
|
||||||
|
|
||||||
|
// Update value displays when sliders change
|
||||||
|
const updateValueDisplay = (slider, display) => {
|
||||||
|
display.textContent = slider.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
exaggerationSlider.oninput = () => updateValueDisplay(exaggerationSlider, exaggerationValue);
|
||||||
|
cfgWeightSlider.oninput = () => updateValueDisplay(cfgWeightSlider, cfgWeightValue);
|
||||||
|
temperatureSlider.oninput = () => updateValueDisplay(temperatureSlider, temperatureValue);
|
||||||
|
|
||||||
|
// Show modal
|
||||||
|
modal.style.display = 'flex';
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
const saveSettings = () => {
|
||||||
|
dialogItems[index].exaggeration = parseFloat(exaggerationSlider.value);
|
||||||
|
dialogItems[index].cfg_weight = parseFloat(cfgWeightSlider.value);
|
||||||
|
dialogItems[index].temperature = parseFloat(temperatureSlider.value);
|
||||||
|
|
||||||
|
// Clear any existing audio since settings changed
|
||||||
|
dialogItems[index].audioUrl = null;
|
||||||
|
|
||||||
|
closeModal();
|
||||||
|
renderDialogItems(); // Re-render to reflect changes
|
||||||
|
console.log('TTS settings updated for item:', dialogItems[index]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close modal
|
||||||
|
const closeModal = () => {
|
||||||
|
modal.style.display = 'none';
|
||||||
|
// Clean up event listeners
|
||||||
|
exaggerationSlider.oninput = null;
|
||||||
|
cfgWeightSlider.oninput = null;
|
||||||
|
temperatureSlider.oninput = null;
|
||||||
|
saveBtn.onclick = null;
|
||||||
|
cancelBtn.onclick = null;
|
||||||
|
closeBtn.onclick = null;
|
||||||
|
modal.onclick = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Event listeners
|
||||||
|
saveBtn.onclick = saveSettings;
|
||||||
|
cancelBtn.onclick = closeModal;
|
||||||
|
closeBtn.onclick = closeModal;
|
||||||
|
|
||||||
|
// Close modal when clicking outside
|
||||||
|
modal.onclick = (e) => {
|
||||||
|
if (e.target === modal) {
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close modal on Escape key
|
||||||
|
const handleEscape = (e) => {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
closeModal();
|
||||||
|
document.removeEventListener('keydown', handleEscape);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener('keydown', handleEscape);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Results Display --- //
|
// --- Results Display --- //
|
||||||
|
|
Loading…
Reference in New Issue