mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 21:50:28 +02:00
feat: Add contraction handling options and UI for normalization settings
This commit is contained in:
@@ -2100,6 +2100,12 @@ BOOLEAN_SETTINGS = {
|
||||
"normalization_apostrophes_sibilant_possessives",
|
||||
"normalization_apostrophes_decades",
|
||||
"normalization_apostrophes_leading_elisions",
|
||||
"normalization_contraction_aux_be",
|
||||
"normalization_contraction_aux_have",
|
||||
"normalization_contraction_modal_will",
|
||||
"normalization_contraction_modal_would",
|
||||
"normalization_contraction_negation_not",
|
||||
"normalization_contraction_let_us",
|
||||
}
|
||||
|
||||
FLOAT_SETTINGS = {"silence_between_chapters", "chapter_intro_delay", "llm_timeout"}
|
||||
@@ -2111,6 +2117,12 @@ _APOSTROPHE_OVERRIDE_KEYS = (
|
||||
"normalization_apostrophes_sibilant_possessives",
|
||||
"normalization_apostrophes_decades",
|
||||
"normalization_apostrophes_leading_elisions",
|
||||
"normalization_contraction_aux_be",
|
||||
"normalization_contraction_aux_have",
|
||||
"normalization_contraction_modal_will",
|
||||
"normalization_contraction_modal_would",
|
||||
"normalization_contraction_negation_not",
|
||||
"normalization_contraction_let_us",
|
||||
)
|
||||
|
||||
|
||||
@@ -3376,6 +3388,12 @@ def api_normalization_preview() -> ResponseReturnValue:
|
||||
"normalization_apostrophes_sibilant_possessives",
|
||||
"normalization_apostrophes_decades",
|
||||
"normalization_apostrophes_leading_elisions",
|
||||
"normalization_contraction_aux_be",
|
||||
"normalization_contraction_aux_have",
|
||||
"normalization_contraction_modal_will",
|
||||
"normalization_contraction_modal_would",
|
||||
"normalization_contraction_negation_not",
|
||||
"normalization_contraction_let_us",
|
||||
)
|
||||
for key in boolean_keys:
|
||||
if key in normalization_payload:
|
||||
|
||||
@@ -28,6 +28,11 @@ let folderModalOpener = null;
|
||||
let folderModalPreviousFocus = null;
|
||||
let audiobookshelfFolderSource = [];
|
||||
|
||||
const contractionModal = document.querySelector('[data-role="contraction-modal"]');
|
||||
const contractionModalOverlay = contractionModal ? contractionModal.querySelector('[data-role="contraction-modal-overlay"]') : null;
|
||||
let contractionModalOpener = null;
|
||||
let contractionModalPreviousFocus = null;
|
||||
|
||||
function setStatus(target, message, state) {
|
||||
if (!target) {
|
||||
return;
|
||||
@@ -177,6 +182,66 @@ function closeFolderModal(event) {
|
||||
folderModalOpener = null;
|
||||
}
|
||||
|
||||
function openContractionModal(opener) {
|
||||
if (!contractionModal) {
|
||||
return;
|
||||
}
|
||||
contractionModalOpener = opener || null;
|
||||
contractionModalPreviousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
||||
contractionModal.hidden = false;
|
||||
contractionModal.dataset.open = 'true';
|
||||
document.body.classList.add('modal-open');
|
||||
const focusTarget = contractionModal.querySelector('input, button, select, textarea');
|
||||
if (focusTarget instanceof HTMLElement) {
|
||||
focusTarget.focus({ preventScroll: true });
|
||||
}
|
||||
}
|
||||
|
||||
function closeContractionModal(event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
if (!contractionModal || contractionModal.hidden) {
|
||||
return;
|
||||
}
|
||||
contractionModal.dataset.open = 'false';
|
||||
contractionModal.hidden = true;
|
||||
document.body.classList.remove('modal-open');
|
||||
const focusTarget =
|
||||
(contractionModalPreviousFocus && typeof contractionModalPreviousFocus.focus === 'function'
|
||||
? contractionModalPreviousFocus
|
||||
: contractionModalOpener) || null;
|
||||
if (focusTarget && typeof focusTarget.focus === 'function') {
|
||||
focusTarget.focus({ preventScroll: true });
|
||||
}
|
||||
contractionModalPreviousFocus = null;
|
||||
contractionModalOpener = null;
|
||||
}
|
||||
|
||||
function initContractionModal() {
|
||||
if (!contractionModal) {
|
||||
return;
|
||||
}
|
||||
const openButton = document.querySelector('[data-action="contraction-modal-open"]');
|
||||
if (openButton) {
|
||||
openButton.addEventListener('click', () => openContractionModal(openButton));
|
||||
}
|
||||
const closeButtons = contractionModal.querySelectorAll('[data-action="contraction-modal-close"]');
|
||||
closeButtons.forEach((button) => {
|
||||
button.addEventListener('click', closeContractionModal);
|
||||
});
|
||||
if (contractionModalOverlay) {
|
||||
contractionModalOverlay.addEventListener('click', closeContractionModal);
|
||||
}
|
||||
contractionModal.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
closeContractionModal(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderFolderList(query) {
|
||||
if (!folderList) {
|
||||
return;
|
||||
@@ -461,6 +526,9 @@ async function previewLLM(button) {
|
||||
}
|
||||
|
||||
function collectNormalizationSettings() {
|
||||
if (!form) {
|
||||
return null;
|
||||
}
|
||||
const normalization = {
|
||||
normalization_numbers: Boolean(form.querySelector('input[name="normalization_numbers"]')?.checked),
|
||||
normalization_titles: Boolean(form.querySelector('input[name="normalization_titles"]')?.checked),
|
||||
@@ -471,6 +539,12 @@ function collectNormalizationSettings() {
|
||||
normalization_apostrophes_sibilant_possessives: Boolean(form.querySelector('input[name="normalization_apostrophes_sibilant_possessives"]')?.checked),
|
||||
normalization_apostrophes_decades: Boolean(form.querySelector('input[name="normalization_apostrophes_decades"]')?.checked),
|
||||
normalization_apostrophes_leading_elisions: Boolean(form.querySelector('input[name="normalization_apostrophes_leading_elisions"]')?.checked),
|
||||
normalization_contraction_aux_be: Boolean(form.querySelector('input[name="normalization_contraction_aux_be"]')?.checked),
|
||||
normalization_contraction_aux_have: Boolean(form.querySelector('input[name="normalization_contraction_aux_have"]')?.checked),
|
||||
normalization_contraction_modal_will: Boolean(form.querySelector('input[name="normalization_contraction_modal_will"]')?.checked),
|
||||
normalization_contraction_modal_would: Boolean(form.querySelector('input[name="normalization_contraction_modal_would"]')?.checked),
|
||||
normalization_contraction_negation_not: Boolean(form.querySelector('input[name="normalization_contraction_negation_not"]')?.checked),
|
||||
normalization_contraction_let_us: Boolean(form.querySelector('input[name="normalization_contraction_let_us"]')?.checked),
|
||||
normalization_apostrophe_mode: form.querySelector('input[name="normalization_apostrophe_mode"]:checked')?.value || 'spacy',
|
||||
};
|
||||
return normalization;
|
||||
@@ -687,10 +761,13 @@ async function previewNormalization(button) {
|
||||
normalizationAudio.removeAttribute('src');
|
||||
}
|
||||
setStatus(status, 'Building preview…');
|
||||
button.disabled = true;
|
||||
const normalization = collectNormalizationSettings();
|
||||
if (!normalization) {
|
||||
setStatus(status, 'Unable to gather normalization settings.', 'error');
|
||||
return;
|
||||
}
|
||||
const llmFields = collectLLMFields();
|
||||
try {
|
||||
const normalization = collectNormalizationSettings();
|
||||
const llmFields = collectLLMFields();
|
||||
const response = await fetch('/api/normalization/preview', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -797,5 +874,6 @@ if (form) {
|
||||
initSampleSelector();
|
||||
initActions();
|
||||
initFolderPicker();
|
||||
initContractionModal();
|
||||
initLLMStateWatchers();
|
||||
}
|
||||
|
||||
@@ -324,6 +324,10 @@
|
||||
<span>Expand leading elisions ('tis -> it is)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="field field--inline field--actions">
|
||||
<button type="button" class="button button--ghost button--small" data-action="contraction-modal-open">Advanced…</button>
|
||||
<p class="hint">Choose which contraction families are expanded.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<span class="field__label">Apostrophe strategy</span>
|
||||
<div class="choices choices--inline">
|
||||
@@ -494,6 +498,49 @@
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="modal" data-role="contraction-modal" hidden>
|
||||
<div class="modal__overlay" data-role="contraction-modal-overlay" tabindex="-1"></div>
|
||||
<div class="modal__content card card--modal" role="dialog" aria-modal="true" aria-labelledby="contraction-modal-title">
|
||||
<header class="modal__header">
|
||||
<p class="modal__eyebrow">Normalization</p>
|
||||
<h2 class="modal__title" id="contraction-modal-title">Contraction Options</h2>
|
||||
<button type="button" class="button button--ghost button--small" data-action="contraction-modal-close" aria-label="Close contraction options">Close</button>
|
||||
</header>
|
||||
<div class="modal__body">
|
||||
<p class="hint">Enable or disable specific contraction families. These controls apply when contraction expansion is enabled.</p>
|
||||
<div class="field field--choices">
|
||||
<label class="toggle-pill">
|
||||
<input type="checkbox" name="normalization_contraction_aux_be" value="true" {% if settings.normalization_contraction_aux_be %}checked{% endif %}>
|
||||
<span>Be verbs ('m, 're, 's -> am/is/are)</span>
|
||||
</label>
|
||||
<label class="toggle-pill">
|
||||
<input type="checkbox" name="normalization_contraction_aux_have" value="true" {% if settings.normalization_contraction_aux_have %}checked{% endif %}>
|
||||
<span>Have auxiliaries ('ve, 'd -> have/had)</span>
|
||||
</label>
|
||||
<label class="toggle-pill">
|
||||
<input type="checkbox" name="normalization_contraction_modal_will" value="true" {% if settings.normalization_contraction_modal_will %}checked{% endif %}>
|
||||
<span>Will modals ('ll -> will)</span>
|
||||
</label>
|
||||
<label class="toggle-pill">
|
||||
<input type="checkbox" name="normalization_contraction_modal_would" value="true" {% if settings.normalization_contraction_modal_would %}checked{% endif %}>
|
||||
<span>Would conditionals ('d -> would)</span>
|
||||
</label>
|
||||
<label class="toggle-pill">
|
||||
<input type="checkbox" name="normalization_contraction_negation_not" value="true" {% if settings.normalization_contraction_negation_not %}checked{% endif %}>
|
||||
<span>Negative forms (can't -> can not)</span>
|
||||
</label>
|
||||
<label class="toggle-pill">
|
||||
<input type="checkbox" name="normalization_contraction_let_us" value="true" {% if settings.normalization_contraction_let_us %}checked{% endif %}>
|
||||
<span>Let us (let's -> let us)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="modal__footer">
|
||||
<button type="button" class="button button--ghost" data-action="contraction-modal-close">Done</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal" data-role="audiobookshelf-folder-modal" hidden>
|
||||
<div class="modal__overlay" data-role="audiobookshelf-folder-overlay" tabindex="-1"></div>
|
||||
<div class="modal__content card card--modal folder-picker-modal" role="dialog" aria-modal="true" aria-labelledby="audiobookshelf-folder-picker-title">
|
||||
|
||||
Reference in New Issue
Block a user