| package controller |
|
|
| import ( |
| "bytes" |
| "encoding/json" |
| "io" |
| "net/http" |
| "strings" |
|
|
| "github.com/gin-gonic/gin" |
|
|
| "veloera/common" |
| "veloera/dto" |
| "veloera/model" |
| relaycommon "veloera/relay/common" |
| "veloera/service" |
| ) |
|
|
| func RelayGemini(c *gin.Context) { |
| modelParam := c.Param("model") |
| action := "generateContent" |
| modelName := modelParam |
| if idx := strings.Index(modelParam, ":"); idx >= 0 { |
| action = modelParam[idx+1:] |
| modelName = modelParam[:idx] |
| } |
|
|
| stream := false |
| switch action { |
| case "generateContent": |
| stream = false |
| case "streamGenerateContent": |
| stream = true |
| default: |
| respondGeminiError(c, http.StatusNotFound, "unsupported action") |
| return |
| } |
|
|
| if modelName == "" { |
| respondGeminiError(c, http.StatusBadRequest, "model is required") |
| return |
| } |
|
|
| bodyBytes, err := common.GetRequestBody(c) |
| if err != nil { |
| respondGeminiError(c, http.StatusBadRequest, "failed to read request body") |
| return |
| } |
|
|
| var geminiReq dto.GeminiCompatGenerateContentRequest |
| if len(bodyBytes) > 0 { |
| if err := json.Unmarshal(bodyBytes, &geminiReq); err != nil { |
| respondGeminiError(c, http.StatusBadRequest, "invalid JSON body") |
| return |
| } |
| } |
|
|
| openaiReq, err := service.ConvertGeminiCompatRequestToOpenAI(&geminiReq, modelName, stream) |
| if err != nil { |
| respondGeminiError(c, http.StatusBadRequest, err.Error()) |
| return |
| } |
|
|
| convertedBody, err := json.Marshal(openaiReq) |
| if err != nil { |
| respondGeminiError(c, http.StatusInternalServerError, "failed to encode internal request") |
| return |
| } |
|
|
| c.Set(common.KeyRequestBody, convertedBody) |
| c.Request.Body = io.NopCloser(bytes.NewBuffer(convertedBody)) |
| c.Request.ContentLength = int64(len(convertedBody)) |
| c.Request.Header.Set("Content-Type", "application/json") |
| c.Set("relay_format", relaycommon.RelayFormatGemini) |
|
|
| Relay(c) |
| } |
|
|
| func ListGeminiModels(c *gin.Context) { |
| userID := c.GetInt("id") |
| group, err := model.GetUserGroup(userID, true) |
| if err != nil { |
| respondGeminiError(c, http.StatusInternalServerError, "failed to load user group") |
| return |
| } |
|
|
| tokenGroup := c.GetString("token_group") |
| if tokenGroup != "" { |
| group = tokenGroup |
| } |
|
|
| models := model.GetGroupModels(group) |
| response := dto.GeminiModelListResponse{Models: make([]dto.GeminiModel, 0, len(models))} |
|
|
| for _, name := range models { |
| response.Models = append(response.Models, dto.GeminiModel{ |
| Name: "models/" + name, |
| BaseModelID: name, |
| Version: "v1beta", |
| DisplayName: name, |
| Description: "", |
| InputTokenLimit: 32768, |
| OutputTokenLimit: 8192, |
| SupportedGenerationMethods: []string{"generateContent", "streamGenerateContent"}, |
| }) |
| } |
|
|
| c.JSON(http.StatusOK, response) |
| } |
|
|
| func RetrieveGeminiModel(c *gin.Context) { |
| modelName := c.Param("model") |
| if modelName == "" { |
| respondGeminiError(c, http.StatusNotFound, "model not found") |
| return |
| } |
|
|
| userID := c.GetInt("id") |
| group, err := model.GetUserGroup(userID, true) |
| if err != nil { |
| respondGeminiError(c, http.StatusInternalServerError, "failed to load user group") |
| return |
| } |
| tokenGroup := c.GetString("token_group") |
| if tokenGroup != "" { |
| group = tokenGroup |
| } |
|
|
| models := model.GetGroupModels(group) |
| found := false |
| for _, name := range models { |
| if name == modelName { |
| found = true |
| break |
| } |
| } |
|
|
| if !found { |
| respondGeminiError(c, http.StatusNotFound, "model not found") |
| return |
| } |
|
|
| c.JSON(http.StatusOK, dto.GeminiModel{ |
| Name: "models/" + modelName, |
| BaseModelID: modelName, |
| Version: "v1beta", |
| DisplayName: modelName, |
| Description: "", |
| InputTokenLimit: 32768, |
| OutputTokenLimit: 8192, |
| SupportedGenerationMethods: []string{"generateContent", "streamGenerateContent"}, |
| }) |
| } |
|
|
| func respondGeminiError(c *gin.Context, status int, message string) { |
| resp := service.BuildGeminiErrorResponse(status, message) |
| c.JSON(status, resp) |
| } |
|
|