fix(feishu): attach ffprobe-derived duration to voice uploads - #40592
fix(feishu): attach ffprobe-derived duration to voice uploads#40592seamusmore wants to merge 1 commit into
Conversation
Feishu requires duration (ms) during file upload (POST /im/v1/files) for audio files, not just in the message payload. Previously only the message send included duration via ffprobe; the file upload body was missing it. Add duration extraction before upload and pass it to _build_file_upload_body so the SDK includes it in CreateFileRequestBody. This completes the fix from NousResearch#40592 which only added duration to the message payload.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for identifying several real Feishu voice-path gaps. Current main still has the reported behaviors, but this branch needs a targeted salvage.
Problems
- Feishu was migrated to the bundled plugin in
560010547; the live code is nowplugins/platforms/feishu/adapter.py:2158,:3822, and:4536.gateway/platforms/feishu.pyno longer exists, so these hunks need porting rather than a direct merge. subprocess.run()blocks async adapter execution for up to 60 seconds in the PR atgateway/platforms/feishu.py:2072, and ffprobe blocks similarly at:4401and:4446.tests/gateway/test_feishu.py:2596only covers an existing Opus upload; this change needs regression coverage for STT classification, conversion/duration handling, and cross-turn TTS dedup.
Suggested changes
- Port the Feishu work to
plugins/platforms/feishu/adapter.py, run ffmpeg/ffprobe off-loop, calculate duration once, and add focused tests.
Automated hermes-sweeper review.
329bfad to
cb52407
Compare
969d269 to
cb52407
Compare
…dio path dedup Trimmed cherry-pick of PR #40592 (duration + dedup hunks only; the voice-classification hunk duplicates #29235 and the send_voice Opus rewrite is out of scope for this inbound-focused PR): - adapter.py: ffprobe duration (off-loop) attached to Feishu voice uploads via _build_file_upload_body(duration=...) and the audio message payload (#16524, #8300) - gateway/run.py: TTS dedup narrowed to the current turn; _enrich_message_with_transcription dedups repeated audio paths Refs #40592 #16524 #8300
…dio path dedup Trimmed cherry-pick of PR #40592 (duration + dedup hunks only; the voice-classification hunk duplicates #29235 and the send_voice Opus rewrite is out of scope for this inbound-focused PR): - adapter.py: ffprobe duration (off-loop) attached to Feishu voice uploads via _build_file_upload_body(duration=...) and the audio message payload (#16524, #8300) - gateway/run.py: TTS dedup narrowed to the current turn; _enrich_message_with_transcription dedups repeated audio paths Refs #40592 #16524 #8300
…dio path dedup Trimmed cherry-pick of PR #40592 (duration + dedup hunks only; the voice-classification hunk duplicates #29235 and the send_voice Opus rewrite is out of scope for this inbound-focused PR): - adapter.py: ffprobe duration (off-loop) attached to Feishu voice uploads via _build_file_upload_body(duration=...) and the audio message payload (#16524, #8300) - gateway/run.py: TTS dedup narrowed to the current turn; _enrich_message_with_transcription dedups repeated audio paths Refs #40592 #16524 #8300
adapter.py: - send_voice: async Opus conversion via asyncio.to_thread (off-loop) - _resolve_normalized_message_type: AUDIO -> VOICE for STT routing - _send_uploaded_file_message: ffprobe off-loop, duration reused - _build_file_upload_body: optional duration parameter gateway/run.py: - _should_send_voice_reply: TTS dedup narrowed to current turn - _enrich_message_with_transcription: audio path dedup Tested: 5/5 single transcription, no event-loop blocking.
cb52407 to
a81aafd
Compare
|
Current head |
|
The two failing CI checks are unrelated to this PR's changes:
All relevant checks pass: Python tests (8/8 slices), ruff lints, Docker builds (amd64 + arm64), OSV scan. This appears to be a pre-existing flaky E2E test, not a regression from this diff. |
|
Merged into main via consolidated salvage PR #73515 (merge Your contribution is credited to you in git history. Thank you! Closing this PR as merged-via-salvage. |
…dio path dedup Trimmed cherry-pick of PR NousResearch#40592 (duration + dedup hunks only; the voice-classification hunk duplicates NousResearch#29235 and the send_voice Opus rewrite is out of scope for this inbound-focused PR): - adapter.py: ffprobe duration (off-loop) attached to Feishu voice uploads via _build_file_upload_body(duration=...) and the audio message payload (NousResearch#16524, NousResearch#8300) - gateway/run.py: TTS dedup narrowed to the current turn; _enrich_message_with_transcription dedups repeated audio paths Refs NousResearch#40592 NousResearch#16524 NousResearch#8300
Adds ffprobe duration probing to
_send_uploaded_file_message, passing the duration (in ms) to both the file upload body and the message payload for audio-type messages. Falls back to the existing pure-Python OGG/Opus granule parser when ffprobe is unavailable.Background
This PR originally carried six Feishu voice-path fixes. During rebase onto current
main:mainvia fix(feishu): classify native voice messages as VOICE for auto-transcription #29235 (by @wuli666), rebase auto-resolved this hunk.gateway/run.pyhunks) — landed onmainvia commitd0c635399, rebase auto-resolved.send_voiceOpus conversion rewrite — marked out of scope by @teknium1's review, removed.This PR now carries only the adapter-side duration handling that is not yet on
main.Changes
plugins/platforms/feishu/adapter.py:_send_uploaded_file_message: probes the file withffprobeviaasyncio.to_thread(non-blocking), stores duration in ms asupload_duration.upload_duration or duration_ms— prefers ffprobe result, falls back to the existing pure-Python OGG/Opus granule-position parser (_get_audio_duration_ms) for.opusfiles.resolved_message_type == "audio"andupload_durationis available, the duration is included in the Feishu message payload ({"file_key": ..., "duration": ...}) so Feishu clients display the correct voice-bubble length.payload_dict(with duration) instead of the bare{"file_key": ...}.Fixes #16524, #8300.
Related
main