Ver Fonte

add submodel.ai

DD há 3 meses atrás
pai
commit
511489db09

+ 2 - 0
common/api_type.go

@@ -65,6 +65,8 @@ func ChannelType2APIType(channelType int) (int, bool) {
 		apiType = constant.APITypeCoze
 	case constant.ChannelTypeJimeng:
 		apiType = constant.APITypeJimeng
+	case constant.ChannelTypeSubmodel:
+		apiType = constant.APITypeSubmodel
 	}
 	if apiType == -1 {
 		return constant.APITypeOpenAI, false

+ 1 - 0
constant/api_type.go

@@ -31,5 +31,6 @@ const (
 	APITypeXai
 	APITypeCoze
 	APITypeJimeng
+	APITypeSubmodel
 	APITypeDummy // this one is only for count, do not add any channel after this
 )

+ 2 - 0
constant/channel.go

@@ -49,6 +49,7 @@ const (
 	ChannelTypeCoze           = 49
 	ChannelTypeKling          = 50
 	ChannelTypeJimeng         = 51
+	ChannelTypeSubmodel       = 52
 	ChannelTypeDummy          // this one is only for count, do not add any channel after this
 
 )
@@ -106,4 +107,5 @@ var ChannelBaseURLs = []string{
 	"https://api.coze.cn",                       //49
 	"https://api.klingai.com",                   //50
 	"https://visual.volcengineapi.com",          //51
+	"https://llm.submodel.ai",                   //52
 }

+ 82 - 0
relay/channel/submodel/adaptor.go

@@ -0,0 +1,82 @@
+package submodel
+
+import (
+	"errors"
+	"io"
+	"net/http"
+	"one-api/dto"
+	"one-api/relay/channel"
+	"one-api/relay/channel/openai"
+	relaycommon "one-api/relay/common"
+	"one-api/types"
+
+	"github.com/gin-gonic/gin"
+)
+
+type Adaptor struct {
+}
+
+func (a *Adaptor) ConvertClaudeRequest(*gin.Context, *relaycommon.RelayInfo, *dto.ClaudeRequest) (any, error) {
+	return nil, errors.New("not implemented")
+}
+
+func (a *Adaptor) ConvertAudioRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.AudioRequest) (io.Reader, error) {
+	return nil, errors.New("not implemented")
+}
+
+func (a *Adaptor) ConvertImageRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.ImageRequest) (any, error) {
+	return nil, errors.New("not implemented")
+}
+
+func (a *Adaptor) Init(info *relaycommon.RelayInfo) {
+}
+
+func (a *Adaptor) GetRequestURL(info *relaycommon.RelayInfo) (string, error) {
+	return relaycommon.GetFullRequestURL(info.BaseUrl, info.RequestURLPath, info.ChannelType), nil
+}
+
+func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Header, info *relaycommon.RelayInfo) error {
+	channel.SetupApiRequestHeader(info, c, req)
+	req.Set("Authorization", "Bearer "+info.ApiKey)
+	return nil
+}
+
+func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayInfo, request *dto.GeneralOpenAIRequest) (any, error) {
+	if request == nil {
+		return nil, errors.New("request is nil")
+	}
+	return request, nil
+}
+
+func (a *Adaptor) ConvertRerankRequest(c *gin.Context, relayMode int, request dto.RerankRequest) (any, error) {
+	return nil, errors.New("not implemented")
+}
+
+func (a *Adaptor) ConvertEmbeddingRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.EmbeddingRequest) (any, error) {
+	return nil, errors.New("not implemented")
+}
+
+func (a *Adaptor) ConvertOpenAIResponsesRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.OpenAIResponsesRequest) (any, error) {
+	return nil, errors.New("not implemented")
+}
+
+func (a *Adaptor) DoRequest(c *gin.Context, info *relaycommon.RelayInfo, requestBody io.Reader) (any, error) {
+	return channel.DoApiRequest(a, c, info, requestBody)
+}
+
+func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (usage any, err *types.NewAPIError) {
+	if info.IsStream {
+		usage, err = openai.OaiStreamHandler(c, info, resp)
+	} else {
+		usage, err = openai.OpenaiHandler(c, info, resp)
+	}
+	return
+}
+
+func (a *Adaptor) GetModelList() []string {
+	return ModelList
+}
+
+func (a *Adaptor) GetChannelName() string {
+	return ChannelName
+}

+ 16 - 0
relay/channel/submodel/constants.go

@@ -0,0 +1,16 @@
+package submodel
+
+var ModelList = []string{
+	"NousResearch/Hermes-4-405B-FP8",
+	"Qwen/Qwen3-235B-A22B-Thinking-2507",
+	"Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8",
+	"Qwen/Qwen3-235B-A22B-Instruct-2507",
+	"zai-org/GLM-4.5-FP8",
+	"openai/gpt-oss-120b",
+	"deepseek-ai/DeepSeek-R1-0528",
+	"deepseek-ai/DeepSeek-R1",
+	"deepseek-ai/DeepSeek-V3-0324",
+	"deepseek-ai/DeepSeek-V3.1",
+}
+
+var ChannelName = "submodel"

+ 3 - 0
relay/relay_adaptor.go

@@ -34,6 +34,7 @@ import (
 	"one-api/relay/channel/xunfei"
 	"one-api/relay/channel/zhipu"
 	"one-api/relay/channel/zhipu_4v"
+	"one-api/relay/channel/submodel"
 )
 
 func GetAdaptor(apiType int) channel.Adaptor {
@@ -96,6 +97,8 @@ func GetAdaptor(apiType int) channel.Adaptor {
 		return &coze.Adaptor{}
 	case constant.APITypeJimeng:
 		return &jimeng.Adaptor{}
+	case constant.APITypeSubmodel:
+		return &submodel.Adaptor{}
 	}
 	return nil
 }

+ 13 - 0
setting/ratio_setting/model_ratio.go

@@ -223,6 +223,19 @@ var defaultModelRatio = map[string]float64{
 	"grok-vision-beta":      2.5,
 	"grok-3-fast-beta":      2.5,
 	"grok-3-mini-fast-beta": 0.3,
+
+    // submodel
+	"NousResearch/Hermes-4-405B-FP8":               0.8,
+	"Qwen/Qwen3-235B-A22B-Thinking-2507":           0.6,
+	"Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8":      0.8,
+	"Qwen/Qwen3-235B-A22B-Instruct-2507":           0.3,
+	"zai-org/GLM-4.5-FP8":                          0.8,
+	"openai/gpt-oss-120b":                          0.5,
+	"deepseek-ai/DeepSeek-R1-0528":                 0.8,
+	"deepseek-ai/DeepSeek-R1":                      0.8,
+	"deepseek-ai/DeepSeek-V3-0324":                 0.8,
+	"deepseek-ai/DeepSeek-V3.1":                    0.8
+
 }
 
 var defaultModelPrice = map[string]float64{

+ 5 - 0
web/src/constants/channel.constants.js

@@ -135,6 +135,11 @@ export const CHANNEL_OPTIONS = [
     color: 'blue',
     label: '即梦',
   },
+  {
+    value: 52,
+    color: 'blue',
+    label: 'SubModel',
+  },
 ];
 
 export const MODEL_TABLE_PAGE_SIZE = 10;

+ 2 - 0
web/src/helpers/render.js

@@ -398,6 +398,8 @@ export function getChannelIcon(channelType) {
       return <FastGPT.Color size={iconSize} />;
     case 21: // 知识库:AI Proxy
     case 44: // 嵌入模型:MokaAI M3E
+    case 52: // SubModel
+      return null;
     default:
       return null; // 未知类型或自定义渠道不显示图标
   }

+ 3 - 0
web/src/pages/Channel/EditTagModal.js

@@ -98,6 +98,9 @@ const EditTagModal = (props) => {
         case 36:
           localModels = ['suno_music', 'suno_lyrics'];
           break;
+        case 52:
+          localModels = ['NousResearch/Hermes-4-405B-FP8', 'Qwen/Qwen3-235B-A22B-Thinking-2507', 'Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8', 'zai-org/GLM-4.5-FP8', 'openai/gpt-oss-120b', 'deepseek-ai/DeepSeek-R1-0528', 'deepseek-ai/DeepSeek-R1', 'deepseek-ai/DeepSeek-V3-0324', 'deepseek-ai/DeepSeek-V3.1'];
+          break; 
         default:
           localModels = getChannelModels(value);
           break;