Files
ragflow/internal/handler/providers.go
Jin Hai 719ce15c95 Go CLI: update list supported models (#15845)
### What problem does this PR solve?

Now list supported models will show more info.

```
RAGFlow(api/default)> list supported models from 'gitee' 'test';
+-----------+------------+-------------+----------------------------------------------------------+---------------------------------------------+
| dimension | max_tokens | model_types | name                                                     | thinking                                    |
+-----------+------------+-------------+----------------------------------------------------------+---------------------------------------------+
|           |            |             | Wan2.7                                                   |                                             |
|           |            |             | HappyHorse-1.0                                           |                                             |
|           |            |             | Qwen3.6-27B@Qwen                                         |                                             |
|           |            |             | Qwen3.6-35B-A3B@Qwen                                     |                                             |
|           | 1048576    | [chat]      | DeepSeek-V4-Flash@deepseek-ai                            | map[clear_thinking:true default_value:true] |
|           | 1048576    | [chat]      | DeepSeek-V4-Pro@deepseek-ai                              | map[clear_thinking:true default_value:true] |
+-----------+------------+-------------+----------------------------------------------------------+---------------------------------------------+
```

### Type of change

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

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-06-09 19:01:00 +08:00

1585 lines
37 KiB
Go

//
// 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 (
"errors"
"fmt"
"net/http"
"ragflow/internal/common"
"ragflow/internal/dao"
"ragflow/internal/entity/models"
"ragflow/internal/service"
"strings"
"github.com/gin-gonic/gin"
)
// ProviderHandler provider handler
type ProviderHandler struct {
userService *service.UserService
modelProviderService *service.ModelProviderService
userTenantDAO *dao.UserTenantDAO
}
// NewProviderHandler create provider handler
func NewProviderHandler(userService *service.UserService, modelProviderService *service.ModelProviderService) *ProviderHandler {
return &ProviderHandler{
userService: userService,
modelProviderService: modelProviderService,
userTenantDAO: dao.NewUserTenantDAO(),
}
}
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 {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeNotFound,
"message": err.Error(),
})
return
}
for _, provider := range providers {
delete(provider, "url_suffix")
delete(provider, "tags")
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": providers,
})
return
}
userID := c.GetString("user_id")
// list tenant providers
providers, errorCode, err := h.modelProviderService.ListProvidersOfTenant(userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
"data": nil,
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": providers,
})
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 {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
"data": false,
})
return
}
userID := c.GetString("user_id")
errorCode, err := h.modelProviderService.AddModelProvider(req.ProviderName, userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
})
}
func (h *ProviderHandler) DeleteProvider(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
userID := c.GetString("user_id")
errorCode, err := h.modelProviderService.DeleteModelProvider(providerName, userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
})
}
func (h *ProviderHandler) ShowProvider(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
provider, err := dao.GetModelProviderManager().GetProviderByName(providerName)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeNotFound,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": provider,
})
}
func (h *ProviderHandler) ListModels(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
providerModels, err := dao.GetModelProviderManager().ListModels(providerName)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeNotFound,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": providerModels,
})
}
func (h *ProviderHandler) ShowModel(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
modelName := c.Param("model_name")
if modelName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Model name is required",
})
return
}
model, err := dao.GetModelProviderManager().GetModelByName(providerName, modelName)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeNotFound,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": model,
})
}
type CreateProviderInstanceRequest struct {
InstanceName string `json:"instance_name" binding:"required"`
APIKey string `json:"api_key"`
BaseURL string `json:"base_url"`
Region string `json:"region"`
}
func (h *ProviderHandler) CreateProviderInstance(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
var req CreateProviderInstanceRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
userID := c.GetString("user_id")
_, err := h.modelProviderService.CreateProviderInstance(providerName, req.InstanceName, req.APIKey, req.BaseURL, req.Region, userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeServerError,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
})
}
func (h *ProviderHandler) ListProviderInstances(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
userID := c.GetString("user_id")
instances, errorCode, err := h.modelProviderService.ListProviderInstances(providerName, userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": instances,
})
}
func (h *ProviderHandler) ShowProviderInstance(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
instanceName := c.Param("instance_name")
if instanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
userID := c.GetString("user_id")
// Get tenant ID from user
instance, errorCode, err := h.modelProviderService.ShowProviderInstance(providerName, instanceName, userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": instance,
})
}
func (h *ProviderHandler) ShowInstanceBalance(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
instanceName := c.Param("instance_name")
if instanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
userID := c.GetString("user_id")
// Get tenant ID from user
balance, errorCode, err := h.modelProviderService.ShowInstanceBalance(providerName, instanceName, userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": balance,
})
}
func (h *ProviderHandler) CheckConnection(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
var req service.CheckConnectionRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": err.Error(),
})
return
}
userID := c.GetString("user_id")
errCode, err := h.modelProviderService.CheckConnection(providerName, req.APIKey, req.Region, req.BaseURL, userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
})
}
func (h *ProviderHandler) CheckInstanceConnection(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
instanceName := c.Param("instance_name")
if instanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
userID := c.GetString("user_id")
instanceInfo, code, err := h.modelProviderService.ShowProviderInstance(providerName, instanceName, userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": code,
"message": err.Error(),
})
return
}
apikey, _ := instanceInfo["apikey"].(string)
region, _ := instanceInfo["region"].(string)
baseURL, _ := instanceInfo["base_url"].(string)
// Get tenant ID from user
errorCode, err := h.modelProviderService.CheckConnection(providerName, apikey, region, baseURL, userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
})
}
func (h *ProviderHandler) ListTasks(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
instanceName := c.Param("instance_name")
if instanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
userID := c.GetString("user_id")
// Get tenant ID from user
listTaskResponse, errorCode, err := h.modelProviderService.ListTasks(providerName, instanceName, userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": listTaskResponse,
})
}
func (h *ProviderHandler) ShowTask(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
instanceName := c.Param("instance_name")
if instanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
taskID := c.Param("task_id")
if taskID == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Task id is required",
})
return
}
userID := c.GetString("user_id")
// Get tenant ID from user
taskResponse, errorCode, err := h.modelProviderService.ShowTask(providerName, instanceName, taskID, userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": taskResponse,
})
}
type AlterProviderInstanceRequest struct {
LLMName string `json:"llm_name" binding:"required"`
}
func (h *ProviderHandler) AlterProviderInstance(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
instanceName := c.Param("instance_name")
if instanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
var req AlterProviderInstanceRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
userID := c.GetString("user_id")
if userID == "" {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeUnauthorized,
"message": "Unauthorized",
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": common.CodeNotFound,
"message": "success",
})
}
type DropProviderInstanceRequest struct {
Instances []string `json:"instances" binding:"required"`
}
func (h *ProviderHandler) DropProviderInstance(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
var req DropProviderInstanceRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
userID := c.GetString("user_id")
_, err := h.modelProviderService.DropProviderInstances(providerName, userID, req.Instances)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeServerError,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
})
}
func (h *ProviderHandler) ListInstanceModels(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
instanceName := c.Param("instance_name")
if instanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
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 {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeServerError,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": modelList,
})
return
}
modelInstances, err := h.modelProviderService.ListInstanceModels(providerName, instanceName, c.GetString("user_id"))
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeNotFound,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": modelInstances,
})
}
type EnableOrDisableModelRequest struct {
Status string `json:"status" binding:"required"`
}
func (h *ProviderHandler) EnableOrDisableModel(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
instanceName := c.Param("instance_name")
if instanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
modelName := c.Param("model_name")
if modelName != "" {
modelName = strings.TrimPrefix(modelName, "/")
}
if modelName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Model name is required",
})
return
}
var req EnableOrDisableModelRequest
if err := c.ShouldBindJSON(&req); err != nil {
println("JSON bind error: %v (type: %T)", err, err)
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
userID := c.GetString("user_id")
_, err := h.modelProviderService.UpdateModelStatus(providerName, instanceName, modelName, userID, req.Status)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeServerError,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
})
}
func prepareProviderInstance(providerName, instanceName, reqProviderName, reqInstanceName string) error {
if providerName == "" {
return errors.New("Provider name is required")
}
if instanceName == "" {
return errors.New("Instance name is required")
}
if reqProviderName != "" && !strings.EqualFold(reqProviderName, providerName) {
return errors.New("Provider name does not match path")
}
if reqInstanceName != "" && !strings.EqualFold(reqInstanceName, instanceName) {
return errors.New("Instance name does not match path")
}
return nil
}
func prepareAddModelRequest(req *service.AddModelRequest, providerName, instanceName string) error {
if err := prepareProviderInstance(providerName, instanceName, req.ProviderName, req.InstanceName); err != nil {
return err
}
if len(req.Models) == 0 {
return errors.New("Models are required")
}
for _, model := range req.Models {
if model.ModelName == "" {
return errors.New("Model name is required")
}
if len(model.ModelTypes) == 0 {
return errors.New("Model type is required")
}
}
req.ProviderName = providerName
req.InstanceName = instanceName
return nil
}
func (h *ProviderHandler) AddModel(c *gin.Context) {
var req service.AddModelRequest
if err := c.ShouldBindJSON(&req); err != nil {
println("JSON bind error: %v (type: %T)", err, err)
c.JSON(http.StatusBadRequest, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
if err := prepareAddModelRequest(&req, c.Param("provider_name"), c.Param("instance_name")); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
userID := c.GetString("user_id")
code, err := h.modelProviderService.AddModel(&req, userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": code,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": code,
"message": "success",
})
}
type DropInstanceModelRequest struct {
Models []string `json:"models" binding:"required"`
}
func (h *ProviderHandler) DropInstanceModels(c *gin.Context) {
providerName := c.Param("provider_name")
if providerName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
instanceName := c.Param("instance_name")
if instanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
var req DropInstanceModelRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
userID := c.GetString("user_id")
_, err := h.modelProviderService.DropInstanceModels(providerName, instanceName, userID, req.Models)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": common.CodeServerError,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
})
}
type ChatToModelRequest struct {
ProviderName *string `json:"provider_name"`
InstanceName *string `json:"instance_name"`
ModelName *string `json:"model_name"`
Messages []map[string]interface{} `json:"messages"`
Stream bool `json:"stream"`
Thinking bool `json:"thinking"`
Effort *string `json:"effort"`
Verbosity *string `json:"verbosity"`
}
func (h *ProviderHandler) ChatToModel(c *gin.Context) {
var req ChatToModelRequest
if err := c.ShouldBindJSON(&req); err != nil {
println("JSON bind error: %v (type: %T)", err, err)
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
if req.ProviderName == nil || *req.ProviderName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
if req.InstanceName == nil || *req.InstanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
if req.ModelName == nil || *req.ModelName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Model name is required",
})
return
}
userID := c.GetString("user_id")
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,
Vision: nil,
Stop: &[]string{},
DoSample: nil,
MaxTokens: nil,
Temperature: nil,
TopP: nil,
Effort: req.Effort,
Verbosity: req.Verbosity,
}
// Check if it's a stream request
if req.Stream {
// Set SSE headers
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
}
// 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}
}
// Stream response using sender function (best performance, no channel)
errorCode, err := h.modelProviderService.ChatToModelStreamWithSender(*req.ProviderName, *req.InstanceName, *req.ModelName, userID, messages, &apiConfig, &chatConfig, sender)
if errorCode != common.CodeSuccess {
c.SSEvent("error", err.Error())
}
return
}
// Non-stream response
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}
}
response, errorCode, err = h.modelProviderService.ChatToModelWithMessages(*req.ProviderName, *req.InstanceName, *req.ModelName, userID, messages, &apiConfig, &chatConfig)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"reasoning_content": response.ReasonContent,
"answer": response.Answer,
})
}
type EmbedTextRequest struct {
ProviderName *string `json:"provider_name"`
InstanceName *string `json:"instance_name"`
ModelName *string `json:"model_name"`
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)
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
if req.ProviderName == nil || *req.ProviderName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
if req.InstanceName == nil || *req.InstanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
if req.ModelName == nil || *req.ModelName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Model name is required",
})
return
}
userID := c.GetString("user_id")
apiConfig := models.APIConfig{
ApiKey: nil,
Region: nil,
}
embeddingConfig := models.EmbeddingConfig{
Dimension: req.Dimension,
}
// Non-stream response
var response []models.EmbeddingData
var errorCode common.ErrorCode
var err error
response, errorCode, err = h.modelProviderService.EmbedText(*req.ProviderName, *req.InstanceName, *req.ModelName, userID, req.Texts, &apiConfig, &embeddingConfig)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": response,
"message": "success",
})
}
type RerankDocumentRequest struct {
ProviderName *string `json:"provider_name"`
InstanceName *string `json:"instance_name"`
ModelName *string `json:"model_name"`
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)
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
if req.ProviderName == nil || *req.ProviderName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
if req.InstanceName == nil || *req.InstanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
if req.ModelName == nil || *req.ModelName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Model name is required",
})
return
}
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
response, errorCode, err = h.modelProviderService.RerankDocument(*req.ProviderName, *req.InstanceName, *req.ModelName, userID, req.Query, req.Documents, &apiConfig, &rerankConfig)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": response.Data,
"message": "success",
})
}
type TranscribeAudioRequest struct {
ProviderName *string `json:"provider_name"`
InstanceName *string `json:"instance_name"`
ModelName *string `json:"model_name"`
File *string `json:"file"`
Language []string `json:"language"`
Prompt int `json:"prompt"`
Stream bool `json:"stream"`
ASRConfig *models.ASRConfig `json:"asr_config"`
}
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)
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
if req.ProviderName == nil || *req.ProviderName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
if req.InstanceName == nil || *req.InstanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
if req.ModelName == nil || *req.ModelName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Model name is required",
})
return
}
userID := c.GetString("user_id")
apiConfig := models.APIConfig{
ApiKey: nil,
Region: nil,
}
asrConfig := models.ASRConfig{}
if req.ASRConfig != nil {
asrConfig = *req.ASRConfig
}
// Check if it's a stream request
if req.Stream {
// Set SSE headers
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
}
// Stream response using sender function (best performance, no channel)
errorCode, err := h.modelProviderService.TranscribeAudioStream(*req.ProviderName, *req.InstanceName, *req.ModelName, userID, req.File, &apiConfig, &asrConfig, sender)
if errorCode != common.CodeSuccess {
c.SSEvent("error", err.Error())
}
return
}
// Non-stream response
var response *models.ASRResponse
var errorCode common.ErrorCode
var err error
response, errorCode, err = h.modelProviderService.TranscribeAudio(*req.ProviderName, *req.InstanceName, *req.ModelName, userID, req.File, &apiConfig, &asrConfig)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": response,
"message": "success",
})
}
type AudioSpeechRequest struct {
ProviderName *string `json:"provider_name"`
InstanceName *string `json:"instance_name"`
ModelName *string `json:"model_name"`
Text *string `json:"text"`
Stream bool `json:"stream"`
TTSConfig *models.TTSConfig `json:"tts_config"`
}
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)
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
if req.ProviderName == nil || *req.ProviderName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
if req.InstanceName == nil || *req.InstanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
if req.ModelName == nil || *req.ModelName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Model name is required",
})
return
}
userID := c.GetString("user_id")
apiConfig := models.APIConfig{
ApiKey: nil,
Region: nil,
}
ttsConfig := models.TTSConfig{}
if req.TTSConfig != nil {
ttsConfig = *req.TTSConfig
}
// Check if it's a stream request
if req.Stream {
// Set SSE headers
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
}
// Stream response using sender function (best performance, no channel)
errorCode, err := h.modelProviderService.AudioSpeechStream(*req.ProviderName, *req.InstanceName, *req.ModelName, userID, req.Text, &apiConfig, &ttsConfig, sender)
if errorCode != common.CodeSuccess {
c.SSEvent("error", err.Error())
}
return
}
// Non-stream response
var response *models.TTSResponse
var errorCode common.ErrorCode
var err error
response, errorCode, err = h.modelProviderService.AudioSpeech(*req.ProviderName, *req.InstanceName, *req.ModelName, userID, req.Text, &apiConfig, &ttsConfig)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": response,
"message": "success",
})
}
type OCRFileRequest struct {
ProviderName *string `json:"provider_name"`
InstanceName *string `json:"instance_name"`
ModelName *string `json:"model_name"`
Content []byte `json:"content"`
URL *string `json:"url"`
}
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)
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
if req.ProviderName == nil || *req.ProviderName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
if req.InstanceName == nil || *req.InstanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
if req.ModelName == nil || *req.ModelName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Model name is required",
})
return
}
userID := c.GetString("user_id")
apiConfig := models.APIConfig{
ApiKey: nil,
Region: nil,
}
OCRConfig := models.OCRConfig{}
// Non-stream response
var response *models.OCRFileResponse
var errorCode common.ErrorCode
var err error
response, errorCode, err = h.modelProviderService.OCRFile(*req.ProviderName, *req.InstanceName, *req.ModelName, userID, req.Content, req.URL, &apiConfig, &OCRConfig)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": response,
"message": "success",
})
}
type ParseFileRequest struct {
ProviderName *string `json:"provider_name"`
InstanceName *string `json:"instance_name"`
ModelName *string `json:"model_name"`
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)
c.JSON(http.StatusOK, gin.H{
"code": common.CodeBadRequest,
"message": err.Error(),
})
return
}
if req.ProviderName == nil || *req.ProviderName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Provider name is required",
})
return
}
if req.InstanceName == nil || *req.InstanceName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Instance name is required",
})
return
}
if req.ModelName == nil || *req.ModelName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Model name is required",
})
return
}
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
response, errorCode, err = h.modelProviderService.ParseFile(*req.ProviderName, *req.InstanceName, *req.ModelName, userID, req.Content, req.URL, &apiConfig, &parseFileConfig)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": errorCode,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": response,
"message": "success",
})
}