Add MiniMax text-to-speech processor - #169
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces the MiniMaxTextToSpeech processor, which integrates with the MiniMax Text-to-Audio API to convert text parts into audio. It supports both global and China endpoints, streaming responses, and multiple audio formats, and includes a comprehensive test suite and documentation. The review feedback highlights two critical improvements: stripping the sensitive Authorization header when fetching audio from pre-signed URLs to prevent credential leakage, and making the SSE stream parser more robust by explicitly ignoring non-data metadata lines.
|
|
||
| async def _audio_bytes(self, audio: str) -> bytes: | ||
| if self._output_format == 'url': | ||
| response = await self._client.get(audio) |
There was a problem hiding this comment.
When output_format is set to 'url', the processor fetches the audio file from the pre-signed URL returned by the MiniMax API. Since self._client is initialized with default headers containing the sensitive Authorization header (MiniMax API key), calling self._client.get(audio) will forward this credential to the external storage provider (e.g., Aliyun OSS or AWS S3) hosting the audio file. This leads to credential leakage and can also cause the request to fail with a 400 Bad Request or 403 Forbidden error because object storage providers often reject requests containing unexpected authorization headers. To prevent this, strip the Authorization and Content-Type headers when fetching the audio URL.
response = await self._client.get(
audio,
headers={'Authorization': None, 'Content-Type': None},
)| async for line in response.aiter_lines(): | ||
| if not line or line.startswith(':'): | ||
| continue | ||
| if line.startswith('data:'): | ||
| line = line[5:].strip() | ||
| if line == '[DONE]': | ||
| continue |
There was a problem hiding this comment.
The current SSE parser processes any line that does not start with : or is not empty. However, standard SSE streams can contain other metadata lines (such as event:, id:, or retry:). If the server sends any of these metadata lines, the parser will attempt to parse them as JSON and fail with a JSONDecodeError. To make the stream parsing robust and compliant with the SSE specification, explicitly ignore any lines that do not start with data:.
async for line in response.aiter_lines():
if not line or line.startswith(':'):
continue
if not line.startswith('data:'):
continue
line = line[5:].strip()
if line == '[DONE]':
continue
Reason: Add current MiniMax Text-to-Audio support through a reusable contributed processor.
This adds configurable global and China endpoints, the current speech model set,
streaming and non-streaming response parsing, and MP3, WAV, FLAC, and PCM output.
It also documents the processor and covers request construction, endpoint routing,
audio decoding, pass-through behavior, error handling, and validation.
Checks:
.venv/bin/pytest -q genai_processors/contrib/tests/minimax_text_to_speech_test.py.venv/bin/pytest -q genai_processors/tests/text_to_speech_test.py.venv/bin/pyink --check genai_processors/contrib/minimax_text_to_speech.py genai_processors/contrib/tests/minimax_text_to_speech_test.py.venv/bin/python -m compileall -q genai_processors/contrib/minimax_text_to_speech.py genai_processors/contrib/tests/minimax_text_to_speech_test.py