Skip to content

fix(server): segment text-only OpenAI transcription responses#3292

Merged
LauraGPT merged 1 commit into
mainfrom
codex/openai-fallback-segments-20260719
Jul 19, 2026
Merged

fix(server): segment text-only OpenAI transcription responses#3292
LauraGPT merged 1 commit into
mainfrom
codex/openai-fallback-segments-20260719

Conversation

@LauraGPT

Copy link
Copy Markdown
Collaborator

Summary

Fixes the OpenAI-compatible /v1/audio/transcriptions fallback path for non-vLLM models such as sensevoice / paraformer when the underlying AutoModel.generate() result returns text but no sentence_info.

Before this patch, response_format=verbose_json returned segments: [] even when text was populated, which causes OpenAI-compatible clients that rely on segments for subtitles to render one large cue or lose timing entirely.

This patch:

  • records fallback audio duration via soundfile.info()
  • preserves model-provided sentence_info when available
  • builds coarse OpenAI-style segments from long text-only results when sentence_info is missing
  • keeps short text-only responses as one cue
  • adds lightweight tests for the Kennedy-style long-text / empty-segments response shape

Validation

python3 -m pytest tests/test_server_app_openai_segments.py tests/test_fun_asr_nano_openai_response.py -q
# 4 passed

python3 -m py_compile funasr/bin/_server_app.py tests/test_server_app_openai_segments.py

git diff --check

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

Copy link
Copy Markdown
Contributor

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 fallback segment generation for non-LLM models when only text is returned. It adds helper functions to split text into OpenAI-compatible segments based on character length and audio duration, and includes unit tests for this behavior. Feedback highlights two main issues: potential data loss when the audio duration is invalid or zero (where only the first segment of a split text is returned instead of the full text), and a redundant, dead-code check for an empty word list after the text has already been stripped and validated.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread funasr/bin/_server_app.py
Comment on lines +70 to +71
if len(parts) == 1 or duration <= 0:
return [{"start": 0.0, "end": max(float(duration), 0.0), "text": parts[0]}]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

When duration is less than or equal to 0 (which can happen if soundfile.info fails to parse the audio duration, e.g., for unsupported formats like MP3 on some platforms), and the transcribed text is long enough to be split into multiple parts, returning parts[0] will silently discard all subsequent parts of the transcription. This leads to severe data loss in the response. Instead, the entire text.strip() should be returned as a single segment when the duration is invalid or cannot be determined.

Suggested change
if len(parts) == 1 or duration <= 0:
return [{"start": 0.0, "end": max(float(duration), 0.0), "text": parts[0]}]
if len(parts) == 1 or duration <= 0:
return [{"start": 0.0, "end": max(float(duration), 0.0), "text": text.strip()}]

Comment thread funasr/bin/_server_app.py
Comment on lines +35 to +37
words = text.split()
if not words:
return [text[i : i + max_chars] for i in range(0, len(text), max_chars)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Since text is stripped and checked for truthiness on lines 31-33, it is guaranteed to contain at least one non-whitespace character. Therefore, text.split() will never return an empty list, making the if not words: check dead code. We can safely remove this check to simplify the function.

Suggested change
words = text.split()
if not words:
return [text[i : i + max_chars] for i in range(0, len(text), max_chars)]
words = text.split()

@LauraGPT
LauraGPT merged commit 6be08b4 into main Jul 19, 2026
@LauraGPT
LauraGPT deleted the codex/openai-fallback-segments-20260719 branch July 19, 2026 11:18
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