Skip to content
Open
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
10 changes: 10 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@
},
"server_url":"https://api.minimax.chat/v1/text/chatcompletion_pro"
}
],
"jiutian": [
{
"models": ["jiutian-qianwen"],
"enabled": true,
"credentials": {
"api_key": "xxx"
},
"server_url":"https://jiutian.10086.cn/largemodel/api/v1"
}
]
}
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ require (
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/s2a-go v0.1.7 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBEx
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
Expand Down
169 changes: 169 additions & 0 deletions pkg/adapter/jiutian_openai.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package adapter

import (
"github.com/sashabaranov/go-openai"
"go.uber.org/zap"
"simple-one-api/pkg/llm/jiutian"
"simple-one-api/pkg/mylog"
"time"
)

// convertFinishReason 将字符串转换为OpenAI的FinishReason类型
func convertFinishReason(reason string) openai.FinishReason {
switch reason {
case "stop":
return openai.FinishReasonStop
case "length":
return openai.FinishReasonLength
case "content_filter":
return openai.FinishReasonContentFilter
case "function_call":
return openai.FinishReasonFunctionCall
default:
return openai.FinishReasonNull
}
}

// OpenAIRequestToJiuTianRequest 将OpenAI请求转换为九天模型请求
func OpenAIRequestToJiuTianRequest(oaiReq *openai.ChatCompletionRequest) *jiutian.ChatCompletionRequest {
mylog.Logger.Info("Converting OpenAI request to JiuTian request",
zap.String("model", oaiReq.Model),
zap.Int("message_count", len(oaiReq.Messages)),
zap.Float32("temperature", oaiReq.Temperature),
zap.Float32("top_p", oaiReq.TopP))

// 获取最后一条消息作为prompt
lastMessage := oaiReq.Messages[len(oaiReq.Messages)-1].Content

// 构建历史消息
var history [][]string
if len(oaiReq.Messages) > 1 {
for i := 0; i < len(oaiReq.Messages)-1; i += 2 {
if i+1 < len(oaiReq.Messages) {
history = append(history, []string{
oaiReq.Messages[i].Content,
oaiReq.Messages[i+1].Content,
})
}
}
}

mylog.Logger.Debug("Request conversion details",
zap.String("prompt", lastMessage),
zap.Int("history_length", len(history)))

// 创建请求
req := jiutian.NewChatCompletionRequest().
WithModelID(oaiReq.Model). // 使用传入的模型ID
WithPrompt(lastMessage).
WithHistory(history).
WithStream(oaiReq.Stream)

// 设置温度参数(如果有)
if oaiReq.Temperature > 0 {
req.WithTemperature(oaiReq.Temperature)
}

// 设置top_p参数(如果有)
if oaiReq.TopP > 0 {
req.WithTopP(oaiReq.TopP)
}

mylog.Logger.Debug("Created JiuTian request",
zap.String("model_id", req.ModelID),
zap.Bool("stream", req.Stream),
zap.Float32("temperature", req.Params.Temperature),
zap.Float32("top_p", req.Params.TopP))

return req
}

// JiuTianResponseToOpenAIResponse 将九天模型响应转换为OpenAI响应
func JiuTianResponseToOpenAIResponse(jiutianResp *jiutian.ChatCompletionResponse) *openai.ChatCompletionResponse {
mylog.Logger.Info("Converting JiuTian response to OpenAI response",
zap.Any("jiutian_response", map[string]interface{}{
"usage": jiutianResp.Usage,
"response": jiutianResp.Response,
"delta": jiutianResp.Delta,
"finished": jiutianResp.Finished,
"history": jiutianResp.History,
}))

// 创建选项
choice := openai.ChatCompletionChoice{
Index: 0,
Message: openai.ChatCompletionMessage{
Role: "assistant",
Content: jiutianResp.Response,
},
}

// 设置结束原因
if jiutianResp.Finished != "" {
choice.FinishReason = convertFinishReason(jiutianResp.Finished)
}

resp := &openai.ChatCompletionResponse{
ID: "jiutian-" + time.Now().Format("20060102150405"),
Object: "chat.completion",
Created: time.Now().Unix(),
Model: "Llama3.1-70B", // 使用实际的模型ID
Choices: []openai.ChatCompletionChoice{choice},
Usage: openai.Usage{
PromptTokens: jiutianResp.Usage.PromptTokens,
CompletionTokens: jiutianResp.Usage.CompletionTokens,
TotalTokens: jiutianResp.Usage.TotalTokens,
},
}

mylog.Logger.Info("Converted to OpenAI response",
zap.Any("openai_response", map[string]interface{}{
"id": resp.ID,
"model": resp.Model,
"choices": resp.Choices,
"usage": resp.Usage,
}))

return resp
}

// JiuTianStreamResponseToOpenAIStreamResponse 将九天模型的流式响应转换为OpenAI流式响应
func JiuTianStreamResponseToOpenAIStreamResponse(jiutianResp *jiutian.ChatCompletionStreamResponse) *openai.ChatCompletionStreamResponse {
mylog.Logger.Info("Converting JiuTian stream response to OpenAI stream response",
zap.Any("jiutian_stream_response", map[string]interface{}{
"response": jiutianResp.Response,
"delta": jiutianResp.Delta,
"finished": jiutianResp.Finished,
"history": jiutianResp.History,
}))

choice := openai.ChatCompletionStreamChoice{
Index: 0,
Delta: openai.ChatCompletionStreamChoiceDelta{
Role: "assistant",
Content: jiutianResp.Response,
},
}

// 只在收到结束标记时设置结束原因
if jiutianResp.Delta == "[EOS]" {
choice.FinishReason = convertFinishReason(jiutianResp.Finished)
}

resp := &openai.ChatCompletionStreamResponse{
ID: "jiutian-stream-" + time.Now().Format("20060102150405"),
Object: "chat.completion.chunk",
Created: time.Now().Unix(),
Model: "Llama3.1-70B", // 使用实际的模型ID
Choices: []openai.ChatCompletionStreamChoice{choice},
}

mylog.Logger.Info("Converted to OpenAI stream response",
zap.Any("openai_stream_response", map[string]interface{}{
"id": resp.ID,
"model": resp.Model,
"choices": resp.Choices,
}))

return resp
}
8 changes: 5 additions & 3 deletions pkg/handler/openai_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import (
"bytes"
"context"
"errors"
"github.com/gin-gonic/gin"
"github.com/sashabaranov/go-openai"
"go.uber.org/zap"
"io"
"net/http"
"simple-one-api/pkg/adapter"
Expand All @@ -17,6 +14,10 @@ import (
"simple-one-api/pkg/utils"
"strings"
"time"

"github.com/gin-gonic/gin"
"github.com/sashabaranov/go-openai"
"go.uber.org/zap"
)

var defaultReqTimeout = 10
Expand Down Expand Up @@ -52,6 +53,7 @@ var serviceHandlerMap = map[string]func(*gin.Context, *OAIRequestParam) error{
"claude": OpenAI2ClaudeHandler,
"agentbuilder": OpenAI2AgentBuilderHandler,
"dify": OpenAI2DifyHandler,
"jiutian": OpenAI2JiuTianHandler,
}

func LogRequestDetails(c *gin.Context) {
Expand Down
Loading