mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-14 17:08:31 +08:00
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:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user