Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
//
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package handler
import (
2026-05-28 23:15:01 -03:00
"errors"
2026-04-03 18:11:23 +08:00
"fmt"
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
"net/http"
"ragflow/internal/common"
"ragflow/internal/dao"
2026-04-03 18:11:23 +08:00
"ragflow/internal/entity/models"
2026-03-31 18:42:12 +08:00
"ragflow/internal/service"
"strings"
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
"github.com/gin-gonic/gin"
)
2026-03-31 18:42:12 +08:00
// ProviderHandler provider handler
type ProviderHandler struct {
2026-04-02 20:20:35 +08:00
userService * service . UserService
modelProviderService * service . ModelProviderService
userTenantDAO * dao . UserTenantDAO
2026-03-31 18:42:12 +08:00
}
// NewProviderHandler create provider handler
2026-04-02 20:20:35 +08:00
func NewProviderHandler ( userService * service . UserService , modelProviderService * service . ModelProviderService ) * ProviderHandler {
2026-03-31 18:42:12 +08:00
return & ProviderHandler {
2026-04-02 20:20:35 +08:00
userService : userService ,
modelProviderService : modelProviderService ,
userTenantDAO : dao . NewUserTenantDAO ( ) ,
2026-03-31 18:42:12 +08:00
}
}
func ( h * ProviderHandler ) ListProviders ( c * gin . Context ) {
keywords := ""
if queryKeywords := c . Query ( "available" ) ; queryKeywords != "" {
keywords = queryKeywords
}
// convert keywords to small case
keywords = strings . ToLower ( keywords )
if keywords == "true" {
// list pool providers
providers , err := dao . GetModelProviderManager ( ) . ListProviders ( )
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeNotFound , err . Error ( ) )
2026-03-31 18:42:12 +08:00
return
}
2026-04-02 20:20:35 +08:00
for _ , provider := range providers {
delete ( provider , "url_suffix" )
delete ( provider , "tags" )
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , providers , "success" )
2026-04-02 20:20:35 +08:00
return
}
userID := c . GetString ( "user_id" )
// list tenant providers
providers , errorCode , err := h . modelProviderService . ListProvidersOfTenant ( userID )
if err != nil {
2026-07-06 18:14:05 +08:00
common . ResponseWithCodeData ( c , errorCode , nil , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , providers , "success" )
2026-04-02 20:20:35 +08:00
return
}
type AddProviderRequest struct {
ProviderName string ` json:"provider_name" binding:"required" `
}
func ( h * ProviderHandler ) AddProvider ( c * gin . Context ) {
var req AddProviderRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
2026-07-06 18:14:05 +08:00
common . ResponseWithCodeData ( c , common . CodeBadRequest , false , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
}
2026-04-02 20:20:35 +08:00
userID := c . GetString ( "user_id" )
errorCode , err := h . modelProviderService . AddModelProvider ( req . ProviderName , userID )
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithMessage ( c , "success" )
2026-04-02 20:20:35 +08:00
}
func ( h * ProviderHandler ) DeleteProvider ( c * gin . Context ) {
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-04-02 20:20:35 +08:00
return
}
userID := c . GetString ( "user_id" )
2026-06-23 10:26:31 +08:00
errorCode , err := h . modelProviderService . DeleteModelProvider ( userID , providerName )
2026-04-02 20:20:35 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithMessage ( c , "success" )
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
}
2026-03-31 18:42:12 +08:00
func ( h * ProviderHandler ) ShowProvider ( c * gin . Context ) {
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
return
}
provider , err := dao . GetModelProviderManager ( ) . GetProviderByName ( providerName )
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeNotFound , err . Error ( ) )
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , provider , "success" )
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
}
2026-03-31 18:42:12 +08:00
func ( h * ProviderHandler ) ListModels ( c * gin . Context ) {
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
return
}
2026-04-20 15:31:12 +08:00
providerModels , err := dao . GetModelProviderManager ( ) . ListModels ( providerName )
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeNotFound , err . Error ( ) )
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , providerModels , "success" )
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
}
2026-03-31 18:42:12 +08:00
func ( h * ProviderHandler ) ShowModel ( c * gin . Context ) {
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
return
}
modelName := c . Param ( "model_name" )
if modelName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model name is required" )
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
return
}
model , err := dao . GetModelProviderManager ( ) . GetModelByName ( providerName , modelName )
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeNotFound , err . Error ( ) )
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , model , "success" )
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
}
2026-04-02 20:20:35 +08:00
type CreateProviderInstanceRequest struct {
2026-07-13 11:20:02 +08:00
InstanceName string ` json:"instance_name" binding:"required" `
APIKey string ` json:"api_key" `
BaseURL string ` json:"base_url" `
Region string ` json:"region" `
ModelInfo [ ] service . CreateInstanceModelInfo ` json:"model_info" `
2026-04-02 20:20:35 +08:00
}
func ( h * ProviderHandler ) CreateProviderInstance ( c * gin . Context ) {
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-04-02 20:20:35 +08:00
return
}
var req CreateProviderInstanceRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeBadRequest , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
userID := c . GetString ( "user_id" )
2026-07-13 11:20:02 +08:00
// If the request body only contains "instance_name", create a name-only
// instance without API key validation or model creation.
// Mirrors Python's provider_api.py:349 — set(data.keys()) == {"instance_name"}.
if req . APIKey == "" && req . BaseURL == "" && req . Region == "" && len ( req . ModelInfo ) == 0 {
code , err := h . modelProviderService . CreateNameOnlyProviderInstance ( providerName , req . InstanceName , userID )
if err != nil {
common . ErrorWithCode ( c , code , err . Error ( ) )
return
}
common . SuccessWithMessage ( c , "success" )
return
}
_ , err := h . modelProviderService . CreateProviderInstance ( providerName , req . InstanceName , req . APIKey , req . BaseURL , req . Region , userID , req . ModelInfo )
2026-04-02 20:20:35 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeServerError , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithMessage ( c , "success" )
2026-04-02 20:20:35 +08:00
}
func ( h * ProviderHandler ) ListProviderInstances ( c * gin . Context ) {
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-04-02 20:20:35 +08:00
return
}
userID := c . GetString ( "user_id" )
instances , errorCode , err := h . modelProviderService . ListProviderInstances ( providerName , userID )
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , instances , "success" )
2026-04-02 20:20:35 +08:00
}
func ( h * ProviderHandler ) ShowProviderInstance ( c * gin . Context ) {
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-04-02 20:20:35 +08:00
return
}
2026-07-14 21:06:11 +08:00
instanceIDOrName := c . Param ( "instance_name" )
if instanceIDOrName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-04-02 20:20:35 +08:00
return
}
userID := c . GetString ( "user_id" )
2026-07-14 21:06:11 +08:00
instance , errorCode , err := h . modelProviderService . ShowProviderInstance ( providerName , instanceIDOrName , userID )
2026-04-02 20:20:35 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , instance , "success" )
2026-04-02 20:20:35 +08:00
}
2026-04-21 21:31:50 +08:00
func ( h * ProviderHandler ) ShowInstanceBalance ( c * gin . Context ) {
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-04-21 21:31:50 +08:00
return
}
instanceName := c . Param ( "instance_name" )
if instanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-04-21 21:31:50 +08:00
return
}
userID := c . GetString ( "user_id" )
// Get tenant ID from user
balance , errorCode , err := h . modelProviderService . ShowInstanceBalance ( providerName , instanceName , userID )
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-04-21 21:31:50 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , balance , "success" )
2026-04-21 21:31:50 +08:00
}
2026-06-02 19:32:41 +08:00
func ( h * ProviderHandler ) CheckConnection ( c * gin . Context ) {
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-06-02 19:32:41 +08:00
return
}
var req service . CheckConnectionRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , err . Error ( ) )
2026-06-02 19:32:41 +08:00
return
}
userID := c . GetString ( "user_id" )
errCode , err := h . modelProviderService . CheckConnection ( providerName , req . APIKey , req . Region , req . BaseURL , userID )
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errCode , err . Error ( ) )
2026-06-02 19:32:41 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithMessage ( c , "success" )
2026-06-02 19:32:41 +08:00
}
func ( h * ProviderHandler ) CheckInstanceConnection ( c * gin . Context ) {
2026-04-23 10:16:20 +08:00
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-04-23 10:16:20 +08:00
return
}
instanceName := c . Param ( "instance_name" )
if instanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-04-23 10:16:20 +08:00
return
}
userID := c . GetString ( "user_id" )
2026-06-02 19:32:41 +08:00
instanceInfo , code , err := h . modelProviderService . ShowProviderInstance ( providerName , instanceName , userID )
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , code , err . Error ( ) )
2026-06-02 19:32:41 +08:00
return
}
2026-06-18 14:19:46 +08:00
apikey , _ := instanceInfo [ "api_key" ] . ( string )
2026-06-02 19:32:41 +08:00
region , _ := instanceInfo [ "region" ] . ( string )
baseURL , _ := instanceInfo [ "base_url" ] . ( string )
2026-04-23 10:16:20 +08:00
// Get tenant ID from user
2026-06-02 19:32:41 +08:00
errorCode , err := h . modelProviderService . CheckConnection ( providerName , apikey , region , baseURL , userID )
2026-04-23 10:16:20 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-04-23 10:16:20 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithMessage ( c , "success" )
2026-04-23 10:16:20 +08:00
}
2026-05-15 12:29:52 +08:00
func ( h * ProviderHandler ) ListTasks ( c * gin . Context ) {
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-05-15 12:29:52 +08:00
return
}
instanceName := c . Param ( "instance_name" )
if instanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-05-15 12:29:52 +08:00
return
}
userID := c . GetString ( "user_id" )
// Get tenant ID from user
listTaskResponse , errorCode , err := h . modelProviderService . ListTasks ( providerName , instanceName , userID )
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-05-15 12:29:52 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , listTaskResponse , "success" )
2026-05-15 12:29:52 +08:00
}
func ( h * ProviderHandler ) ShowTask ( c * gin . Context ) {
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-05-15 12:29:52 +08:00
return
}
instanceName := c . Param ( "instance_name" )
if instanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-05-15 12:29:52 +08:00
return
}
taskID := c . Param ( "task_id" )
if taskID == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Task ID is required" )
2026-05-15 12:29:52 +08:00
return
}
userID := c . GetString ( "user_id" )
// Get tenant ID from user
taskResponse , errorCode , err := h . modelProviderService . ShowTask ( providerName , instanceName , taskID , userID )
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-05-15 12:29:52 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , taskResponse , "success" )
2026-05-15 12:29:52 +08:00
}
2026-04-02 20:20:35 +08:00
type AlterProviderInstanceRequest struct {
2026-07-13 11:20:02 +08:00
InstanceName string ` json:"instance_name" `
APIKey string ` json:"api_key" `
BaseURL string ` json:"base_url" `
Region string ` json:"region" `
ModelInfo [ ] service . CreateInstanceModelInfo ` json:"model_info" `
Verify * bool ` json:"verify" `
2026-04-02 20:20:35 +08:00
}
func ( h * ProviderHandler ) AlterProviderInstance ( c * gin . Context ) {
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-04-02 20:20:35 +08:00
return
}
instanceName := c . Param ( "instance_name" )
if instanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-04-02 20:20:35 +08:00
return
}
var req AlterProviderInstanceRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , common . CodeBadRequest , nil , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
userID := c . GetString ( "user_id" )
if userID == "" {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeUnauthorized , "Unauthorized" )
2026-04-02 20:20:35 +08:00
return
}
2026-07-13 11:20:02 +08:00
verify := true
if req . Verify != nil {
verify = * req . Verify
}
code , err := h . modelProviderService . AlterProviderInstance ( userID , providerName , instanceName , req . InstanceName , req . APIKey , req . BaseURL , req . Region , req . ModelInfo , verify )
2026-06-23 16:57:05 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , code , err . Error ( ) )
2026-06-23 16:57:05 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithMessage ( c , "success" )
2026-04-02 20:20:35 +08:00
}
2026-04-17 09:55:25 +08:00
type DropProviderInstanceRequest struct {
Instances [ ] string ` json:"instances" binding:"required" `
}
2026-04-02 20:20:35 +08:00
func ( h * ProviderHandler ) DropProviderInstance ( c * gin . Context ) {
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-04-02 20:20:35 +08:00
return
}
2026-04-17 09:55:25 +08:00
var req DropProviderInstanceRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeBadRequest , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
userID := c . GetString ( "user_id" )
2026-06-18 14:19:46 +08:00
code , err := h . modelProviderService . DropProviderInstances ( providerName , userID , req . Instances )
2026-04-02 20:20:35 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , code , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithMessage ( c , "success" )
2026-04-02 20:20:35 +08:00
}
func ( h * ProviderHandler ) ListInstanceModels ( c * gin . Context ) {
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-04-02 20:20:35 +08:00
return
}
instanceName := c . Param ( "instance_name" )
if instanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-04-02 20:20:35 +08:00
return
}
2026-04-21 16:52:32 +08:00
keywords := ""
if queryKeywords := c . Query ( "supported" ) ; queryKeywords != "" {
keywords = queryKeywords
}
// convert keywords to small case
keywords = strings . ToLower ( keywords )
if keywords == "true" {
// list supported models
modelList , err := h . modelProviderService . ListSupportedModels ( providerName , instanceName , c . GetString ( "user_id" ) )
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeServerError , err . Error ( ) )
2026-04-21 16:52:32 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , modelList , "success" )
2026-04-21 16:52:32 +08:00
return
}
2026-04-20 15:31:12 +08:00
modelInstances , err := h . modelProviderService . ListInstanceModels ( providerName , instanceName , c . GetString ( "user_id" ) )
2026-04-02 20:20:35 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeNotFound , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , modelInstances , "success" )
2026-04-02 20:20:35 +08:00
}
2026-07-14 21:06:11 +08:00
type AlterModelRequest struct {
ModelID string ` json:"model_id" `
Status string ` json:"status" `
MaxTokens int ` json:"max_tokens" `
ModelType interface { } ` json:"model_type" `
Extra interface { } ` json:"extra" `
2026-04-02 20:20:35 +08:00
}
2026-07-14 21:06:11 +08:00
func ( h * ProviderHandler ) AlterModel ( c * gin . Context ) {
2026-04-02 20:20:35 +08:00
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-04-02 20:20:35 +08:00
return
}
instanceName := c . Param ( "instance_name" )
if instanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-04-02 20:20:35 +08:00
return
}
2026-07-14 21:06:11 +08:00
var req AlterModelRequest
2026-04-02 20:20:35 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeBadRequest , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
userID := c . GetString ( "user_id" )
2026-06-18 17:56:51 +08:00
modelName := strings . TrimPrefix ( c . Param ( "model_name" ) , "/" )
modelName = strings . TrimSpace ( modelName )
2026-07-14 21:06:11 +08:00
modelID := strings . TrimSpace ( req . ModelID )
2026-06-18 17:56:51 +08:00
if modelName == "" && modelID == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , common . CodeBadRequest , nil , "model_name or model_id is required" )
2026-06-18 17:56:51 +08:00
return
}
2026-04-02 20:20:35 +08:00
2026-06-18 17:56:51 +08:00
status := strings . TrimSpace ( req . Status )
2026-07-14 21:06:11 +08:00
if status != "" && status != "active" && status != "inactive" {
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , common . CodeBadRequest , nil , "status must be 'active' or 'inactive'" )
2026-06-18 17:56:51 +08:00
return
}
2026-07-14 21:06:11 +08:00
updateDict := make ( map [ string ] interface { } )
if status != "" {
updateDict [ "status" ] = status
}
if req . MaxTokens > 0 {
updateDict [ "max_tokens" ] = req . MaxTokens
}
if req . ModelType != nil {
updateDict [ "model_type" ] = req . ModelType
}
if req . Extra != nil {
updateDict [ "extra" ] = req . Extra
}
2026-07-15 15:44:08 +08:00
if len ( updateDict ) == 0 {
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , common . CodeBadRequest , nil , "at least one update field is required besides model_name or model_id" )
return
}
2026-07-14 21:06:11 +08:00
code , err := h . modelProviderService . AlterModel ( providerName , instanceName , modelName , userID , modelID , updateDict )
2026-04-02 20:20:35 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , code , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithMessage ( c , "success" )
2026-04-02 20:20:35 +08:00
}
2026-06-03 15:26:46 +08:00
func prepareProviderInstance ( providerName , instanceName , reqProviderName , reqInstanceName string ) error {
2026-05-28 23:15:01 -03:00
if providerName == "" {
return errors . New ( "Provider name is required" )
2026-04-29 17:05:08 +08:00
}
2026-05-28 23:15:01 -03:00
if instanceName == "" {
return errors . New ( "Instance name is required" )
2026-04-29 17:05:08 +08:00
}
2026-06-03 15:26:46 +08:00
if reqProviderName != "" && ! strings . EqualFold ( reqProviderName , providerName ) {
2026-05-28 23:15:01 -03:00
return errors . New ( "Provider name does not match path" )
}
2026-06-03 15:26:46 +08:00
if reqInstanceName != "" && ! strings . EqualFold ( reqInstanceName , instanceName ) {
2026-05-28 23:15:01 -03:00
return errors . New ( "Instance name does not match path" )
2026-04-29 17:05:08 +08:00
}
2026-06-03 15:26:46 +08:00
return nil
}
func ( h * ProviderHandler ) AddModel ( c * gin . Context ) {
var req service . AddModelRequest
2026-05-28 23:15:01 -03:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
println ( "JSON bind error: %v (type: %T)" , err , err )
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , common . CodeBadRequest , nil , err . Error ( ) )
2026-04-29 17:05:08 +08:00
return
}
2026-07-14 21:06:11 +08:00
req . ProviderName = c . Param ( "provider_name" )
req . InstanceName = c . Param ( "instance_name" )
if req . ProviderName == "" || req . InstanceName == "" {
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , common . CodeBadRequest , nil , "provider_name and instance_name are required" )
return
}
if req . ModelName == "" {
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , common . CodeBadRequest , nil , "model_name is required" )
return
}
if len ( req . ModelTypes ) == 0 {
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , common . CodeBadRequest , nil , "model_type is required" )
2026-04-29 17:05:08 +08:00
return
}
userID := c . GetString ( "user_id" )
2026-06-03 15:26:46 +08:00
code , err := h . modelProviderService . AddModel ( & req , userID )
2026-04-29 17:05:08 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , code , err . Error ( ) )
2026-04-29 17:05:08 +08:00
return
}
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , code , "success" )
2026-04-29 17:05:08 +08:00
}
2026-04-29 19:18:49 +08:00
type DropInstanceModelRequest struct {
2026-07-14 21:06:11 +08:00
ModelNames [ ] string ` json:"model_name" `
2026-04-29 19:18:49 +08:00
}
func ( h * ProviderHandler ) DropInstanceModels ( c * gin . Context ) {
providerName := c . Param ( "provider_name" )
if providerName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-04-29 19:18:49 +08:00
return
}
instanceName := c . Param ( "instance_name" )
if instanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-04-29 19:18:49 +08:00
return
}
var req DropInstanceModelRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeBadRequest , err . Error ( ) )
2026-04-29 19:18:49 +08:00
return
}
2026-07-14 21:06:11 +08:00
if len ( req . ModelNames ) == 0 {
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , common . CodeBadRequest , nil , "model_name is required" )
2026-06-18 17:56:51 +08:00
return
}
2026-04-29 19:18:49 +08:00
userID := c . GetString ( "user_id" )
2026-07-14 21:06:11 +08:00
code , err := h . modelProviderService . DropInstanceModels ( providerName , instanceName , userID , req . ModelNames )
2026-04-29 19:18:49 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , code , err . Error ( ) )
2026-04-29 19:18:49 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithMessage ( c , "success" )
2026-04-29 19:18:49 +08:00
}
2026-04-02 20:20:35 +08:00
type ChatToModelRequest struct {
2026-04-30 15:25:01 +08:00
ProviderName * string ` json:"provider_name" `
InstanceName * string ` json:"instance_name" `
ModelName * string ` json:"model_name" `
2026-06-15 10:10:14 +08:00
ModelID * string ` json:"model_id" `
2026-04-30 15:25:01 +08:00
Messages [ ] map [ string ] interface { } ` json:"messages" `
Stream bool ` json:"stream" `
Thinking bool ` json:"thinking" `
Effort * string ` json:"effort" `
Verbosity * string ` json:"verbosity" `
2026-04-02 20:20:35 +08:00
}
func ( h * ProviderHandler ) ChatToModel ( c * gin . Context ) {
2026-04-29 11:45:06 +08:00
var req ChatToModelRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
println ( "JSON bind error: %v (type: %T)" , err , err )
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeBadRequest , err . Error ( ) )
2026-04-29 11:45:06 +08:00
return
}
2026-06-15 10:10:14 +08:00
if req . ModelID == nil {
if req . ProviderName == nil || * req . ProviderName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-04-02 20:20:35 +08:00
2026-06-15 10:10:14 +08:00
if req . InstanceName == nil || * req . InstanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-04-02 20:20:35 +08:00
2026-06-15 10:10:14 +08:00
if req . ModelName == nil || * req . ModelName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model name is required" )
2026-06-15 10:10:14 +08:00
return
}
} else {
if * req . ModelID == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model ID is empty" )
2026-06-15 10:10:14 +08:00
return
}
2026-04-02 20:20:35 +08:00
}
userID := c . GetString ( "user_id" )
2026-04-24 20:59:30 +08:00
if ! req . Thinking {
req . Effort = nil
req . Verbosity = nil
}
apiConfig := models . APIConfig {
ApiKey : nil ,
Region : nil ,
}
chatConfig := models . ChatConfig {
Thinking : & req . Thinking ,
Stream : & req . Stream ,
2026-04-29 19:18:49 +08:00
Vision : nil ,
2026-04-24 20:59:30 +08:00
Stop : & [ ] string { } ,
DoSample : nil ,
MaxTokens : nil ,
Temperature : nil ,
TopP : nil ,
Effort : req . Effort ,
Verbosity : req . Verbosity ,
}
2026-04-03 18:11:23 +08:00
// Check if it's a stream request
if req . Stream {
// Set SSE headers
2026-06-12 09:49:34 -03:00
disableWriteDeadlineForSSE ( c )
2026-04-03 18:11:23 +08:00
c . Header ( "Content-Type" , "text/event-stream" )
c . Header ( "Cache-Control" , "no-cache" )
c . Header ( "Connection" , "keep-alive" )
c . Writer . WriteHeader ( http . StatusOK )
c . Writer . Flush ( )
// Create sender function that writes directly to response
sender := func ( content , reasoningContent * string ) error {
// Check for [DONE] marker (OpenAI compatible)
if content != nil {
if * content == "[DONE]" {
c . SSEvent ( "done" , "[DONE]" )
return nil
}
message := fmt . Sprintf ( "[MESSAGE]%s" , * content )
c . SSEvent ( "message" , message )
c . Writer . Flush ( )
}
if reasoningContent != nil {
message := fmt . Sprintf ( "[REASONING]%s" , * reasoningContent )
c . SSEvent ( "message" , message )
c . Writer . Flush ( )
}
//logger.Info(data)
return nil
}
2026-04-30 19:33:57 +08:00
// Convert []map[string]interface{} to []models.Message
messages := make ( [ ] models . Message , len ( req . Messages ) )
for i , msg := range req . Messages {
role , _ := msg [ "role" ] . ( string )
content := msg [ "content" ]
messages [ i ] = models . Message { Role : role , Content : content }
}
2026-06-15 10:10:14 +08:00
// Stream response using sender function (the best performance, no channel)
errorCode , err := h . modelProviderService . ChatToModelStreamWithSender ( req . ProviderName , req . InstanceName , req . ModelName , req . ModelID , userID , messages , & apiConfig , & chatConfig , sender )
2026-04-03 18:11:23 +08:00
if errorCode != common . CodeSuccess {
2026-04-27 20:35:47 +08:00
c . SSEvent ( "error" , err . Error ( ) )
2026-04-03 18:11:23 +08:00
}
return
}
// Non-stream response
2026-04-30 15:25:01 +08:00
var response * models . ChatResponse
var errorCode common . ErrorCode
var err error
// Convert []map[string]interface{} to []models.Message
messages := make ( [ ] models . Message , len ( req . Messages ) )
for i , msg := range req . Messages {
role , _ := msg [ "role" ] . ( string )
content := msg [ "content" ]
messages [ i ] = models . Message { Role : role , Content : content }
}
2026-06-15 10:10:14 +08:00
response , errorCode , err = h . modelProviderService . ChatToModelWithMessages ( req . ProviderName , req . InstanceName , req . ModelName , req . ModelID , userID , messages , & apiConfig , & chatConfig )
2026-04-30 15:25:01 +08:00
2026-04-02 20:20:35 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-04-02 20:20:35 +08:00
return
}
c . JSON ( http . StatusOK , gin . H {
2026-04-21 16:52:32 +08:00
"code" : 0 ,
"reasoning_content" : response . ReasonContent ,
"answer" : response . Answer ,
2026-04-02 20:20:35 +08:00
} )
}
2026-05-09 17:41:54 +08:00
type EmbedTextRequest struct {
ProviderName * string ` json:"provider_name" `
InstanceName * string ` json:"instance_name" `
ModelName * string ` json:"model_name" `
2026-06-15 10:10:14 +08:00
ModelID * string ` json:"model_id" `
2026-05-09 17:41:54 +08:00
Texts [ ] string ` json:"texts" `
Dimension int ` json:"dimension" `
}
func ( h * ProviderHandler ) EmbedText ( c * gin . Context ) {
var req EmbedTextRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
println ( "JSON bind error: %v (type: %T)" , err , err )
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeBadRequest , err . Error ( ) )
2026-05-09 17:41:54 +08:00
return
}
2026-06-15 10:10:14 +08:00
if req . ModelID == nil {
if req . ProviderName == nil || * req . ProviderName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-09 17:41:54 +08:00
2026-06-15 10:10:14 +08:00
if req . InstanceName == nil || * req . InstanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-09 17:41:54 +08:00
2026-06-15 10:10:14 +08:00
if req . ModelName == nil || * req . ModelName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model name is required" )
2026-06-15 10:10:14 +08:00
return
}
} else {
if * req . ModelID == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model ID is empty" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-09 17:41:54 +08:00
}
userID := c . GetString ( "user_id" )
apiConfig := models . APIConfig {
ApiKey : nil ,
Region : nil ,
}
embeddingConfig := models . EmbeddingConfig {
Dimension : req . Dimension ,
}
// Non-stream response
2026-05-11 14:45:30 +08:00
var response [ ] models . EmbeddingData
2026-05-09 17:41:54 +08:00
var errorCode common . ErrorCode
var err error
2026-06-15 10:10:14 +08:00
response , errorCode , err = h . modelProviderService . EmbedText ( req . ProviderName , req . InstanceName , req . ModelName , req . ModelID , userID , req . Texts , & apiConfig , & embeddingConfig )
2026-05-09 17:41:54 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-05-09 17:41:54 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , response , "success" )
2026-05-09 17:41:54 +08:00
}
type RerankDocumentRequest struct {
ProviderName * string ` json:"provider_name" `
InstanceName * string ` json:"instance_name" `
ModelName * string ` json:"model_name" `
2026-06-15 10:10:14 +08:00
ModelID * string ` json:"model_id" `
2026-05-09 17:41:54 +08:00
Query string ` json:"query" `
Documents [ ] string ` json:"documents" `
TopN int ` json:"top_n" `
}
func ( h * ProviderHandler ) RerankDocument ( c * gin . Context ) {
var req RerankDocumentRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
println ( "JSON bind error: %v (type: %T)" , err , err )
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeBadRequest , err . Error ( ) )
2026-05-09 17:41:54 +08:00
return
}
2026-06-15 10:10:14 +08:00
if req . ModelID == nil {
if req . ProviderName == nil || * req . ProviderName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-09 17:41:54 +08:00
2026-06-15 10:10:14 +08:00
if req . InstanceName == nil || * req . InstanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-09 17:41:54 +08:00
2026-06-15 10:10:14 +08:00
if req . ModelName == nil || * req . ModelName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model name is required" )
2026-06-15 10:10:14 +08:00
return
}
} else {
if * req . ModelID == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model ID is empty" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-09 17:41:54 +08:00
}
userID := c . GetString ( "user_id" )
apiConfig := models . APIConfig {
ApiKey : nil ,
Region : nil ,
}
rerankConfig := models . RerankConfig {
TopN : req . TopN ,
}
// Non-stream response
var response * models . RerankResponse
var errorCode common . ErrorCode
var err error
2026-06-15 10:10:14 +08:00
response , errorCode , err = h . modelProviderService . RerankDocument ( req . ProviderName , req . InstanceName , req . ModelName , req . ModelID , userID , req . Query , req . Documents , & apiConfig , & rerankConfig )
2026-05-09 17:41:54 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-05-09 17:41:54 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , response . Data , "success" )
2026-05-09 17:41:54 +08:00
}
2026-05-12 17:17:44 +08:00
type TranscribeAudioRequest struct {
Go: implement TTS for fishaudio, openrouter and asr for fishaudio (#14926)
### What problem does this PR solve?
This PR implement TTS for FishAudio and MiniMax provider and ASR for
FishAudio
**The following functionalities are now supported:**
**FishAudio:**
- [x] Text To Speech
- [x] Stream Text To Speech
- [x] Audio To Text
**OpenRouter:**
- [x] Text To Speech
**Verified examples from the CLI:**
```plaintext
**FishAudio**
RAGFlow(user)> tts with 's1@test@fishaudio' text 'He who desires but acts not, breeds pestilence.' play format 'wav' save './internal' param '{"reference_id": "90e65eaaf50e4470b8e6d43ee6afd7d5", "temperature": 0.7, "top_p": 0.7, "prosody": {"speed": 1, "volume": 0, "normalize_loudness": true}, "chunk_length": 300, "normalize": true, "sample_rate": 44100, "mp3_bitrate": 128, "latency": "normal", "max_new_tokens": 1024, "repetition_penalty": 1.2, "min_chunk_length": 50, "condition_on_previous_chunks": true, "early_stop_threshold": 1}'
Saved to directory: /home/infiniflow/Documents/development/ragflow/internal/s1_output.wav
SUCCESS
RAGFlow(user)> stream tts with 's1@test@fishaudio' text 'He who desires but acts not, breeds pestilence.' play format 'wav' save './internal' param '{"reference_id": "90e65eaaf50e4470b8e6d43ee6afd7d5", "temperature": 0.7, "top_p": 0.7, "prosody": {"speed": 1, "volume": 0, "normalize_loudness": true}, "chunk_length": 300, "normalize": true, "sample_rate": 44100, "mp3_bitrate": 128, "latency": "normal", "max_new_tokens": 1024, "repetition_penalty": 1.2, "min_chunk_length": 50, "condition_on_previous_chunks": true, "early_stop_threshold": 1}'
Saved to directory: /home/infiniflow/Documents/development/ragflow/internal/s1_output.wav
SUCCESS
RAGFlow(user)> asr with 'transcribe-1@test@fishaudio' audio './internal/test.wav' param '{"language": "en", "ignore_timestamps": true}'
+----------------------------------------------------------------------------------------------------------------------+
| text |
+----------------------------------------------------------------------------------------------------------------------+
| The examination and testimony of the experts enabled the commission to conclude that five shots may have been fired. |
+----------------------------------------------------------------------------------------------------------------------+
```
### Type of change
- [x] Bug Fix (non-breaking change which fixes an issue)
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
2026-05-14 18:58:00 +08:00
ProviderName * string ` json:"provider_name" `
InstanceName * string ` json:"instance_name" `
ModelName * string ` json:"model_name" `
2026-06-15 10:10:14 +08:00
ModelID * string ` json:"model_id" `
Go: implement TTS for fishaudio, openrouter and asr for fishaudio (#14926)
### What problem does this PR solve?
This PR implement TTS for FishAudio and MiniMax provider and ASR for
FishAudio
**The following functionalities are now supported:**
**FishAudio:**
- [x] Text To Speech
- [x] Stream Text To Speech
- [x] Audio To Text
**OpenRouter:**
- [x] Text To Speech
**Verified examples from the CLI:**
```plaintext
**FishAudio**
RAGFlow(user)> tts with 's1@test@fishaudio' text 'He who desires but acts not, breeds pestilence.' play format 'wav' save './internal' param '{"reference_id": "90e65eaaf50e4470b8e6d43ee6afd7d5", "temperature": 0.7, "top_p": 0.7, "prosody": {"speed": 1, "volume": 0, "normalize_loudness": true}, "chunk_length": 300, "normalize": true, "sample_rate": 44100, "mp3_bitrate": 128, "latency": "normal", "max_new_tokens": 1024, "repetition_penalty": 1.2, "min_chunk_length": 50, "condition_on_previous_chunks": true, "early_stop_threshold": 1}'
Saved to directory: /home/infiniflow/Documents/development/ragflow/internal/s1_output.wav
SUCCESS
RAGFlow(user)> stream tts with 's1@test@fishaudio' text 'He who desires but acts not, breeds pestilence.' play format 'wav' save './internal' param '{"reference_id": "90e65eaaf50e4470b8e6d43ee6afd7d5", "temperature": 0.7, "top_p": 0.7, "prosody": {"speed": 1, "volume": 0, "normalize_loudness": true}, "chunk_length": 300, "normalize": true, "sample_rate": 44100, "mp3_bitrate": 128, "latency": "normal", "max_new_tokens": 1024, "repetition_penalty": 1.2, "min_chunk_length": 50, "condition_on_previous_chunks": true, "early_stop_threshold": 1}'
Saved to directory: /home/infiniflow/Documents/development/ragflow/internal/s1_output.wav
SUCCESS
RAGFlow(user)> asr with 'transcribe-1@test@fishaudio' audio './internal/test.wav' param '{"language": "en", "ignore_timestamps": true}'
+----------------------------------------------------------------------------------------------------------------------+
| text |
+----------------------------------------------------------------------------------------------------------------------+
| The examination and testimony of the experts enabled the commission to conclude that five shots may have been fired. |
+----------------------------------------------------------------------------------------------------------------------+
```
### Type of change
- [x] Bug Fix (non-breaking change which fixes an issue)
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
2026-05-14 18:58:00 +08:00
File * string ` json:"file" `
Language [ ] string ` json:"language" `
Prompt int ` json:"prompt" `
Stream bool ` json:"stream" `
ASRConfig * models . ASRConfig ` json:"asr_config" `
2026-05-12 17:17:44 +08:00
}
func ( h * ProviderHandler ) TranscribeAudio ( c * gin . Context ) {
var req TranscribeAudioRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
println ( "JSON bind error: %v (type: %T)" , err , err )
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeBadRequest , err . Error ( ) )
2026-05-12 17:17:44 +08:00
return
}
2026-06-15 10:10:14 +08:00
if req . ModelID == nil {
if req . ProviderName == nil || * req . ProviderName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-12 17:17:44 +08:00
2026-06-15 10:10:14 +08:00
if req . InstanceName == nil || * req . InstanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-12 17:17:44 +08:00
2026-06-15 10:10:14 +08:00
if req . ModelName == nil || * req . ModelName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model name is required" )
2026-06-15 10:10:14 +08:00
return
}
} else {
if * req . ModelID == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model ID is empty" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-12 17:17:44 +08:00
}
userID := c . GetString ( "user_id" )
apiConfig := models . APIConfig {
ApiKey : nil ,
Region : nil ,
}
asrConfig := models . ASRConfig { }
Go: implement TTS for fishaudio, openrouter and asr for fishaudio (#14926)
### What problem does this PR solve?
This PR implement TTS for FishAudio and MiniMax provider and ASR for
FishAudio
**The following functionalities are now supported:**
**FishAudio:**
- [x] Text To Speech
- [x] Stream Text To Speech
- [x] Audio To Text
**OpenRouter:**
- [x] Text To Speech
**Verified examples from the CLI:**
```plaintext
**FishAudio**
RAGFlow(user)> tts with 's1@test@fishaudio' text 'He who desires but acts not, breeds pestilence.' play format 'wav' save './internal' param '{"reference_id": "90e65eaaf50e4470b8e6d43ee6afd7d5", "temperature": 0.7, "top_p": 0.7, "prosody": {"speed": 1, "volume": 0, "normalize_loudness": true}, "chunk_length": 300, "normalize": true, "sample_rate": 44100, "mp3_bitrate": 128, "latency": "normal", "max_new_tokens": 1024, "repetition_penalty": 1.2, "min_chunk_length": 50, "condition_on_previous_chunks": true, "early_stop_threshold": 1}'
Saved to directory: /home/infiniflow/Documents/development/ragflow/internal/s1_output.wav
SUCCESS
RAGFlow(user)> stream tts with 's1@test@fishaudio' text 'He who desires but acts not, breeds pestilence.' play format 'wav' save './internal' param '{"reference_id": "90e65eaaf50e4470b8e6d43ee6afd7d5", "temperature": 0.7, "top_p": 0.7, "prosody": {"speed": 1, "volume": 0, "normalize_loudness": true}, "chunk_length": 300, "normalize": true, "sample_rate": 44100, "mp3_bitrate": 128, "latency": "normal", "max_new_tokens": 1024, "repetition_penalty": 1.2, "min_chunk_length": 50, "condition_on_previous_chunks": true, "early_stop_threshold": 1}'
Saved to directory: /home/infiniflow/Documents/development/ragflow/internal/s1_output.wav
SUCCESS
RAGFlow(user)> asr with 'transcribe-1@test@fishaudio' audio './internal/test.wav' param '{"language": "en", "ignore_timestamps": true}'
+----------------------------------------------------------------------------------------------------------------------+
| text |
+----------------------------------------------------------------------------------------------------------------------+
| The examination and testimony of the experts enabled the commission to conclude that five shots may have been fired. |
+----------------------------------------------------------------------------------------------------------------------+
```
### Type of change
- [x] Bug Fix (non-breaking change which fixes an issue)
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
2026-05-14 18:58:00 +08:00
if req . ASRConfig != nil {
asrConfig = * req . ASRConfig
}
2026-05-12 17:17:44 +08:00
// Check if it's a stream request
if req . Stream {
// Set SSE headers
2026-06-12 09:49:34 -03:00
disableWriteDeadlineForSSE ( c )
2026-05-12 17:17:44 +08:00
c . Header ( "Content-Type" , "text/event-stream" )
c . Header ( "Cache-Control" , "no-cache" )
c . Header ( "Connection" , "keep-alive" )
c . Writer . WriteHeader ( http . StatusOK )
c . Writer . Flush ( )
// Create sender function that writes directly to response
sender := func ( content , reasoningContent * string ) error {
// Check for [DONE] marker (OpenAI compatible)
if content != nil {
if * content == "[DONE]" {
c . SSEvent ( "done" , "[DONE]" )
return nil
}
message := fmt . Sprintf ( "[MESSAGE]%s" , * content )
c . SSEvent ( "message" , message )
c . Writer . Flush ( )
}
if reasoningContent != nil {
message := fmt . Sprintf ( "[REASONING]%s" , * reasoningContent )
c . SSEvent ( "message" , message )
c . Writer . Flush ( )
}
//logger.Info(data)
return nil
}
2026-06-15 10:10:14 +08:00
// Stream response using sender function ( the best performance, no channel)
errorCode , err := h . modelProviderService . TranscribeAudioStream ( req . ProviderName , req . InstanceName , req . ModelName , req . ModelID , userID , req . File , & apiConfig , & asrConfig , sender )
2026-05-12 17:17:44 +08:00
if errorCode != common . CodeSuccess {
c . SSEvent ( "error" , err . Error ( ) )
}
return
}
// Non-stream response
var response * models . ASRResponse
var errorCode common . ErrorCode
var err error
2026-06-15 10:10:14 +08:00
response , errorCode , err = h . modelProviderService . TranscribeAudio ( req . ProviderName , req . InstanceName , req . ModelName , req . ModelID , userID , req . File , & apiConfig , & asrConfig )
2026-05-12 17:17:44 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-05-12 17:17:44 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , response , "success" )
2026-05-12 17:17:44 +08:00
}
type AudioSpeechRequest struct {
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)
2026-05-14 13:19:31 +08:00
ProviderName * string ` json:"provider_name" `
InstanceName * string ` json:"instance_name" `
ModelName * string ` json:"model_name" `
2026-06-15 10:10:14 +08:00
ModelID * string ` json:"model_id" `
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)
2026-05-14 13:19:31 +08:00
Text * string ` json:"text" `
Stream bool ` json:"stream" `
TTSConfig * models . TTSConfig ` json:"tts_config" `
2026-05-12 17:17:44 +08:00
}
func ( h * ProviderHandler ) AudioSpeech ( c * gin . Context ) {
var req AudioSpeechRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
println ( "JSON bind error: %v (type: %T)" , err , err )
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeBadRequest , err . Error ( ) )
2026-05-12 17:17:44 +08:00
return
}
2026-06-15 10:10:14 +08:00
if req . ModelID == nil {
if req . ProviderName == nil || * req . ProviderName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-12 17:17:44 +08:00
2026-06-15 10:10:14 +08:00
if req . InstanceName == nil || * req . InstanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-12 17:17:44 +08:00
2026-06-15 10:10:14 +08:00
if req . ModelName == nil || * req . ModelName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model name is required" )
2026-06-15 10:10:14 +08:00
return
}
} else {
if * req . ModelID == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model ID is empty" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-12 17:17:44 +08:00
}
userID := c . GetString ( "user_id" )
apiConfig := models . APIConfig {
ApiKey : nil ,
Region : nil ,
}
ttsConfig := models . TTSConfig { }
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)
2026-05-14 13:19:31 +08:00
if req . TTSConfig != nil {
ttsConfig = * req . TTSConfig
}
2026-05-12 17:17:44 +08:00
// Check if it's a stream request
if req . Stream {
// Set SSE headers
2026-06-12 09:49:34 -03:00
disableWriteDeadlineForSSE ( c )
2026-05-12 17:17:44 +08:00
c . Header ( "Content-Type" , "text/event-stream" )
c . Header ( "Cache-Control" , "no-cache" )
c . Header ( "Connection" , "keep-alive" )
c . Writer . WriteHeader ( http . StatusOK )
c . Writer . Flush ( )
// Create sender function that writes directly to response
sender := func ( content , reasoningContent * string ) error {
// Check for [DONE] marker (OpenAI compatible)
if content != nil {
if * content == "[DONE]" {
c . SSEvent ( "done" , "[DONE]" )
return nil
}
message := fmt . Sprintf ( "[MESSAGE]%s" , * content )
c . SSEvent ( "message" , message )
c . Writer . Flush ( )
}
if reasoningContent != nil {
message := fmt . Sprintf ( "[REASONING]%s" , * reasoningContent )
c . SSEvent ( "message" , message )
c . Writer . Flush ( )
}
//logger.Info(data)
return nil
}
2026-06-15 10:10:14 +08:00
// Stream response using sender function ( the best performance, no channel)
errorCode , err := h . modelProviderService . AudioSpeechStream ( req . ProviderName , req . InstanceName , req . ModelName , req . ModelID , userID , req . Text , & apiConfig , & ttsConfig , sender )
2026-05-12 17:17:44 +08:00
if errorCode != common . CodeSuccess {
c . SSEvent ( "error" , err . Error ( ) )
}
return
}
// Non-stream response
var response * models . TTSResponse
var errorCode common . ErrorCode
var err error
2026-06-15 10:10:14 +08:00
response , errorCode , err = h . modelProviderService . AudioSpeech ( req . ProviderName , req . InstanceName , req . ModelName , req . ModelID , userID , req . Text , & apiConfig , & ttsConfig )
2026-05-12 17:17:44 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-05-12 17:17:44 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , response , "success" )
2026-05-12 17:17:44 +08:00
}
type OCRFileRequest struct {
ProviderName * string ` json:"provider_name" `
InstanceName * string ` json:"instance_name" `
ModelName * string ` json:"model_name" `
2026-06-15 10:10:14 +08:00
ModelID * string ` json:"model_id" `
2026-05-13 17:29:53 +08:00
Content [ ] byte ` json:"content" `
URL * string ` json:"url" `
2026-05-12 17:17:44 +08:00
}
func ( h * ProviderHandler ) OCRFile ( c * gin . Context ) {
var req OCRFileRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
println ( "JSON bind error: %v (type: %T)" , err , err )
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeBadRequest , err . Error ( ) )
2026-05-12 17:17:44 +08:00
return
}
2026-06-15 10:10:14 +08:00
if req . ModelID == nil {
if req . ProviderName == nil || * req . ProviderName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-12 17:17:44 +08:00
2026-06-15 10:10:14 +08:00
if req . InstanceName == nil || * req . InstanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-12 17:17:44 +08:00
2026-06-15 10:10:14 +08:00
if req . ModelName == nil || * req . ModelName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model name is required" )
2026-06-15 10:10:14 +08:00
return
}
} else {
if * req . ModelID == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model ID is empty" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-12 17:17:44 +08:00
}
userID := c . GetString ( "user_id" )
apiConfig := models . APIConfig {
ApiKey : nil ,
Region : nil ,
}
OCRConfig := models . OCRConfig { }
// Non-stream response
2026-05-15 12:29:52 +08:00
var response * models . OCRFileResponse
2026-05-12 17:17:44 +08:00
var errorCode common . ErrorCode
var err error
2026-06-15 10:10:14 +08:00
response , errorCode , err = h . modelProviderService . OCRFile ( req . ProviderName , req . InstanceName , req . ModelName , req . ModelID , userID , req . Content , req . URL , & apiConfig , & OCRConfig )
2026-05-12 17:17:44 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-05-12 17:17:44 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , response , "success" )
2026-05-12 17:17:44 +08:00
}
2026-05-15 12:29:52 +08:00
type ParseFileRequest struct {
ProviderName * string ` json:"provider_name" `
InstanceName * string ` json:"instance_name" `
ModelName * string ` json:"model_name" `
2026-06-15 10:10:14 +08:00
ModelID * string ` json:"model_id" `
2026-05-15 12:29:52 +08:00
Content [ ] byte ` json:"content" `
URL * string ` json:"url" `
}
func ( h * ProviderHandler ) ParseFile ( c * gin . Context ) {
var req ParseFileRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
println ( "JSON bind error: %v (type: %T)" , err , err )
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , common . CodeBadRequest , err . Error ( ) )
2026-05-15 12:29:52 +08:00
return
}
2026-06-15 10:10:14 +08:00
if req . ModelID == nil {
if req . ProviderName == nil || * req . ProviderName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Provider name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-15 12:29:52 +08:00
2026-06-15 10:10:14 +08:00
if req . InstanceName == nil || * req . InstanceName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Instance name is required" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-15 12:29:52 +08:00
2026-06-15 10:10:14 +08:00
if req . ModelName == nil || * req . ModelName == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model name is required" )
2026-06-15 10:10:14 +08:00
return
}
} else {
if * req . ModelID == "" {
2026-07-06 18:14:05 +08:00
common . ResponseWithHttpCodeData ( c , http . StatusBadRequest , 400 , nil , "Model ID is empty" )
2026-06-15 10:10:14 +08:00
return
}
2026-05-15 12:29:52 +08:00
}
userID := c . GetString ( "user_id" )
apiConfig := models . APIConfig {
ApiKey : nil ,
Region : nil ,
}
parseFileConfig := models . ParseFileConfig { }
// Non-stream response
var response * models . ParseFileResponse
var errorCode common . ErrorCode
var err error
2026-06-15 10:10:14 +08:00
response , errorCode , err = h . modelProviderService . ParseFile ( req . ProviderName , req . InstanceName , req . ModelName , req . ModelID , userID , req . Content , req . URL , & apiConfig , & parseFileConfig )
2026-05-15 12:29:52 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , err . Error ( ) )
2026-05-15 12:29:52 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , response , "success" )
2026-05-15 12:29:52 +08:00
}
feat(agent): Go port — canvas engine, 22 components, DSL v2, 13 endpoints (#15952)
Ports the agent canvas subsystem from Python to Go.
## What's included
### Canvas Engine (Phase 0/1)
- State engine, scheduler, variable resolver, Redis checkpoint store,
cancel protocol
- **209 tests** across canvas / component / io packages
### 22 Components (P0–P4)
| Tier | Components |
|---|---|
| P0 T1+T2+T3 | LLM, Agent, ExitLoop, Switch, Categorize, Begin,
Message, Invoke |
| P1 T3 | VariableAggregator, VariableAssigner, StringTransform,
ListOperations, DataOperations |
| P2 T3 | Iteration, IterationItem, Loop, LoopItem |
| P3 T3 | UserFillUp, Fillup |
| P4 T5 | Browser, ExcelProcessor, DocsGenerator |
### DSL v2 Schema (Phase 2.5)
- Typed v2 in-memory model with v1-to-v2 auto-detect converter
- v1 legacy field stripping per plan §2.11.7
### HTTP Endpoints & Bug Fixes (Plans PR1–PR3)
- **DELETE SQL bug fix**: gorm v2 `Where("id = ?", id).Delete(...)`
pattern
- **CreateAgent validation**: title/DSL required, duplicate check, 103
envelope
- **13 new endpoints**: templates, prompts, tags, sessions CRUD,
chat/completions (SSE + non-stream stubs), rerun, test_db_connection,
logs, webhook/logs
- **756 Go unit tests** (745 → 756, +18)
- **17 → 0 Python integration test failures** (test_agents.py +
test_session_management/)
### Tools
21 eino tools: HTTPHelper, search tools, financial/data tools, mandatory
stubs
### Infrastructure
OTel observability, NATS message queue, DeepDoc gRPC client, SSRF
guards, IDOR mitigation
2026-06-12 22:58:28 +08:00
// ListTenantAddedModels is the response handler for GET /api/v1/models.
// It is the Go port of Python's
// api/apps/restful_apis/models_api.py:get_added_models and feeds
// web/src/hooks/use-llm-request.tsx → useFetchAllAddedModels. The data
// shape is the array form (one row per (provider × instance × llm) with
// model_type: string[]), matching the IAddedModel interface in
// web/src/interfaces/database/llm.ts:64-71.
//
// The previous contract routed this path to TenantHandler.GetModels →
// TenantService.ListTenantDefaultModels, which only enumerates the 6-7
// default tenant fields and returned `[]` for any tenant without
// defaults, breaking the front-end's "View Models" list. The Go port
// has no writers for tenant_model, so this endpoint must be driven by
// the factory catalog cross-referenced with the tenant's instance list —
// see service.ModelProviderService.ListTenantAddedModels.
func ( h * ProviderHandler ) ListTenantAddedModels ( c * gin . Context ) {
user , errorCode , errorMessage := GetUser ( c )
if errorCode != common . CodeSuccess {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , errorCode , errorMessage )
feat(agent): Go port — canvas engine, 22 components, DSL v2, 13 endpoints (#15952)
Ports the agent canvas subsystem from Python to Go.
## What's included
### Canvas Engine (Phase 0/1)
- State engine, scheduler, variable resolver, Redis checkpoint store,
cancel protocol
- **209 tests** across canvas / component / io packages
### 22 Components (P0–P4)
| Tier | Components |
|---|---|
| P0 T1+T2+T3 | LLM, Agent, ExitLoop, Switch, Categorize, Begin,
Message, Invoke |
| P1 T3 | VariableAggregator, VariableAssigner, StringTransform,
ListOperations, DataOperations |
| P2 T3 | Iteration, IterationItem, Loop, LoopItem |
| P3 T3 | UserFillUp, Fillup |
| P4 T5 | Browser, ExcelProcessor, DocsGenerator |
### DSL v2 Schema (Phase 2.5)
- Typed v2 in-memory model with v1-to-v2 auto-detect converter
- v1 legacy field stripping per plan §2.11.7
### HTTP Endpoints & Bug Fixes (Plans PR1–PR3)
- **DELETE SQL bug fix**: gorm v2 `Where("id = ?", id).Delete(...)`
pattern
- **CreateAgent validation**: title/DSL required, duplicate check, 103
envelope
- **13 new endpoints**: templates, prompts, tags, sessions CRUD,
chat/completions (SSE + non-stream stubs), rerun, test_db_connection,
logs, webhook/logs
- **756 Go unit tests** (745 → 756, +18)
- **17 → 0 Python integration test failures** (test_agents.py +
test_session_management/)
### Tools
21 eino tools: HTTPHelper, search tools, financial/data tools, mandatory
stubs
### Infrastructure
OTel observability, NATS message queue, DeepDoc gRPC client, SSRF
guards, IDOR mitigation
2026-06-12 22:58:28 +08:00
return
}
modelType := c . Query ( "type" )
2026-07-10 13:29:01 +08:00
ownerTenantID := c . Query ( "owner_tenant_id" )
feat(agent): Go port — canvas engine, 22 components, DSL v2, 13 endpoints (#15952)
Ports the agent canvas subsystem from Python to Go.
## What's included
### Canvas Engine (Phase 0/1)
- State engine, scheduler, variable resolver, Redis checkpoint store,
cancel protocol
- **209 tests** across canvas / component / io packages
### 22 Components (P0–P4)
| Tier | Components |
|---|---|
| P0 T1+T2+T3 | LLM, Agent, ExitLoop, Switch, Categorize, Begin,
Message, Invoke |
| P1 T3 | VariableAggregator, VariableAssigner, StringTransform,
ListOperations, DataOperations |
| P2 T3 | Iteration, IterationItem, Loop, LoopItem |
| P3 T3 | UserFillUp, Fillup |
| P4 T5 | Browser, ExcelProcessor, DocsGenerator |
### DSL v2 Schema (Phase 2.5)
- Typed v2 in-memory model with v1-to-v2 auto-detect converter
- v1 legacy field stripping per plan §2.11.7
### HTTP Endpoints & Bug Fixes (Plans PR1–PR3)
- **DELETE SQL bug fix**: gorm v2 `Where("id = ?", id).Delete(...)`
pattern
- **CreateAgent validation**: title/DSL required, duplicate check, 103
envelope
- **13 new endpoints**: templates, prompts, tags, sessions CRUD,
chat/completions (SSE + non-stream stubs), rerun, test_db_connection,
logs, webhook/logs
- **756 Go unit tests** (745 → 756, +18)
- **17 → 0 Python integration test failures** (test_agents.py +
test_session_management/)
### Tools
21 eino tools: HTTPHelper, search tools, financial/data tools, mandatory
stubs
### Infrastructure
OTel observability, NATS message queue, DeepDoc gRPC client, SSRF
guards, IDOR mitigation
2026-06-12 22:58:28 +08:00
2026-07-10 13:29:01 +08:00
addedModels , code , err := h . modelProviderService . ListTenantAddedModels ( user . ID , ownerTenantID , modelType )
feat(agent): Go port — canvas engine, 22 components, DSL v2, 13 endpoints (#15952)
Ports the agent canvas subsystem from Python to Go.
## What's included
### Canvas Engine (Phase 0/1)
- State engine, scheduler, variable resolver, Redis checkpoint store,
cancel protocol
- **209 tests** across canvas / component / io packages
### 22 Components (P0–P4)
| Tier | Components |
|---|---|
| P0 T1+T2+T3 | LLM, Agent, ExitLoop, Switch, Categorize, Begin,
Message, Invoke |
| P1 T3 | VariableAggregator, VariableAssigner, StringTransform,
ListOperations, DataOperations |
| P2 T3 | Iteration, IterationItem, Loop, LoopItem |
| P3 T3 | UserFillUp, Fillup |
| P4 T5 | Browser, ExcelProcessor, DocsGenerator |
### DSL v2 Schema (Phase 2.5)
- Typed v2 in-memory model with v1-to-v2 auto-detect converter
- v1 legacy field stripping per plan §2.11.7
### HTTP Endpoints & Bug Fixes (Plans PR1–PR3)
- **DELETE SQL bug fix**: gorm v2 `Where("id = ?", id).Delete(...)`
pattern
- **CreateAgent validation**: title/DSL required, duplicate check, 103
envelope
- **13 new endpoints**: templates, prompts, tags, sessions CRUD,
chat/completions (SSE + non-stream stubs), rerun, test_db_connection,
logs, webhook/logs
- **756 Go unit tests** (745 → 756, +18)
- **17 → 0 Python integration test failures** (test_agents.py +
test_session_management/)
### Tools
21 eino tools: HTTPHelper, search tools, financial/data tools, mandatory
stubs
### Infrastructure
OTel observability, NATS message queue, DeepDoc gRPC client, SSRF
guards, IDOR mitigation
2026-06-12 22:58:28 +08:00
if err != nil {
2026-07-10 14:26:54 +08:00
common . ErrorWithCode ( c , code , err . Error ( ) )
feat(agent): Go port — canvas engine, 22 components, DSL v2, 13 endpoints (#15952)
Ports the agent canvas subsystem from Python to Go.
## What's included
### Canvas Engine (Phase 0/1)
- State engine, scheduler, variable resolver, Redis checkpoint store,
cancel protocol
- **209 tests** across canvas / component / io packages
### 22 Components (P0–P4)
| Tier | Components |
|---|---|
| P0 T1+T2+T3 | LLM, Agent, ExitLoop, Switch, Categorize, Begin,
Message, Invoke |
| P1 T3 | VariableAggregator, VariableAssigner, StringTransform,
ListOperations, DataOperations |
| P2 T3 | Iteration, IterationItem, Loop, LoopItem |
| P3 T3 | UserFillUp, Fillup |
| P4 T5 | Browser, ExcelProcessor, DocsGenerator |
### DSL v2 Schema (Phase 2.5)
- Typed v2 in-memory model with v1-to-v2 auto-detect converter
- v1 legacy field stripping per plan §2.11.7
### HTTP Endpoints & Bug Fixes (Plans PR1–PR3)
- **DELETE SQL bug fix**: gorm v2 `Where("id = ?", id).Delete(...)`
pattern
- **CreateAgent validation**: title/DSL required, duplicate check, 103
envelope
- **13 new endpoints**: templates, prompts, tags, sessions CRUD,
chat/completions (SSE + non-stream stubs), rerun, test_db_connection,
logs, webhook/logs
- **756 Go unit tests** (745 → 756, +18)
- **17 → 0 Python integration test failures** (test_agents.py +
test_session_management/)
### Tools
21 eino tools: HTTPHelper, search tools, financial/data tools, mandatory
stubs
### Infrastructure
OTel observability, NATS message queue, DeepDoc gRPC client, SSRF
guards, IDOR mitigation
2026-06-12 22:58:28 +08:00
return
}
2026-07-06 18:14:05 +08:00
common . SuccessWithData ( c , addedModels , "success" )
feat(agent): Go port — canvas engine, 22 components, DSL v2, 13 endpoints (#15952)
Ports the agent canvas subsystem from Python to Go.
## What's included
### Canvas Engine (Phase 0/1)
- State engine, scheduler, variable resolver, Redis checkpoint store,
cancel protocol
- **209 tests** across canvas / component / io packages
### 22 Components (P0–P4)
| Tier | Components |
|---|---|
| P0 T1+T2+T3 | LLM, Agent, ExitLoop, Switch, Categorize, Begin,
Message, Invoke |
| P1 T3 | VariableAggregator, VariableAssigner, StringTransform,
ListOperations, DataOperations |
| P2 T3 | Iteration, IterationItem, Loop, LoopItem |
| P3 T3 | UserFillUp, Fillup |
| P4 T5 | Browser, ExcelProcessor, DocsGenerator |
### DSL v2 Schema (Phase 2.5)
- Typed v2 in-memory model with v1-to-v2 auto-detect converter
- v1 legacy field stripping per plan §2.11.7
### HTTP Endpoints & Bug Fixes (Plans PR1–PR3)
- **DELETE SQL bug fix**: gorm v2 `Where("id = ?", id).Delete(...)`
pattern
- **CreateAgent validation**: title/DSL required, duplicate check, 103
envelope
- **13 new endpoints**: templates, prompts, tags, sessions CRUD,
chat/completions (SSE + non-stream stubs), rerun, test_db_connection,
logs, webhook/logs
- **756 Go unit tests** (745 → 756, +18)
- **17 → 0 Python integration test failures** (test_agents.py +
test_session_management/)
### Tools
21 eino tools: HTTPHelper, search tools, financial/data tools, mandatory
stubs
### Infrastructure
OTel observability, NATS message queue, DeepDoc gRPC client, SSRF
guards, IDOR mitigation
2026-06-12 22:58:28 +08:00
}