Skip to content

feat: markdown-aware TTS text normalization#1

Merged
Fieldnote-Echo merged 1 commit into
masterfrom
feat/markdown-normalization
Feb 21, 2026
Merged

feat: markdown-aware TTS text normalization#1
Fieldnote-Echo merged 1 commit into
masterfrom
feat/markdown-normalization

Conversation

@Fieldnote-Echo

Copy link
Copy Markdown
Owner

Summary

  • Adds handle_markdown() pre-processing pass that strips markdown formatting before TTS synthesis
  • New markdown_normalization toggle in NormalizationOptions (default True)
  • 24 test cases covering headings, bold, italic, links, code blocks, tables, mixed LLM output

Changes

  • api/src/services/text_processing/normalizer.py — new handle_markdown() function + integration into normalize_text()
  • api/src/structures/schemas.py — new markdown_normalization field on NormalizationOptions
  • api/src/services/text_processing/test_normalizer.py — standalone test suite (no Kokoro deps required)

Test plan

  • pytest api/src/services/text_processing/test_normalizer.py -v passes all 24 tests
  • Manual TTS test with markdown input via /v1/audio/speech

🤖 Generated with Claude Code

Add handle_markdown() pre-processing pass that strips markdown formatting
(headings, bold, italic, links, code blocks, tables, etc.) before TTS
synthesis. Preserves code block contents literally and avoids false
positives on snake_case identifiers.

- New: handle_markdown() function in normalizer.py
- New: markdown_normalization toggle in NormalizationOptions (default True)
- New: test_normalizer.py with 24 test cases including mixed LLM output
- Fix: trailing whitespace in normalize_text() output (.strip())

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@Fieldnote-Echo
Fieldnote-Echo merged commit c453baf into master Feb 21, 2026
@Fieldnote-Echo
Fieldnote-Echo deleted the feat/markdown-normalization branch February 21, 2026 22:40
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @Fieldnote-Echo, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the Text-to-Speech (TTS) system by introducing a robust mechanism to preprocess text containing Markdown. The primary goal is to improve the clarity and naturalness of spoken output by systematically removing visual formatting syntax, such as bolding, links, and code blocks, before the text is synthesized. This ensures that the TTS engine focuses solely on articulating the textual content, leading to a more pleasant listening experience.

Highlights

  • Markdown Normalization Function: Introduced a new handle_markdown() function that intelligently strips various Markdown formatting elements (e.g., bold, italics, links, code blocks, headings, lists, tables) from text, ensuring that only the content is passed to the Text-to-Speech (TTS) engine.
  • Configurable Normalization Option: Added a markdown_normalization boolean field to the NormalizationOptions schema, allowing callers to enable or disable this new Markdown stripping behavior. It defaults to True.
  • Integration into Text Normalization Pipeline: Integrated the handle_markdown() function as the first pre-processing step within the normalize_text() pipeline, ensuring Markdown syntax is removed before other normalization rules (like email or URL handling) are applied, which prevents conflicts and improves accuracy.
  • Comprehensive Test Suite: Included a new, standalone test file (test_normalizer.py) with 24 test cases specifically designed to validate the handle_markdown() function's behavior across a wide range of Markdown syntax, including edge cases like nested formatting and preserving content within code blocks.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • api/src/services/text_processing/normalizer.py
    • Updated module docstring to reflect the fork from Kokoro-FastAPI v0.2.4 and the addition of Markdown normalization.
    • Added handle_markdown() function with associated regex patterns to strip various Markdown elements.
    • Integrated handle_markdown() into normalize_text() as an early pre-processing step, conditional on markdown_normalization option.
    • Adjusted whitespace and added a .strip() call to the final return of normalize_text().
  • api/src/services/text_processing/test_normalizer.py
    • Added a new test file containing 24 unit tests for the handle_markdown() function.
    • Implemented a shim to allow standalone testing of handle_markdown() without full Kokoro dependencies.
  • api/src/structures/schemas.py
    • Updated module docstring to reflect the fork and the addition of the new field.
    • Added markdown_normalization boolean field with a default of True to the NormalizationOptions class.
    • Corrected whitespace formatting for default values in volume_multiplier fields.
Activity
  • The author has added a new handle_markdown() function to strip Markdown formatting from text.
  • A new markdown_normalization toggle has been introduced in NormalizationOptions to control this behavior.
  • The handle_markdown() function has been integrated into the normalize_text() pipeline.
  • A comprehensive test suite with 24 test cases has been added to validate the Markdown normalization.
  • The author has confirmed that pytest api/src/services/text_processing/test_normalizer.py -v passes all tests.
  • A manual TTS test with markdown input via /v1/audio/speech is planned.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces markdown-aware text normalization for TTS synthesis, which is a valuable addition for handling varied input formats. The handle_markdown function is well-designed, employing a clever placeholder strategy to protect code blocks from premature stripping. The integration into normalize_text is correctly prioritized to ensure markdown links are processed before URL normalization. The new test suite is comprehensive, covering a wide range of markdown elements and edge cases, which significantly boosts confidence in the new functionality.

_MD_INLINE_CODE = re.compile(r"`([^`]+)`")
_MD_IMAGE = re.compile(r"!\[([^\]]*)\]\([^)]+\)")
_MD_LINK = re.compile(r"\[([^\]]+)\]\([^)]+\)")
_MD_BOLD = re.compile(r"\*\*(.+?)\*\*")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current _MD_BOLD regex only handles **bold**. Markdown also supports __bold__ for bold text. To ensure comprehensive markdown stripping, consider updating this regex to include __ as well, using a backreference to match the opening and closing delimiters.

Suggested change
_MD_BOLD = re.compile(r"\*\*(.+?)\*\*")
_MD_BOLD = re.compile(r"(\*\*|__)(.+?)\1")

Comment on lines +267 to +273
# Table pipes — only replace on lines that look like table rows (2+ pipes).
# This preserves non-table pipes like "true | false".
lines = text.split("\n")
for i, line in enumerate(lines):
if line.count("|") >= 2:
lines[i] = line.replace("|", " ")
text = "\n".join(lines)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current approach to stripping table pipes relies on a heuristic (line.count("|") >= 2). While this works for typical markdown tables, it might inadvertently affect non-table lines that happen to contain two or more pipe characters. For example, a sentence like "This is option A | option B | option C" would have its pipes replaced, which might not be the desired TTS output. Consider refining this logic to be more specific to actual table structures, perhaps by checking for header/separator rows more explicitly, or by using a more robust markdown parsing library if this becomes a frequent issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant