from __future__ import annotations import tempfile import zipfile from dataclasses import dataclass from pathlib import Path from typing import Iterable, List, Sequence MARKER_PREFIX = "[[ABOGEN-DBG:" MARKER_SUFFIX = "]]" @dataclass(frozen=True) class DebugTTSSample: code: str label: str text: str DEBUG_TTS_SAMPLES: Sequence[DebugTTSSample] = ( DebugTTSSample( code="APOS_001", label="Apostrophes & contractions (1)", text="It's a beautiful day, isn't it? Let's see what we'll do.", ), DebugTTSSample( code="APOS_002", label="Apostrophes & contractions (2)", text="I'm sure you're ready; we'd better go before it's too late.", ), DebugTTSSample( code="APOS_003", label="Apostrophes & contractions (3)", text="He'll say it's fine, but I can't promise it'll work.", ), DebugTTSSample( code="APOS_004", label="Apostrophes & contractions (4)", text="They've done it, and I'd agree they've earned it.", ), DebugTTSSample( code="APOS_005", label="Apostrophes & contractions (5)", text="She's here, we're late, they're waiting, and you're right.", ), DebugTTSSample( code="POS_001", label="Plural possessives (1)", text="The dogs' bowls were empty, but the boss's office was quiet.", ), DebugTTSSample( code="POS_002", label="Plural possessives (2)", text="The teachers' lounge was closed during the students' exams.", ), DebugTTSSample( code="POS_003", label="Plural possessives (3)", text="The actresses' roles changed, and the directors' notes piled up.", ), DebugTTSSample( code="POS_004", label="Plural possessives (4)", text="The Joneses' car was parked by the neighbors' fence.", ), DebugTTSSample( code="POS_005", label="Plural possessives (5)", text="The bosses' meeting ended before the witnesses' statements began.", ), DebugTTSSample( code="NUM_001", label="Grouped numbers (1)", text="There are 1,234 apples, 56 oranges, and 7.89 liters of juice.", ), DebugTTSSample( code="NUM_002", label="Grouped numbers (2)", text="The population is 10,000,000 and the area is 123.45 square miles.", ), DebugTTSSample( code="NUM_003", label="Grouped numbers (3)", text="Set the timer for 0.5 seconds, then wait 2.0 minutes.", ), DebugTTSSample( code="NUM_004", label="Grouped numbers (4)", text="We measured 3.1415 radians and wrote down 2,718.28 as well.", ), DebugTTSSample( code="NUM_005", label="Grouped numbers (5)", text="The sequence is 1, 2, 3, 4, 5, and then 13.", ), DebugTTSSample( code="YEAR_001", label="Years and decades (1)", text="In 1999, people said the '90s were over.", ), DebugTTSSample( code="YEAR_002", label="Years and decades (2)", text="In 2001, the show premiered; by 2010 it was everywhere.", ), DebugTTSSample( code="YEAR_003", label="Years and decades (3)", text="The 1980s were loud, and the 1970s were groovy.", ), DebugTTSSample( code="YEAR_004", label="Years and decades (4)", text="She loved the '80s, but he preferred the '60s.", ), DebugTTSSample( code="YEAR_005", label="Years and decades (5)", text="In 2024, we looked back at 2020 and planned for 2030.", ), DebugTTSSample( code="DATE_001", label="Dates (1)", text="On 2023-01-01, we celebrated the new year.", ), DebugTTSSample( code="DATE_002", label="Dates (2)", text="The deadline is 1999-12-31 at midnight.", ), DebugTTSSample( code="DATE_003", label="Dates (3)", text="Leap day happens on 2024-02-29.", ), DebugTTSSample( code="DATE_004", label="Dates (4)", text="Some formats look like 01/02/2003 and can be ambiguous.", ), DebugTTSSample( code="DATE_005", label="Dates (5)", text="We met on March 5, 2020 and again on Apr. 7, 2021.", ), DebugTTSSample( code="CUR_001", label="Currency symbols (1)", text="The price is $10.50, but it was £8.00 yesterday.", ), DebugTTSSample( code="CUR_002", label="Currency symbols (2)", text="Tickets cost €12, and the fine was $0.99.", ), DebugTTSSample( code="CUR_003", label="Currency symbols (3)", text="The bill was ¥500 and the refund was $-3.25.", ), DebugTTSSample( code="CUR_004", label="Currency symbols (4)", text="He paid £1,234.56 for the instrument.", ), DebugTTSSample( code="CUR_005", label="Currency symbols (5)", text="The subscription is $5 per month, or $50 per year.", ), DebugTTSSample( code="TITLE_001", label="Titles and abbreviations (1)", text="Dr. Smith lives on Elm St. near the U.S. border.", ), DebugTTSSample( code="TITLE_002", label="Titles and abbreviations (2)", text="Mr. and Mrs. Doe met Prof. Adams at 5 p.m.", ), DebugTTSSample( code="TITLE_003", label="Titles and abbreviations (3)", text="Gen. Smith spoke to Sgt. Rivera on Main St.", ), DebugTTSSample( code="TITLE_004", label="Titles and abbreviations (4)", text="The report came from the U.K. office, not the U.S.A. team.", ), DebugTTSSample( code="TITLE_005", label="Titles and abbreviations (5)", text="St. John's is different from St. Louis.", ), DebugTTSSample( code="PUNC_001", label="Terminal punctuation (1)", text="This sentence ends without punctuation", ), DebugTTSSample( code="PUNC_002", label="Terminal punctuation (2)", text="An ellipsis is already present...", ), DebugTTSSample( code="PUNC_003", label="Terminal punctuation (3)", text="A question without a mark", ), DebugTTSSample( code="PUNC_004", label="Terminal punctuation (4)", text="An exclamation without a bang", ), DebugTTSSample( code="PUNC_005", label="Terminal punctuation (5)", text='A quote ends here"', ), DebugTTSSample( code="QUOTE_001", label="ALL CAPS inside quotes (1)", text='He shouted, "THIS IS IMPORTANT!" and then whispered, "ok."', ), DebugTTSSample( code="QUOTE_002", label="ALL CAPS inside quotes (2)", text='She said, "NO WAY", but he replied, "maybe".', ), DebugTTSSample( code="QUOTE_003", label="ALL CAPS inside quotes (3)", text='The sign read "DO NOT ENTER" and the note read "pls knock".', ), DebugTTSSample( code="QUOTE_004", label="ALL CAPS inside quotes (4)", text='He muttered, "OK", then yelled, "STOP!"', ), DebugTTSSample( code="QUOTE_005", label="ALL CAPS inside quotes (5)", text='They chanted, "USA!" and someone wrote "idk".', ), DebugTTSSample( code="FOOT_001", label="Footnote indicators (1)", text="This is a sentence with a footnote[1] and another[12].", ), DebugTTSSample( code="FOOT_002", label="Footnote indicators (2)", text="Some books use multiple footnotes like this[2][3] in a row.", ), DebugTTSSample( code="FOOT_003", label="Footnote indicators (3)", text="A footnote can appear mid-sentence[4] and continue afterward.", ), DebugTTSSample( code="FOOT_004", label="Footnote indicators (4)", text="Edge cases include [0] or very large indices like [1234].", ), DebugTTSSample( code="FOOT_005", label="Footnote indicators (5)", text="Sometimes a footnote follows punctuation.[5] Sometimes it doesn't[6]", ), ) def marker_for(code: str) -> str: return f"{MARKER_PREFIX}{code}{MARKER_SUFFIX}" def build_debug_epub(dest_path: Path, *, title: str = "abogen debug samples") -> Path: """Create a tiny EPUB containing all debug samples. The text includes stable marker codes so developers can report failures precisely. """ dest_path = Path(dest_path) dest_path.parent.mkdir(parents=True, exist_ok=True) chapter_lines: List[str] = [ '', "", '', "
", f"Each paragraph begins with a stable debug code marker.
", ] for sample in DEBUG_TTS_SAMPLES: safe_label = sample.label.replace("&", "and") chapter_lines.append(f"" + marker_for(sample.code) + " " + sample.text + "
" ) chapter_lines += ["", ""] chapter_xhtml = "\n".join(chapter_lines) container_xml = """