Go: implement TTS for MiniMax provider and CLI testing for TTS (#14911)

### What problem does this PR solve?

This PR implement TTS for MiniMax provider and CLI testing for TTS

**The following functionalities are now supported:**

**MiniMax:**
- [x] Chat / Stream Chat 
- [x] Embedding
- [x] Rerank
- [x] Model listing
- [x] Provider connection checking
- [x] Text To Speech
- [ ] OCRFile
- [ ] ~~Audio To Text~~
- [ ] ~~Balance~~

**Verified examples from the CLI:**

```plaintext
RAGFlow(user)> tts with 'speech-2.8-hd@test@minimax' text 'He who desires but acts not, breeds pestilence.' play format 'wav' save './internal' param '{"voice_setting": {"voice_id": "English_radiant_girl", "speed": 1, "vol": 1, "pitch": 0}, "audio_setting": {"sample_rate": 32000, "bitrate": 128000, "format": "wav", "channel": 1}, "output_format": "hex"}'
Saved to directory: /home/infiniflow/Documents/development/ragflow/internal/speech-2.8-hd_output.wav
SUCCESS

RAGFlow(user)> stream tts with 'speech-2.8-hd@test@minimax' text 'He who desires but acts not, breeds pestilence.' play format 'wav' save './internal' param '{"voice_setting": {"voice_id": "English_radiant_girl", "speed": 1, "vol": 1, "pitch": 0}, "audio_setting": {"sample_rate": 32000, "bitrate": 128000, "format": "wav", "channel": 1}, "output_format": "hex"}'
Saved to directory: /home/infiniflow/Documents/development/ragflow/internal/speech-2.8-hd_output.wav
SUCCESS
```
Set `Play` to play audio in CLI
Set `Save` `PATH_TO_SAVE` to save file
Set `format` to save file in wav or mp3
Set `Param` align with official request body

### Type of change

- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
Haruko386
2026-05-14 13:19:31 +08:00
committed by GitHub
parent d46bbd30f7
commit ef46005ef1
10 changed files with 405 additions and 39 deletions

View File

@@ -2773,38 +2773,71 @@ func (p *Parser) parseASRCommand() (*Command, error) {
}
func (p *Parser) parseTTSCommand() (*Command, error) {
p.nextToken() // consume TTS
p.nextToken()
cmd := NewCommand("tts_user_command")
if p.curToken.Type != TokenWith {
return nil, fmt.Errorf("expected WITH after TTS")
return nil, fmt.Errorf("expect 'with' after tts")
}
p.nextToken() // consume WITH
p.nextToken()
compositeModelName, err := p.parseQuotedString()
if err != nil {
return nil, err
if p.curToken.Type != TokenQuotedString && p.curToken.Type != TokenIdentifier {
return nil, fmt.Errorf("expect model name after 'with'")
}
cmd.Params["composite_model_name"] = strings.Trim(p.curToken.Value, "\"'")
p.nextToken()
if p.curToken.Type != TokenText {
return nil, fmt.Errorf("expected TEXT to TTS")
}
p.nextToken() // consume FILE
text, err := p.parseQuotedString()
if err != nil {
return nil, err
return nil, fmt.Errorf("expect 'text' parameter")
}
p.nextToken()
// Semicolon is optional for UNSET TOKEN
if p.curToken.Type != TokenQuotedString {
return nil, fmt.Errorf("expect quoted string after 'text'")
}
cmd.Params["text"] = strings.Trim(p.curToken.Value, "\"'")
p.nextToken()
for p.curToken.Type != TokenEOF && p.curToken.Type != TokenSemicolon {
switch p.curToken.Type {
case TokenPlay:
p.nextToken()
cmd.Params["play"] = true
case TokenParam:
p.nextToken()
if p.curToken.Type != TokenQuotedString {
return nil, fmt.Errorf("expect quoted string after 'param'")
}
cmd.Params["param_str"] = strings.Trim(p.curToken.Value, "\"'")
p.nextToken()
p.nextToken()
case TokenSave:
p.nextToken()
if p.curToken.Type != TokenQuotedString && p.curToken.Type != TokenIdentifier {
return nil, fmt.Errorf("expect directory path after 'save'")
}
cmd.Params["save"] = true
cmd.Params["save_path"] = strings.Trim(p.curToken.Value, "\"'")
p.nextToken()
case TokenFormat:
p.nextToken()
if p.curToken.Type != TokenQuotedString && p.curToken.Type != TokenIdentifier {
return nil, fmt.Errorf("expect format string (e.g. 'wav') after 'format'")
}
cmd.Params["format"] = strings.Trim(p.curToken.Value, "\"'")
p.nextToken()
default:
return nil, fmt.Errorf("unexpected token: %s", p.curToken.Value)
}
}
if p.curToken.Type == TokenSemicolon {
p.nextToken()
}
cmd := NewCommand("tts_user_command")
cmd.Params["composite_model_name"] = compositeModelName
cmd.Params["text"] = text
return cmd, nil
}