Skip to content
Closed

Develop #4391

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions common/api_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ func ChannelType2APIType(channelType int) (int, bool) {
apiType = constant.APITypeReplicate
case constant.ChannelTypeCodex:
apiType = constant.APITypeCodex
case constant.ChannelTypeRunningHub:
apiType = constant.APITypeOpenAI
}
if apiType == -1 {
return constant.APITypeOpenAI, false
Expand Down
3 changes: 3 additions & 0 deletions constant/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const (
ChannelTypeSora = 55
ChannelTypeReplicate = 56
ChannelTypeCodex = 57
ChannelTypeRunningHub = 58
ChannelTypeDummy // this one is only for count, do not add any channel after this

)
Expand Down Expand Up @@ -118,6 +119,7 @@ var ChannelBaseURLs = []string{
"https://api.openai.com", //55
"https://api.replicate.com", //56
"https://chatgpt.com", //57
"https://www.runninghub.cn", //58
}

var ChannelTypeNames = map[int]string{
Expand Down Expand Up @@ -175,6 +177,7 @@ var ChannelTypeNames = map[int]string{
ChannelTypeSora: "Sora",
ChannelTypeReplicate: "Replicate",
ChannelTypeCodex: "Codex",
ChannelTypeRunningHub: "RunningHub",
}

func GetChannelTypeName(channelType int) string {
Expand Down
279 changes: 279 additions & 0 deletions controller/channel.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package controller

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -1033,6 +1036,22 @@ func FetchModels(c *gin.Context) {
return
}

if req.Type == constant.ChannelTypeRunningHub {
models, err := fetchRunningHubModels(baseURL, key)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": fmt.Sprintf("获取RunningHub模型失败: %s", err.Error()),
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": models,
})
return
}

client := &http.Client{}
url := fmt.Sprintf("%s/v1/models", baseURL)

Expand Down Expand Up @@ -1090,6 +1109,266 @@ func FetchModels(c *gin.Context) {
})
}

func fetchRunningHubModels(baseURL, key string) ([]string, error) {
payload, err := common.Marshal(map[string]any{})
if err != nil {
return nil, err
}
url := fmt.Sprintf("%s/openapi/v2/resource/list", strings.TrimRight(baseURL, "/"))
request, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(payload))
if err != nil {
return nil, err
}
request.Header.Set("Authorization", "Bearer "+key)
request.Header.Set("Content-Type", "application/json")

response, err := http.DefaultClient.Do(request)
if err != nil {
return nil, err
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status code: %d", response.StatusCode)
}

var result struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
Records []struct {
ResourceName string `json:"resourceName"`
} `json:"records"`
} `json:"data"`
}
if err = common.DecodeJson(response.Body, &result); err != nil {
return nil, err
}
if result.Code != 0 {
return nil, fmt.Errorf("runninghub error code=%d msg=%s", result.Code, result.Msg)
}
models := make([]string, 0, len(result.Data.Records))
for _, record := range result.Data.Records {
name := strings.TrimSpace(record.ResourceName)
if name == "" {
continue
}
models = append(models, name)
}
return models, nil
}

func RunningHubRunAIAppTask(c *gin.Context) {
var req struct {
BaseURL string `json:"base_url"`
Key string `json:"key"`
WebAppID int64 `json:"webapp_id"`
APIKey string `json:"api_key"`
NodeInfoList []any `json:"node_info_list"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.ApiError(c, err)
return
}
if req.WebAppID <= 0 {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "webapp_id is required"})
return
}
baseURL := strings.TrimRight(req.BaseURL, "/")
if baseURL == "" {
baseURL = strings.TrimRight(constant.ChannelBaseURLs[constant.ChannelTypeRunningHub], "/")
}
key := strings.Split(strings.TrimSpace(req.Key), "\n")[0]
apiKey := strings.TrimSpace(req.APIKey)
if apiKey == "" {
apiKey = key
}
payload := map[string]any{
"webappId": req.WebAppID,
"apiKey": apiKey,
}
if len(req.NodeInfoList) > 0 {
payload["nodeInfoList"] = req.NodeInfoList
}
raw, err := common.Marshal(payload)
if err != nil {
common.ApiError(c, err)
return
}
respBody, err := doRunningHubRequest(http.MethodPost, baseURL+"/task/openapi/ai-app/run", key, bytes.NewReader(raw))
if err != nil {
common.ApiError(c, err)
return
}
c.Data(http.StatusOK, "application/json", respBody)
}

func RunningHubGetAIAppCallDemo(c *gin.Context) {
var req struct {
BaseURL string `json:"base_url"`
Key string `json:"key"`
WebAppID int64 `json:"webapp_id"`
APIKey string `json:"api_key"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.ApiError(c, err)
return
}
if req.WebAppID <= 0 {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "webapp_id is required"})
return
}
baseURL := strings.TrimRight(req.BaseURL, "/")
if baseURL == "" {
baseURL = strings.TrimRight(constant.ChannelBaseURLs[constant.ChannelTypeRunningHub], "/")
}
key := strings.Split(strings.TrimSpace(req.Key), "\n")[0]
apiKey := strings.TrimSpace(req.APIKey)
if apiKey == "" {
apiKey = key
}
query := url.Values{}
query.Set("apiKey", apiKey)
query.Set("webappId", strconv.FormatInt(req.WebAppID, 10))
reqURL := fmt.Sprintf("%s/api/webapp/apiCallDemo?%s", baseURL, query.Encode())
respBody, err := doRunningHubRequest(http.MethodGet, reqURL, key, nil)
if err != nil {
common.ApiError(c, err)
return
}
c.Data(http.StatusOK, "application/json", respBody)
}

func RunningHubGetPublicModelList(c *gin.Context) {
var req struct {
BaseURL string `json:"base_url"`
Key string `json:"key"`
Filter map[string]any `json:"filter"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.ApiError(c, err)
return
}
baseURL := strings.TrimRight(req.BaseURL, "/")
if baseURL == "" {
baseURL = strings.TrimRight(constant.ChannelBaseURLs[constant.ChannelTypeRunningHub], "/")
}
key := strings.Split(strings.TrimSpace(req.Key), "\n")[0]
if req.Filter == nil {
req.Filter = map[string]any{}
}
raw, err := common.Marshal(req.Filter)
if err != nil {
common.ApiError(c, err)
return
}
respBody, err := doRunningHubRequest(http.MethodPost, baseURL+"/openapi/v2/resource/list", key, bytes.NewReader(raw))
if err != nil {
common.ApiError(c, err)
return
}
c.Data(http.StatusOK, "application/json", respBody)
}

func RunningHubGetAccountInfo(c *gin.Context) {
var req struct {
BaseURL string `json:"base_url"`
Key string `json:"key"`
APIKey string `json:"api_key"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.ApiError(c, err)
return
}
baseURL := strings.TrimRight(req.BaseURL, "/")
if baseURL == "" {
baseURL = strings.TrimRight(constant.ChannelBaseURLs[constant.ChannelTypeRunningHub], "/")
}
key := strings.Split(strings.TrimSpace(req.Key), "\n")[0]
apiKey := strings.TrimSpace(req.APIKey)
if apiKey == "" {
apiKey = key
}
raw, err := common.Marshal(map[string]string{
"apikey": apiKey,
})
if err != nil {
common.ApiError(c, err)
return
}
respBody, err := doRunningHubRequest(http.MethodPost, baseURL+"/uc/openapi/accountStatus", key, bytes.NewReader(raw))
if err != nil {
common.ApiError(c, err)
return
}
c.Data(http.StatusOK, "application/json", respBody)
}

func RunningHubListAPIKeys(c *gin.Context) {
var req struct {
BaseURL string `json:"base_url"`
Key string `json:"key"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.ApiError(c, err)
return
}
baseURL := strings.TrimRight(req.BaseURL, "/")
if baseURL == "" {
baseURL = strings.TrimRight(constant.ChannelBaseURLs[constant.ChannelTypeRunningHub], "/")
}
key := strings.Split(strings.TrimSpace(req.Key), "\n")[0]
respBody, err := doRunningHubRequest(http.MethodGet, baseURL+"/openapi/v2/api-key/list", key, nil)
if err != nil {
common.ApiError(c, err)
return
}
c.Data(http.StatusOK, "application/json", respBody)
}

func RunningHubGetAPIKeyQueueStatus(c *gin.Context) {
var req struct {
BaseURL string `json:"base_url"`
Key string `json:"key"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.ApiError(c, err)
return
}
baseURL := strings.TrimRight(req.BaseURL, "/")
if baseURL == "" {
baseURL = strings.TrimRight(constant.ChannelBaseURLs[constant.ChannelTypeRunningHub], "/")
}
key := strings.Split(strings.TrimSpace(req.Key), "\n")[0]
respBody, err := doRunningHubRequest(http.MethodGet, baseURL+"/openapi/v2/queue/status", key, nil)
if err != nil {
common.ApiError(c, err)
return
}
c.Data(http.StatusOK, "application/json", respBody)
}

func doRunningHubRequest(method, reqURL, key string, body io.Reader) ([]byte, error) {
req, err := http.NewRequest(method, reqURL, body)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode >= 300 {
return nil, fmt.Errorf("runninghub request failed, status=%d, body=%s", resp.StatusCode, string(respBody))
}
return respBody, nil
}

func BatchSetChannelTag(c *gin.Context) {
channelBatch := ChannelBatch{}
err := c.ShouldBindJSON(&channelBatch)
Expand Down
Loading
Loading