feat: Enhance normalization settings with additional options and UI elements

This commit is contained in:
JB
2025-11-27 10:49:29 -08:00
parent d0532347be
commit 550fdbf537
3 changed files with 97 additions and 8 deletions
+23 -5
View File
@@ -1778,10 +1778,17 @@ def _apply_book_step_form(
return default return default
overrides_existing = getattr(pending, "normalization_overrides", None) overrides_existing = getattr(pending, "normalization_overrides", None)
overrides: Dict[str, bool] = dict(overrides_existing or {}) overrides: Dict[str, Any] = dict(overrides_existing or {})
for key in _APOSTROPHE_OVERRIDE_KEYS: for key in _NORMALIZATION_BOOLEAN_KEYS:
default_toggle = overrides.get(key, bool(settings.get(key, True))) default_toggle = overrides.get(key, bool(settings.get(key, True)))
overrides[key] = _extract_checkbox(key, default_toggle) overrides[key] = _extract_checkbox(key, default_toggle)
for key in _NORMALIZATION_STRING_KEYS:
default_val = overrides.get(key, str(settings.get(key, "")))
val = form.get(key)
if val is not None:
overrides[key] = str(val)
else:
overrides[key] = default_val
pending.normalization_overrides = overrides pending.normalization_overrides = overrides
speed_value = form.get("speed") speed_value = form.get("speed")
@@ -2014,6 +2021,7 @@ def _template_options() -> Dict[str, Any]:
"speaker_pronunciation_sentence": current_settings.get( "speaker_pronunciation_sentence": current_settings.get(
"speaker_pronunciation_sentence", _settings_defaults()["speaker_pronunciation_sentence"] "speaker_pronunciation_sentence", _settings_defaults()["speaker_pronunciation_sentence"]
), ),
"apostrophe_modes": _APOSTROPHE_MODE_OPTIONS,
} }
@@ -2112,7 +2120,12 @@ BOOLEAN_SETTINGS = {
FLOAT_SETTINGS = {"silence_between_chapters", "chapter_intro_delay", "llm_timeout"} FLOAT_SETTINGS = {"silence_between_chapters", "chapter_intro_delay", "llm_timeout"}
INT_SETTINGS = {"max_subtitle_words", "speaker_analysis_threshold"} INT_SETTINGS = {"max_subtitle_words", "speaker_analysis_threshold"}
_APOSTROPHE_OVERRIDE_KEYS = ( _NORMALIZATION_BOOLEAN_KEYS = (
"normalization_numbers",
"normalization_titles",
"normalization_terminal",
"normalization_phoneme_hints",
"normalization_caps_quotes",
"normalization_apostrophes_contractions", "normalization_apostrophes_contractions",
"normalization_apostrophes_plural_possessives", "normalization_apostrophes_plural_possessives",
"normalization_apostrophes_sibilant_possessives", "normalization_apostrophes_sibilant_possessives",
@@ -2124,7 +2137,11 @@ _APOSTROPHE_OVERRIDE_KEYS = (
"normalization_contraction_modal_would", "normalization_contraction_modal_would",
"normalization_contraction_negation_not", "normalization_contraction_negation_not",
"normalization_contraction_let_us", "normalization_contraction_let_us",
"normalization_caps_quotes", )
_NORMALIZATION_STRING_KEYS = (
"normalization_numbers_year_style",
"normalization_apostrophe_mode",
) )
@@ -4431,7 +4448,8 @@ def _build_pending_job_from_extraction(
metadata_tags=metadata_tags, metadata_tags=metadata_tags,
chapters=chapters_payload, chapters=chapters_payload,
normalization_overrides={ normalization_overrides={
key: bool(settings.get(key, True)) for key in _APOSTROPHE_OVERRIDE_KEYS **{key: bool(settings.get(key, True)) for key in _NORMALIZATION_BOOLEAN_KEYS},
**{key: str(settings.get(key, "")) for key in _NORMALIZATION_STRING_KEYS},
}, },
created_at=time.time(), created_at=time.time(),
cover_image_path=cover_path, cover_image_path=cover_path,
+6 -3
View File
@@ -1095,10 +1095,13 @@ class ConversionService:
if existing_items: if existing_items:
job.add_log( job.add_log(
f"Audiobookshelf upload skipped: '{display_title}' already exists in the configured folder.", f"Removing existing Audiobookshelf item(s) for '{display_title}' before upload.",
level="warning", level="info",
) )
return try:
client.delete_items(existing_items)
except Exception as exc:
job.add_log(f"Failed to remove existing item(s): {exc}", level="warning")
client.upload_audiobook( client.upload_audiobook(
audio_path, audio_path,
@@ -128,6 +128,26 @@
{% endif %} {% endif %}
{% set normalization_overrides = pending.normalization_overrides if pending and pending.normalization_overrides else {} %} {% set normalization_overrides = pending.normalization_overrides if pending and pending.normalization_overrides else {} %}
{% set normalization_toggles = [ {% set normalization_toggles = [
{
'name': 'normalization_numbers',
'label': "Convert grouped numbers to words",
'value': normalization_overrides.get('normalization_numbers', settings_dict.get('normalization_numbers', True)),
},
{
'name': 'normalization_titles',
'label': "Expand titles and suffixes (Dr., St., Jr., …)",
'value': normalization_overrides.get('normalization_titles', settings_dict.get('normalization_titles', True)),
},
{
'name': 'normalization_terminal',
'label': "Ensure sentences end with terminal punctuation",
'value': normalization_overrides.get('normalization_terminal', settings_dict.get('normalization_terminal', True)),
},
{
'name': 'normalization_phoneme_hints',
'label': "Apply phoneme hints for common abbreviations",
'value': normalization_overrides.get('normalization_phoneme_hints', settings_dict.get('normalization_phoneme_hints', True)),
},
{ {
'name': 'normalization_caps_quotes', 'name': 'normalization_caps_quotes',
'label': "Convert ALL CAPS dialogue inside quotes", 'label': "Convert ALL CAPS dialogue inside quotes",
@@ -158,6 +178,36 @@
'label': "Expand leading elisions ('tis -> it is)", 'label': "Expand leading elisions ('tis -> it is)",
'value': normalization_overrides.get('normalization_apostrophes_leading_elisions', settings_dict.get('normalization_apostrophes_leading_elisions', True)), 'value': normalization_overrides.get('normalization_apostrophes_leading_elisions', settings_dict.get('normalization_apostrophes_leading_elisions', True)),
}, },
{
'name': 'normalization_contraction_aux_be',
'label': "Expand auxiliary 'be' (I'm -> I am)",
'value': normalization_overrides.get('normalization_contraction_aux_be', settings_dict.get('normalization_contraction_aux_be', True)),
},
{
'name': 'normalization_contraction_aux_have',
'label': "Expand auxiliary 'have' (I've -> I have)",
'value': normalization_overrides.get('normalization_contraction_aux_have', settings_dict.get('normalization_contraction_aux_have', True)),
},
{
'name': 'normalization_contraction_modal_will',
'label': "Expand modal 'will' (I'll -> I will)",
'value': normalization_overrides.get('normalization_contraction_modal_will', settings_dict.get('normalization_contraction_modal_will', True)),
},
{
'name': 'normalization_contraction_modal_would',
'label': "Expand modal 'would' (I'd -> I would)",
'value': normalization_overrides.get('normalization_contraction_modal_would', settings_dict.get('normalization_contraction_modal_would', True)),
},
{
'name': 'normalization_contraction_negation_not',
'label': "Expand negation 'not' (don't -> do not)",
'value': normalization_overrides.get('normalization_contraction_negation_not', settings_dict.get('normalization_contraction_negation_not', True)),
},
{
'name': 'normalization_contraction_let_us',
'label': "Expand 'let's' -> let us",
'value': normalization_overrides.get('normalization_contraction_let_us', settings_dict.get('normalization_contraction_let_us', True)),
},
] %} ] %}
{% set voice_formula_value = '' %} {% set voice_formula_value = '' %}
{% set profile_value = narrator_profile if narrator_profile else '__standard' %} {% set profile_value = narrator_profile if narrator_profile else '__standard' %}
@@ -303,6 +353,24 @@
<section class="form-section"> <section class="form-section">
<h3 class="form-section__title">Text normalization</h3> <h3 class="form-section__title">Text normalization</h3>
<div class="field-grid field-grid--compact"> <div class="field-grid field-grid--compact">
<div class="field field--stack field--span-2">
<span class="field__label">Apostrophe strategy</span>
<div class="choices choices--inline">
{% for option in options.apostrophe_modes %}
<label class="radio-pill">
<input type="radio" name="normalization_apostrophe_mode" value="{{ option.value }}" {% if normalization_overrides.get('normalization_apostrophe_mode', settings_dict.get('normalization_apostrophe_mode', 'spacy')) == option.value %}checked{% endif %} {{ 'disabled' if readonly else '' }}>
<span>{{ option.label }}</span>
</label>
{% endfor %}
</div>
</div>
<div class="field field--stack field--span-2">
<label for="normalization_numbers_year_style">Year pronunciation style</label>
<select id="normalization_numbers_year_style" name="normalization_numbers_year_style" {{ 'disabled' if readonly else '' }}>
<option value="american" {% if normalization_overrides.get('normalization_numbers_year_style', settings_dict.get('normalization_numbers_year_style', 'american')) == 'american' %}selected{% endif %}>American (1990 -> nineteen ninety)</option>
<option value="off" {% if normalization_overrides.get('normalization_numbers_year_style', settings_dict.get('normalization_numbers_year_style', 'american')) == 'off' %}selected{% endif %}>Off (read as number)</option>
</select>
</div>
{% for toggle in normalization_toggles %} {% for toggle in normalization_toggles %}
<div class="field field--stack"> <div class="field field--stack">
<label class="toggle-pill"> <label class="toggle-pill">