From 7d11ebc338c2a14c948d057ad0907156fa85e223 Mon Sep 17 00:00:00 2001 From: JB Date: Sun, 12 Oct 2025 06:59:39 -0700 Subject: [PATCH] refactor: Remove speaker mode handling from various components --- abogen/web/routes.py | 62 +++---------------- abogen/web/static/prepare.js | 32 ---------- abogen/web/static/wizard.js | 11 ++++ abogen/web/templates/job_detail.html | 1 - .../templates/partials/new_job_step_book.html | 36 +++-------- .../partials/new_job_step_chapters.html | 3 - .../partials/new_job_step_entities.html | 2 - abogen/web/templates/settings.html | 8 --- 8 files changed, 28 insertions(+), 127 deletions(-) diff --git a/abogen/web/routes.py b/abogen/web/routes.py index e1b95a3..4668642 100644 --- a/abogen/web/routes.py +++ b/abogen/web/routes.py @@ -106,13 +106,7 @@ _CHUNK_LEVEL_OPTIONS = [ {"value": "sentence", "label": "Sentences"}, ] -_SPEAKER_MODE_OPTIONS = [ - {"value": "single", "label": "Single Speaker"}, - {"value": "multi", "label": "Multi-Speaker"}, -] - _CHUNK_LEVEL_VALUES = {option["value"] for option in _CHUNK_LEVEL_OPTIONS} -_SPEAKER_MODE_VALUES = {option["value"] for option in _SPEAKER_MODE_OPTIONS} _DEFAULT_ANALYSIS_THRESHOLD = 3 @@ -835,7 +829,6 @@ def _prepare_speaker_metadata( chapters: List[Dict[str, Any]], chunks: List[Dict[str, Any]], analysis_chunks: Optional[List[Dict[str, Any]]] = None, - speaker_mode: str, voice: str, voice_profile: Optional[str], threshold: int, @@ -848,7 +841,7 @@ def _prepare_speaker_metadata( chunk_list = [dict(chunk) for chunk in chunks] analysis_source = [dict(chunk) for chunk in (analysis_chunks or chunks)] threshold_value = max(1, int(threshold)) - analysis_enabled = speaker_mode == "multi" and run_analysis + analysis_enabled = run_analysis settings_state = _load_settings() global_random_languages = [ code @@ -1323,10 +1316,7 @@ def _apply_prepare_form( pending.chunk_level = raw_chunk_level chunk_level_literal = cast(ChunkLevel, pending.chunk_level) - raw_speaker_mode = (form.get("speaker_mode") or pending.speaker_mode or "single").strip().lower() - if raw_speaker_mode not in _SPEAKER_MODE_VALUES: - raw_speaker_mode = "single" - pending.speaker_mode = raw_speaker_mode + pending.speaker_mode = "single" pending.generate_epub3 = _coerce_bool(form.get("generate_epub3"), False) @@ -1660,13 +1650,12 @@ def _template_options() -> Dict[str, Any]: "voice_profiles": ordered_profiles, "voice_profile_options": profile_options, "separate_formats": ["wav", "flac", "mp3", "opus"], - "voice_catalog": voice_catalog, - "voice_catalog_map": {entry["id"]: entry for entry in voice_catalog}, + "voice_catalog": voice_catalog, + "voice_catalog_map": {entry["id"]: entry for entry in voice_catalog}, "sample_voice_texts": SAMPLE_VOICE_TEXTS, "voice_profiles_data": profiles, "speaker_configs": list_configs(), "chunk_levels": _CHUNK_LEVEL_OPTIONS, - "speaker_modes": _SPEAKER_MODE_OPTIONS, "speaker_analysis_threshold": current_settings.get( "speaker_analysis_threshold", _DEFAULT_ANALYSIS_THRESHOLD ), @@ -1718,7 +1707,6 @@ def _settings_defaults() -> Dict[str, Any]: "chapter_intro_delay": 0.5, "max_subtitle_words": 50, "chunk_level": "paragraph", - "speaker_mode": "single", "generate_epub3": False, "speaker_analysis_threshold": _DEFAULT_ANALYSIS_THRESHOLD, "speaker_pronunciation_sentence": "This is {{name}} speaking.", @@ -1788,10 +1776,6 @@ def _normalize_setting_value(key: str, value: Any, defaults: Dict[str, Any]) -> if isinstance(value, str) and value in _CHUNK_LEVEL_VALUES: return value return defaults[key] - if key == "speaker_mode": - if isinstance(value, str) and value in _SPEAKER_MODE_VALUES: - return value - return defaults[key] if key == "speaker_random_languages": if isinstance(value, (list, tuple, set)): return [code for code in value if isinstance(code, str) and code in LANGUAGE_DESCRIPTIONS] @@ -1995,9 +1979,6 @@ def settings_page() -> ResponseReturnValue: updated["chunk_level"] = _normalize_setting_value( "chunk_level", form.get("chunk_level"), defaults ) - updated["speaker_mode"] = _normalize_setting_value( - "speaker_mode", form.get("speaker_mode"), defaults - ) updated["separate_chapters_format"] = _normalize_setting_value( "separate_chapters_format", form.get("separate_chapters_format"), defaults ) @@ -2744,11 +2725,7 @@ def enqueue_job() -> ResponseReturnValue: chunk_level_value = raw_chunk_level chunk_level_literal = cast(ChunkLevel, chunk_level_value) - speaker_mode_default = str(settings.get("speaker_mode", "single")).strip().lower() - raw_speaker_mode = (request.form.get("speaker_mode") or speaker_mode_default).strip().lower() - if raw_speaker_mode not in _SPEAKER_MODE_VALUES: - raw_speaker_mode = "single" - speaker_mode_value = raw_speaker_mode + speaker_mode_value = "single" generate_epub3_default = bool(settings.get("generate_epub3", False)) generate_epub3 = _coerce_bool(request.form.get("generate_epub3"), generate_epub3_default) @@ -2764,12 +2741,11 @@ def enqueue_job() -> ResponseReturnValue: maximum=25, ) - initial_analysis = speaker_mode_value == "multi" + initial_analysis = False processed_chunks, speakers, analysis_payload, config_languages, _ = _prepare_speaker_metadata( chapters=selected_chapter_sources, chunks=raw_chunks, analysis_chunks=analysis_chunks, - speaker_mode=speaker_mode_value, voice=voice, voice_profile=selected_profile or None, threshold=analysis_threshold, @@ -2868,20 +2844,6 @@ def analyze_pending_job(pending_id: str) -> ResponseReturnValue: ) abort(400, message) - if pending.speaker_mode != "multi": - setattr(pending, "analysis_requested", False) - pending.chunks = [] - pending.speaker_analysis = {} - error_message = "Switch to multi-speaker mode to analyze speakers." - if _wants_wizard_json(): - return _wizard_json_response( - pending, - "chapters", - error=error_message, - status=400, - ) - abort(400, error_message) - if not enabled_overrides: setattr(pending, "analysis_requested", False) pending.chunks = [] @@ -2911,7 +2873,6 @@ def analyze_pending_job(pending_id: str) -> ResponseReturnValue: chapters=enabled_overrides, chunks=raw_chunks, analysis_chunks=analysis_chunks, - speaker_mode=pending.speaker_mode, voice=pending.voice, voice_profile=pending.voice_profile, threshold=pending.speaker_analysis_threshold, @@ -2981,9 +2942,6 @@ def finalize_job(pending_id: str) -> ResponseReturnValue: ) abort(400, message) - if pending.speaker_mode != "multi": - setattr(pending, "analysis_requested", False) - if not enabled_overrides: pending.chunks = [] error_message = "Select at least one chapter to convert." @@ -3003,9 +2961,8 @@ def finalize_job(pending_id: str) -> ResponseReturnValue: normalized_step = _normalize_wizard_step(active_step, pending) raw_chunks = build_chunks_for_chapters(enabled_overrides, level=chunk_level_literal) analysis_chunks = build_chunks_for_chapters(enabled_overrides, level="sentence") - is_multi = pending.speaker_mode == "multi" analysis_requested = bool(getattr(pending, "analysis_requested", False)) - should_force_entities = is_multi and normalized_step != "entities" + should_force_entities = analysis_requested and normalized_step != "entities" if analysis_requested: existing_roster: Optional[Mapping[str, Any]] = pending.speakers @@ -3019,12 +2976,11 @@ def finalize_job(pending_id: str) -> ResponseReturnValue: config_name = pending.applied_speaker_config or selected_config speaker_config_payload = get_config(config_name) if config_name else None - run_analysis = is_multi and (should_force_entities or analysis_requested) + run_analysis = should_force_entities or analysis_requested processed_chunks, roster, analysis_payload, config_languages, updated_config = _prepare_speaker_metadata( chapters=enabled_overrides, chunks=raw_chunks, analysis_chunks=analysis_chunks, - speaker_mode=pending.speaker_mode, voice=pending.voice, voice_profile=pending.voice_profile, threshold=pending.speaker_analysis_threshold, @@ -3183,8 +3139,6 @@ def _normalize_wizard_step(step: Optional[str], pending: Optional[PendingJob] = chosen = normalized else: chosen = default_step - if chosen == "entities" and pending is not None and pending.speaker_mode != "multi": - return "chapters" return chosen diff --git a/abogen/web/static/prepare.js b/abogen/web/static/prepare.js index 1a84aed..a949bac 100644 --- a/abogen/web/static/prepare.js +++ b/abogen/web/static/prepare.js @@ -474,38 +474,6 @@ const initPrepare = (root = document) => { }); }); - const speakerModeSelect = form.querySelector("#speaker_mode"); - const analysisToggleButtons = Array.from(form.querySelectorAll('[data-step-toggle="analysis"]')); - const finalizeToggleButtons = Array.from(form.querySelectorAll('[data-step-toggle="finalize"]')); - - const setButtonVisibility = (button, isVisible) => { - if (!button) return; - if (isVisible) { - button.hidden = false; - button.removeAttribute("aria-hidden"); - button.removeAttribute("tabindex"); - } else { - button.hidden = true; - button.setAttribute("aria-hidden", "true"); - button.setAttribute("tabindex", "-1"); - } - }; - - const updateStepButtons = () => { - if (!speakerModeSelect) { - return; - } - const modeValue = (speakerModeSelect.value || "").toLowerCase(); - const isMulti = modeValue === "multi"; - analysisToggleButtons.forEach((button) => setButtonVisibility(button, isMulti)); - finalizeToggleButtons.forEach((button) => setButtonVisibility(button, !isMulti)); - }; - - if (speakerModeSelect) { - updateStepButtons(); - speakerModeSelect.addEventListener("change", updateStepButtons); - } - const voiceModal = document.querySelector('[data-role="voice-modal"]'); let activeGenderFilter = ""; diff --git a/abogen/web/static/wizard.js b/abogen/web/static/wizard.js index 117db20..e9e94d1 100644 --- a/abogen/web/static/wizard.js +++ b/abogen/web/static/wizard.js @@ -273,7 +273,18 @@ const submitWizardForm = async (form, submitter) => { } const action = submitter?.getAttribute("formaction") || form.getAttribute("action") || window.location.href; const method = (submitter?.getAttribute("formmethod") || form.getAttribute("method") || "GET").toUpperCase(); + const stepTarget = submitter?.dataset?.stepTarget || ""; + const normalizedStepTarget = stepTarget ? stepTarget.toLowerCase() : ""; + if (normalizedStepTarget) { + const activeInput = form.querySelector('[data-role="active-step-input"]'); + if (activeInput) { + activeInput.value = normalizedStepTarget; + } + } const formData = new FormData(form); + if (normalizedStepTarget) { + formData.set("active_step", normalizedStepTarget); + } if (submitter && submitter.name && !formData.has(submitter.name)) { formData.append(submitter.name, submitter.value ?? ""); } diff --git a/abogen/web/templates/job_detail.html b/abogen/web/templates/job_detail.html index a3ee9aa..3202e99 100644 --- a/abogen/web/templates/job_detail.html +++ b/abogen/web/templates/job_detail.html @@ -27,7 +27,6 @@
  • Max words per subtitle: {{ job.max_subtitle_words }}
  • Project folder: {{ 'Yes' if job.save_as_project else 'No' }}
  • Chunk granularity: {{ job.chunk_level|replace('_', ' ')|title }}
  • -
  • Speaker mode: {{ job.speaker_mode|replace('_', ' ')|title }}
  • Speaker analysis threshold: {{ job.speaker_analysis_threshold }}
  • Generate EPUB 3: {{ 'Yes' if job.generate_epub3 else 'No' }}
  • diff --git a/abogen/web/templates/partials/new_job_step_book.html b/abogen/web/templates/partials/new_job_step_book.html index b785237..ee8fe86 100644 --- a/abogen/web/templates/partials/new_job_step_book.html +++ b/abogen/web/templates/partials/new_job_step_book.html @@ -31,14 +31,6 @@ {% else %} {% set generate_epub3 = pending.generate_epub3 if pending else settings_dict.get('generate_epub3', False) %} {% endif %} -{% set speaker_mode_value = form_values.get('speaker_mode') if form_values else None %} -{% if not speaker_mode_value %} - {% if pending and pending.speaker_mode %} - {% set speaker_mode_value = pending.speaker_mode %} - {% else %} - {% set speaker_mode_value = settings_dict.get('speaker_mode', 'single') %} - {% endif %} -{% endif %} {% set chunk_level_value = form_values.get('chunk_level') if form_values else None %} {% if not chunk_level_value %} {% if pending and pending.chunk_level %} @@ -247,25 +239,15 @@

    Entities & casting

    -
    -
    - - -

    Reuse a saved roster to keep character voices consistent.

    -
    -
    - - -
    +
    + + +

    Reuse a saved roster to keep character voices consistent.

    diff --git a/abogen/web/templates/partials/new_job_step_chapters.html b/abogen/web/templates/partials/new_job_step_chapters.html index 649501a..18a9a17 100644 --- a/abogen/web/templates/partials/new_job_step_chapters.html +++ b/abogen/web/templates/partials/new_job_step_chapters.html @@ -1,4 +1,3 @@ -{% set is_multi_speaker = pending.speaker_mode == 'multi' %}
    -
    - - -