Go: add ASR, TTS, OCR command (#14836)

### What problem does this PR solve?

```
RAGFlow(user)> asr with 'glm-asr-2512@test@zhipu-ai' audio './speech.wav';
CLI error: zhipu, no such method
RAGFlow(user)> stream asr with 'glm-asr-2512@test@zhipu-ai' audio './speech.wav';
CLI error: zhipu, no such method

RAGFlow(user)> tts with 'glm-tts@test@zhipu-ai' text 'how are you';
CLI error: zhipu, no such method

RAGFlow(user)> stream tts with 'glm-tts@test@zhipu-ai' text 'how are you';
CLI error: zhipu, no such method

RAGFlow(user)> ocr with 'glm-ocr@test@zhipu-ai' file './test.log';
CLI error: zhipu, no such method
```

### Type of change

- [x] New Feature (non-breaking change which adds functionality)

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
This commit is contained in:
Jin Hai
2026-05-12 17:17:44 +08:00
committed by GitHub
parent 9ee481807f
commit d08bf02d9b
32 changed files with 1869 additions and 71 deletions

View File

@@ -2587,16 +2587,29 @@ func (p *Parser) parseStreamCommand() (*Command, error) {
var command *Command
var err error
if p.curToken.Type == TokenChat {
switch p.curToken.Type {
case TokenChat:
command, err = p.parseChatCommand()
if err != nil {
return nil, err
}
} else if p.curToken.Type == TokenThink {
case TokenThink:
command, err = p.parseThinkCommand()
if err != nil {
return nil, err
}
case TokenASR:
command, err = p.parseASRCommand()
if err != nil {
return nil, err
}
case TokenTTS:
command, err = p.parseTTSCommand()
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("expected CHAT, THINK, ASR, or TTS after STREAM")
}
command.Params["stream"] = true
@@ -2723,6 +2736,109 @@ documentLoop:
return cmd, nil
}
func (p *Parser) parseASRCommand() (*Command, error) {
p.nextToken() // consume ASR
if p.curToken.Type != TokenWith {
return nil, fmt.Errorf("expected WITH after ASR")
}
p.nextToken() // consume WITH
compositeModelName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
if p.curToken.Type != TokenAudio {
return nil, fmt.Errorf("expected AUDIO to ASR")
}
p.nextToken() // consume FILE
audioFile, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
// Semicolon is optional for UNSET TOKEN
if p.curToken.Type == TokenSemicolon {
p.nextToken()
}
cmd := NewCommand("asr_user_command")
cmd.Params["composite_model_name"] = compositeModelName
cmd.Params["audio_file"] = audioFile
return cmd, nil
}
func (p *Parser) parseTTSCommand() (*Command, error) {
p.nextToken() // consume TTS
if p.curToken.Type != TokenWith {
return nil, fmt.Errorf("expected WITH after TTS")
}
p.nextToken() // consume WITH
compositeModelName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
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
}
p.nextToken()
// Semicolon is optional for UNSET TOKEN
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
}
func (p *Parser) parseOCRCommand() (*Command, error) {
p.nextToken() // consume OCR
if p.curToken.Type != TokenWith {
return nil, fmt.Errorf("expected WITH after OCR")
}
p.nextToken() // consume WITH
compositeModelName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
if p.curToken.Type != TokenFile {
return nil, fmt.Errorf("expected FILE to OCR")
}
p.nextToken() // consume FILE
file, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
cmd := NewCommand("ocr_user_command")
cmd.Params["composite_model_name"] = compositeModelName
cmd.Params["file"] = file
return cmd, nil
}
func (p *Parser) parseCheckCommand() (*Command, error) {
p.nextToken() // consume CHECK