Skip to content

Strip markdown from the speech handed to Assist/TTS - #43

Open
qian2023qian wants to merge 1 commit into
techartdev:mainfrom
qian2023qian:fix/strip-markdown-for-tts
Open

qian2023qian wants to merge 1 commit into
techartdev:mainfrom
qian2023qian:fix/strip-markdown-for-tts

Conversation

@qian2023qian

Copy link
Copy Markdown

Problem

When OpenClaw answers through the Assist pipeline, intent_response.speech is
handed straight to text-to-speech. The speech is currently set to the raw
response text, so markdown is read out literally:

**卧室三**:23.3℃ / 湿度 61% → "asterisk asterisk 卧室三 asterisk asterisk ..."

Reported symptoms include ** being spoken aloud, headings/list markers being
read as symbols, and URLs spelled out character by character.

Change

  • Add strip_markdown_for_speech() to the dependency-free helpers.py:
    headings, bullets and numbered lists, block quotes, code fences and inline
    code, **/__/*/_ emphasis, ~~strikethrough~~ and [text](url) link
    syntax are removed. Words, numbers, punctuation and emoji are preserved, and
    arithmetic such as 3*4=12 is deliberately left alone.
  • Use it only for the speech text in conversation.py. The chat card and
    the openclaw_message_received event keep the raw response, so markdown still
    renders in the UI.

Tests

  • python -m unittest discover -s tests -v → 17 tests, 8 of them new:
    CJK bold text, a full reported response, headings/lists/quotes, links and
    inline code, arithmetic (3*4=12), plain text, empty input, and an
    unbalanced ** run.
  • Also verified against a real response captured from HA's pipeline debug view:
    22 × ** before → 0 after, with emoji and numeric values intact.

Relation to #6

This is the integration-side safeguard for the markdown part of #6 — it stays
correct even once a voice-optimised agent is in use, and fixes the symptom
immediately for existing setups. It does not implement the voice-origin
detection / TTS-friendly text (numbers, dates, bare URLs) that #6 also asks
for, so I did not mark this as closing it.

Note for the streaming work in #39: once responses are streamed through Assist,
the deltas are piped to TTS directly and the final speech text is no longer what
gets spoken, so the same stripping has to be applied per delta. Happy to prepare
that follow-up if it is useful.

Assist passes `intent_response.speech` straight to text-to-speech, so any
markdown left in a reply is read out literally ("asterisk asterisk bold text
asterisk asterisk"). OpenClaw currently sets the speech to the raw response
text.

Add `strip_markdown_for_speech()` to the dependency-free helpers and use it
for the speech only: headings, list markers, quotes, code fences and inline
code, emphasis, strikethrough and link syntax are removed, while words,
numbers, punctuation and emoji are preserved. The chat card and the
`openclaw_message_received` event keep receiving the raw response.

Regression tests cover CJK bold text, a full reported response, headings and
lists, links/inline code, arithmetic such as `3*4=12`, plain text and an
unbalanced emphasis run.

Refs techartdev#6 (the broader voice-mode request). This is the integration-side
safeguard that stays correct even when a voice-optimised agent is in use.
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