diff --git a/internal/dao/tenant_model_instance.go b/internal/dao/tenant_model_instance.go index 97eb4304e..d8d7f6026 100644 --- a/internal/dao/tenant_model_instance.go +++ b/internal/dao/tenant_model_instance.go @@ -41,6 +41,15 @@ func (dao *TenantModelInstanceDAO) GetAllInstancesByProviderID(providerID string return instances, nil } +func (dao *TenantModelInstanceDAO) GetInstanceByApiKey(apiKey, providerID string) (*entity.TenantModelInstance, error) { + var instance entity.TenantModelInstance + err := DB.Where("api_key = ? && provider_id = ?", apiKey, providerID).First(&instance).Error + if err != nil { + return nil, err + } + return &instance, nil +} + func (dao *TenantModelInstanceDAO) GetByProviderIDAndInstanceName(providerID, instanceName string) (*entity.TenantModelInstance, error) { var instance entity.TenantModelInstance err := DB.Where("provider_id = ? AND instance_name = ?", providerID, instanceName).First(&instance).Error diff --git a/internal/handler/providers.go b/internal/handler/providers.go index 9c7425050..ef5fc0066 100644 --- a/internal/handler/providers.go +++ b/internal/handler/providers.go @@ -387,7 +387,42 @@ func (h *ProviderHandler) ShowInstanceBalance(c *gin.Context) { }) } -func (h *ProviderHandler) CheckProviderConnection(c *gin.Context) { +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{ @@ -408,8 +443,21 @@ func (h *ProviderHandler) CheckProviderConnection(c *gin.Context) { 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.CheckProviderConnection(providerName, instanceName, userID) + errorCode, err := h.modelProviderService.CheckConnection(providerName, apikey, region, baseURL, userID) if err != nil { c.JSON(http.StatusOK, gin.H{ "code": errorCode, diff --git a/internal/router/router.go b/internal/router/router.go index 9ea1075b4..bc56eb5aa 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -319,7 +319,8 @@ func (r *Router) Setup(engine *gin.Engine) { provider.GET("/:provider_name/instances", r.providerHandler.ListProviderInstances) provider.GET("/:provider_name/instances/:instance_name", r.providerHandler.ShowProviderInstance) provider.GET("/:provider_name/instances/:instance_name/balance", r.providerHandler.ShowInstanceBalance) - provider.GET("/:provider_name/instances/:instance_name/connection", r.providerHandler.CheckProviderConnection) + provider.GET("/:provider_name/instances/:instance_name/connection", r.providerHandler.CheckInstanceConnection) + provider.GET("/:provider_name/connection", r.providerHandler.CheckConnection) provider.GET("/:provider_name/instances/:instance_name/tasks", r.providerHandler.ListTasks) provider.GET("/:provider_name/instances/:instance_name/tasks/:task_id", r.providerHandler.ShowTask) provider.PUT("/:provider_name/instances/:instance_name", r.providerHandler.AlterProviderInstance) diff --git a/internal/service/model_service.go b/internal/service/model_service.go index 768fe0dae..cee461b59 100644 --- a/internal/service/model_service.go +++ b/internal/service/model_service.go @@ -88,6 +88,14 @@ type ModelProviderService struct { userTenantDAO *dao.UserTenantDAO } +// CheckConnectionRequest carries the credentials and optional instance selector +// for checking provider connectivity without creating a new model instance. +type CheckConnectionRequest struct { + APIKey string `json:"api_key"` + Region string `json:"region"` + BaseURL string `json:"base_url"` +} + func (m *ModelProviderService) AddModelProvider(providerName, userID string) (common.ErrorCode, error) { _, err := dao.GetModelProviderManager().GetProviderByName(providerName) @@ -364,7 +372,9 @@ func (m *ModelProviderService) ShowProviderInstance(providerName, instanceName, "instanceName": instance.InstanceName, "providerID": instance.ProviderID, "status": instance.Status, + "apikey": instance.APIKey, "region": extra["region"], + "base_url": extra["base_url"], } return result, common.CodeSuccess, nil @@ -423,7 +433,46 @@ func (m *ModelProviderService) ShowInstanceBalance(providerName, instanceName, u return result, common.CodeSuccess, nil } -func (m *ModelProviderService) CheckProviderConnection(providerName, instanceName, userID string) (common.ErrorCode, error) { +func (m *ModelProviderService) CheckConnection(providerName, apiKey, region, baseURL string, userID string) (common.ErrorCode, error) { + providerInfo := dao.GetModelProviderManager().FindProvider(providerName) + if providerInfo == nil { + return common.CodeServerError, fmt.Errorf("provider %s not found", providerName) + } + + apiKey = strings.TrimSpace(apiKey) + region = strings.TrimSpace(region) + baseURL = strings.TrimSpace(baseURL) + if region == "" { + region = "default" + } + + driver := providerInfo.ModelDriver + if strings.EqualFold(providerInfo.Class, "local") { + if baseURL == "" { + return common.CodeDataError, fmt.Errorf("base_url is required for local provider %s", providerName) + } + + var err error + driver, err = newModelDriverForBaseURL(driver, providerName, region, baseURL) + if err != nil { + return common.CodeServerError, err + } + } + + apiConfig := &modelModule.APIConfig{ + ApiKey: &apiKey, + Region: ®ion, + } + + err := driver.CheckConnection(apiConfig) + if err != nil { + return common.CodeServerError, err + } + + return common.CodeSuccess, nil +} + +func (m *ModelProviderService) CheckInstanceConnection(providerName, instanceName, userID string) (common.ErrorCode, error) { // Get tenant ID from user tenants, err := m.userTenantDAO.GetByUserIDAndRole(userID, "owner")