Skip to content

Add Qwen 3 TTS support for Simplismart-livekit plugin#5474

Merged
tinalenguyen merged 1 commit intolivekit:mainfrom
simplipratik:integration/qwen3-tts
Apr 21, 2026
Merged

Add Qwen 3 TTS support for Simplismart-livekit plugin#5474
tinalenguyen merged 1 commit intolivekit:mainfrom
simplipratik:integration/qwen3-tts

Conversation

@simplipratik
Copy link
Copy Markdown
Contributor

@simplipratik simplipratik commented Apr 17, 2026

Summary

This PR adds Qwen 3 TTS support to the SimpliSmart LiveKit plugin while maintaining full backwards compatibility with the existing Orpheus TTS implementation.

Changes

  • Added qwen-tts to TTSModels in models.py
  • Created QwenTTSOptions class for Qwen 3 specific configuration (language, leading_silence)
  • Updated TTS class to accept an options parameter that can be either SimplismartTTSOptions or QwenTTSOptions
  • Updated ChunkedStream._run() to use type-based payload construction for the appropriate API format
  • Added comprehensive error handling and logging (consistent with stt.py patterns)
  • Exported QwenTTSOptions and SimplismartTTSOptions from the module

Usage

Legacy Orpheus (backwards compatible)

from livekit.plugins.simplismart import TTS

tts = TTS()  # Uses default Orpheus model
tts = TTS(model="canopylabs/orpheus-3b-0.1-ft", voice="tara")

Qwen 3 TTS

from livekit.plugins.simplismart import TTS, QwenTTSOptions

tts = TTS(
    model="qwen-tts",
    voice="Chelsie",
    base_url="https://api.simplismart.live/v1/audio/speech",
    options=QwenTTSOptions(language="English", leading_silence=True)
)

Files Changed

  • livekit-plugins/livekit-plugins-simplismart/livekit/plugins/simplismart/__init__.py
  • livekit-plugins/livekit-plugins-simplismart/livekit/plugins/simplismart/models.py
  • livekit-plugins/livekit-plugins-simplismart/livekit/plugins/simplismart/tts.py

devin-ai-integration[bot]

This comment was marked as resolved.

@simplipratik simplipratik force-pushed the integration/qwen3-tts branch 2 times, most recently from e2ff8c2 to 0228713 Compare April 17, 2026 13:38
@simplipratik simplipratik changed the title Add Qwen 3 TTS support with backwards compatibility Add Qwen 3 TTS support for Simplismart-livekit plugin Apr 17, 2026
if options is None:
self._opts = SimplismartTTSOptions()
is_qwen = False
elif isinstance(options, QwenTTSOptions):
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.

Setting model="qwen-tts" or base_url=QWEN_BASE_URL without options=QwenTTSOptions(...) sends Orpheus-format JSON to the Qwen endpoint. Is there a better way we can approach the is_qwen check?

Comment thread livekit-plugins/livekit-plugins-simplismart/livekit/plugins/simplismart/tts.py Outdated
@simplipratik simplipratik force-pushed the integration/qwen3-tts branch from 0228713 to 8c1a0ba Compare April 20, 2026 12:36
# sample_rate controls how the framework decodes/plays back the returned PCM audio;
# it is not sent to the server.
sample_rate: int = 24000,
options: SimplismartTTSOptions | QwenTTSOptions | None = None,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

i would unpack the params in these options and avoid exposing the options object here, ideally the user wouldn't have to import anything to pass any parameters. i think we can also keep the defaults here for clarity

i recommend following the pattern rime has here: https://github.com/livekit/agents/blob/main/livekit-plugins/livekit-plugins-rime/livekit/plugins/rime/tts.py

@simplipratik simplipratik force-pushed the integration/qwen3-tts branch from 8c1a0ba to e57bdd2 Compare April 21, 2026 11:13
if self._opts.qwen_options is not None:
qwen_opts = self._opts.qwen_options
payload: dict = {
"text": self._input_text,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
"text": self._input_text,
"model": self._opts.model,
"text": self._input_text,

i got this error when trying qwen:

livekit.agents._exceptions.APIStatusError: message='Simplismart TTS API Error: {"error":"Missing required field: model"}', status_code=400, 
retryable=False, body={"error":"Missing required field: model"}

"Accept": "audio/L16",
}
else:
assert self._opts.simplismart_options is not None
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we can remove this line, simplismart_options will always be set in this else from the init

Suggested change
assert self._opts.simplismart_options is not None

@simplipratik simplipratik force-pushed the integration/qwen3-tts branch from f281b86 to e97c4ae Compare April 21, 2026 18:36
"model": self._opts.model,
"text": self._input_text,
"language": qwen_opts.language,
"speaker": self._opts.voice,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
"speaker": self._opts.voice,
"voice": self._opts.voice,

- Add `qwen-tts` to `TTSModels`
- Add `_SimplismartTTSOptions` and `_QwenTTSOptions` private dataclasses following the rime plugin pattern (flat params, no public Options objects)
- Auto-detect `base_url`, `model`, and `voice` from model name via `_is_qwen_model()`
- Defaults set for Orpheus model; Qwen 3 defaults auto-applied when model name contains `qwen`
- All verbose logging changed to `logger.debug`
- `sample_rate` documented as framework-only, not sent to server
- Backwards compatible: existing `TTS()` usage unchanged
- Add `model` field to Qwen payload (fixes `Missing required field: model` error)

Made-with: Cursor
@simplipratik simplipratik force-pushed the integration/qwen3-tts branch from e97c4ae to 09030ab Compare April 21, 2026 20:02
Copy link
Copy Markdown
Member

@tinalenguyen tinalenguyen left a comment

Choose a reason for hiding this comment

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

lgtm, thank you!

@tinalenguyen tinalenguyen merged commit 6b35678 into livekit:main Apr 21, 2026
15 checks passed
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.

3 participants