fix(gateway): support Feishu voice TTS opus delivery - #37804
Conversation
10d021a to
32d47bf
Compare
|
Updated this PR branch onto latest upstream Conflict resolution was limited to the Feishu test mock path, keeping it on Validation run:
Result: 2 passed. |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for combining the two verified Feishu voice-delivery gaps. Current main still excludes Feishu from want_opus at tools/tts_tool.py:2202, and sends an audio payload with only file_key at plugins/platforms/feishu/adapter.py:4591.
Problems
- The new duration probe is called directly inside async
_send_uploaded_file_message(plugins/platforms/feishu/adapter.py:4506in the PR diff) but runssubprocess.run(..., timeout=10). The live adapter has_run_blocking()atplugins/platforms/feishu/adapter.py:1692-1695; use it so an audio probe cannot stall the gateway loop. _probe_audio_duration_ms()returnsNonewhen ffmpeg is unavailable. Native-Opus providers use.oggwithout needing ffmpeg (tools/tts_tool.py:2241-2244), so that path would still send the duration-less payload and preserve the reported behavior.tests/tools/test_tts_command_providers.py:207snapshots the entire format set. Replace it with an Opus acceptance behavior test, and add Feishu routing coverage analogous to the Telegram-only test intests/tools/test_tts_opus_routing.py:47-70.
Suggested changes
- Offload the probe and provide a positive non-ffmpeg fallback before adding the upload/message duration.
- Add Feishu Opus-routing and no-ffmpeg duration-fallback tests.
Automated hermes-sweeper review.
| requested_message_type=outbound_message_type, | ||
| ) | ||
| upload_duration_ms = ( | ||
| self._probe_audio_duration_ms(file_path) |
There was a problem hiding this comment.
This synchronous probe runs subprocess.run(..., timeout=10) on the gateway event loop. Please await the adapter's existing _run_blocking(self._probe_audio_duration_ms, file_path) (or an equivalent nonblocking call), and ensure the probe still supplies a positive duration when ffmpeg is unavailable.
| def _probe_audio_duration_ms(file_path: str) -> Optional[int]: | ||
| ffmpeg = shutil.which("ffmpeg") | ||
| if not ffmpeg: | ||
| return None |
There was a problem hiding this comment.
Please pass creationflags=windows_hide_flags() here, as existing subprocess call sites do, so Feishu TTS delivery does not flash a console window on native Windows.
|
|
||
| def test_output_format_supported_set(self): | ||
| assert COMMAND_TTS_OUTPUT_FORMATS == frozenset({"mp3", "wav", "ogg", "flac"}) | ||
| assert COMMAND_TTS_OUTPUT_FORMATS == frozenset({"mp3", "wav", "ogg", "opus", "flac"}) |
There was a problem hiding this comment.
This freezes the full mutable format catalog. Test the intended contract instead: assert that _get_command_tts_output_format({"format": "opus"}) returns "opus".
|
The root cause here (gateway auto-TTS choosing MP3 vs Ogg/Opus via the cleared (Landed via #73508, merge |
What does this PR do?
Fixes Feishu voice/TTS delivery so generated TTS audio can render as native Feishu voice bubbles instead of generic file attachments.
The Feishu path had two related gaps:
This draft combines those fixes and also allows command TTS providers to declare
.opusoutput directly.Related Issue
Fixes #16524
Related existing PRs found during duplicate search:
want_opuspart intools/tts_tool.py.This draft is intentionally scoped as a combined alternative because it covers both areas plus command-provider
.opussupport.Type of Change
Changes Made
tools/tts_tool.py— treat Feishu like Telegram for Opus voice output, recognize.opusas a voice-compatible payload, and allow command providers to outputopus.gateway/platforms/feishu.py— probe Opus audio duration and include duration metadata in Feishu upload/message payload construction for audio sends.tests/tools/test_tts_command_providers.py— update accepted command TTS output formats.tests/gateway/test_feishu.py— assert Feishu voice sends include duration metadata in the upload body and audio message payload.How to Test
Automated checks run on macOS 26.4.1 with Python 3.11.15 virtualenv:
Result:
Manual behavior to verify with a real Feishu bot:
Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AScreenshots / Logs