Procházet zdrojové kódy

feat: swagger docs (#50)

* feat: init swag

* feat: relay swagger

* feat: swag workflow

* fix: fmt swagger commend

* docs: swagger readme

* feat: relay swag headers
zijiren před 9 měsíci
rodič
revize
45f0833066
100 změnil soubory, kde provedl 20650 přidání a 1398 odebrání
  1. 6 1
      .github/workflows/release.yml
  2. 4 0
      Dockerfile
  3. 1 0
      README.md
  4. 1 0
      README.zh.md
  5. 20 38
      controller/channel-billing.go
  6. 45 13
      controller/channel-test.go
  7. 141 1
      controller/channel.go
  8. 48 0
      controller/dashboard.go
  9. 146 6
      controller/group.go
  10. 10 0
      controller/import.go
  11. 132 1
      controller/log.go
  12. 8 0
      controller/misc.go
  13. 75 61
      controller/model.go
  14. 86 0
      controller/modelconfig.go
  15. 74 7
      controller/monitor.go
  16. 40 0
      controller/option.go
  17. 530 0
      controller/relay-controller.go
  18. 60 0
      controller/relay-dashboard.go
  19. 88 0
      controller/relay-model.go
  20. 233 521
      controller/relay.go
  21. 197 4
      controller/token.go
  22. 6913 0
      docs/docs.go
  23. 6884 0
      docs/swagger.json
  24. 4242 0
      docs/swagger.yaml
  25. 11 0
      go.mod
  26. 47 0
      go.sum
  27. 3 0
      main.go
  28. 2 2
      middleware/auth.go
  29. 8 8
      middleware/distributor.go
  30. 2 2
      model/channel.go
  31. 12 12
      model/channeltest.go
  32. 2 2
      model/modelconfig.go
  33. 5 5
      relay/adaptor/ai360/constants.go
  34. 20 20
      relay/adaptor/ali/adaptor.go
  35. 62 62
      relay/adaptor/ali/constants.go
  36. 6 6
      relay/adaptor/ali/embeddings.go
  37. 3 3
      relay/adaptor/ali/image.go
  38. 4 4
      relay/adaptor/ali/model.go
  39. 9 9
      relay/adaptor/ali/rerank.go
  40. 3 3
      relay/adaptor/ali/stt-realtime.go
  41. 3 3
      relay/adaptor/ali/tts.go
  42. 7 7
      relay/adaptor/anthropic/constants.go
  43. 11 11
      relay/adaptor/anthropic/main.go
  44. 3 3
      relay/adaptor/anthropic/model.go
  45. 10 10
      relay/adaptor/aws/claude/main.go
  46. 11 11
      relay/adaptor/aws/llama3/main.go
  47. 3 3
      relay/adaptor/aws/llama3/main_test.go
  48. 4 4
      relay/adaptor/aws/utils/utils.go
  49. 7 7
      relay/adaptor/azure/constants.go
  50. 7 7
      relay/adaptor/baichuan/constants.go
  51. 13 13
      relay/adaptor/baidu/adaptor.go
  52. 8 8
      relay/adaptor/baidu/constants.go
  53. 3 3
      relay/adaptor/baidu/embeddings.go
  54. 2 2
      relay/adaptor/baidu/error.go
  55. 3 3
      relay/adaptor/baidu/image.go
  56. 8 8
      relay/adaptor/baidu/main.go
  57. 5 7
      relay/adaptor/baiduv2/adaptor.go
  58. 22 22
      relay/adaptor/baiduv2/constants.go
  59. 3 3
      relay/adaptor/cloudflare/adaptor.go
  60. 31 31
      relay/adaptor/cloudflare/constant.go
  61. 2 2
      relay/adaptor/cohere/adaptor.go
  62. 7 7
      relay/adaptor/cohere/constant.go
  63. 8 8
      relay/adaptor/cohere/main.go
  64. 2 2
      relay/adaptor/coze/adaptor.go
  65. 8 8
      relay/adaptor/coze/main.go
  66. 3 3
      relay/adaptor/deepseek/constants.go
  67. 4 4
      relay/adaptor/doc2x/adaptor.go
  68. 2 2
      relay/adaptor/doc2x/constants.go
  69. 6 6
      relay/adaptor/doc2x/pdf.go
  70. 16 16
      relay/adaptor/doubao/constants.go
  71. 4 4
      relay/adaptor/doubao/main.go
  72. 3 3
      relay/adaptor/doubaoaudio/constants.go
  73. 6 6
      relay/adaptor/doubaoaudio/main.go
  74. 3 3
      relay/adaptor/doubaoaudio/tts.go
  75. 6 6
      relay/adaptor/gemini/adaptor.go
  76. 9 9
      relay/adaptor/gemini/constants.go
  77. 4 4
      relay/adaptor/gemini/embeddings.go
  78. 8 8
      relay/adaptor/gemini/main.go
  79. 22 22
      relay/adaptor/groq/constants.go
  80. 3 3
      relay/adaptor/lingyiwanwu/constants.go
  81. 7 7
      relay/adaptor/minimax/adaptor.go
  82. 8 8
      relay/adaptor/minimax/constants.go
  83. 5 5
      relay/adaptor/minimax/tts.go
  84. 7 7
      relay/adaptor/mistral/constants.go
  85. 7 7
      relay/adaptor/moonshot/constants.go
  86. 8 8
      relay/adaptor/novita/constants.go
  87. 8 8
      relay/adaptor/ollama/adaptor.go
  88. 8 8
      relay/adaptor/ollama/constants.go
  89. 2 2
      relay/adaptor/ollama/error.go
  90. 32 32
      relay/adaptor/ollama/main.go
  91. 25 25
      relay/adaptor/openai/adaptor.go
  92. 33 33
      relay/adaptor/openai/constants.go
  93. 1 1
      relay/adaptor/openai/image.go
  94. 6 6
      relay/adaptor/openai/main.go
  95. 0 138
      relay/adaptor/openai/model.go
  96. 1 1
      relay/adaptor/openai/rerank.go
  97. 2 2
      relay/adaptor/openai/stt.go
  98. 3 3
      relay/adaptor/openai/tts.go
  99. 12 12
      relay/adaptor/openai/util.go
  100. 2 2
      relay/adaptor/openrouter/adaptor.go

+ 6 - 1
.github/workflows/release.yml

@@ -47,7 +47,7 @@ jobs:
     steps:
       - name: Checkout
         uses: actions/checkout@v4
-      
+
       - name: Download tiktoken
         run: |
           bash common/tiktoken/assest.sh
@@ -57,6 +57,11 @@ jobs:
         with:
           go-version: "1.23"
 
+      - name: Generate Swagger
+        run: |
+          go install github.com/swaggo/swag/cmd/swag@latest
+          swag init
+
       - name: Build
         run: |
           export GOOS=${{ matrix.targets.GOOS }}

+ 4 - 0
Dockerfile

@@ -8,6 +8,10 @@ RUN apk add --no-cache curl
 
 RUN sh common/tiktoken/assest.sh
 
+RUN go install github.com/swaggo/swag/cmd/swag@latest
+
+RUN swag init
+
 RUN go build -trimpath -tags "jsoniter" -ldflags "-s -w" -o aiproxy
 
 FROM alpine:latest

+ 1 - 0
README.md

@@ -33,6 +33,7 @@ Next-generation AI gateway, using OpenAI as the protocol entry point.
 - Think model support `<think>` split to `reasoning_content`
 - Prompt Token Cache billing support
 - Inline tiktoken, no need to download tiktoken file
+- API `Swagger` documentation support `http://host:port/swagger/index.html`
 
 ## Deploy
 

+ 1 - 0
README.zh.md

@@ -34,6 +34,7 @@
 - Think 模型支持 `<think>` 切分到 `reasoning_content`
 - 提示词缓存计费支持
 - 内敛分词器,无需额外下载 tiktoken 文件
+- API `Swagger` 文档支持 `http://host:port/swagger/index.html`
 
 ## 部署
 

+ 20 - 38
controller/channel-billing.go

@@ -9,14 +9,11 @@ import (
 	"time"
 
 	"github.com/gin-gonic/gin"
-	"github.com/labring/aiproxy/common/balance"
 	"github.com/labring/aiproxy/common/notify"
 	"github.com/labring/aiproxy/middleware"
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/adaptor"
-	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/channeltype"
-	log "github.com/sirupsen/logrus"
 )
 
 // https://github.com/labring/aiproxy/issues/79
@@ -43,6 +40,16 @@ func updateChannelBalance(channel *model.Channel) (float64, error) {
 	return 0, nil
 }
 
+// UpdateChannelBalance godoc
+//
+//	@Summary		Update channel balance
+//	@Description	Updates the balance for a single channel
+//	@Tags			channel
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id	path		int	true	"Channel ID"
+//	@Success		200	{object}	middleware.APIResponse{data=float64}
+//	@Router			/api/channel/{id}/balance [get]
 func UpdateChannelBalance(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
@@ -69,11 +76,7 @@ func UpdateChannelBalance(c *gin.Context) {
 		})
 		return
 	}
-	c.JSON(http.StatusOK, middleware.APIResponse{
-		Success: true,
-		Message: "",
-		Data:    balance,
-	})
+	middleware.SuccessResponse(c, balance)
 }
 
 func updateAllChannelsBalance() error {
@@ -105,6 +108,15 @@ func updateAllChannelsBalance() error {
 	return nil
 }
 
+// UpdateAllChannelsBalance godoc
+//
+//	@Summary		Update all channels balance
+//	@Description	Updates the balance for all channels
+//	@Tags			channel
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse
+//	@Router			/api/channels/balance [get]
 func UpdateAllChannelsBalance(c *gin.Context) {
 	err := updateAllChannelsBalance()
 	if err != nil {
@@ -120,33 +132,3 @@ func UpdateChannelsBalance(frequency time.Duration) {
 		_ = updateAllChannelsBalance()
 	}
 }
-
-// subscription
-func GetSubscription(c *gin.Context) {
-	group := middleware.GetGroup(c)
-	b, _, err := balance.GetGroupRemainBalance(c, *group)
-	if err != nil {
-		if errors.Is(err, balance.ErrNoRealNameUsedAmountLimit) {
-			middleware.ErrorResponse(c, http.StatusForbidden, err.Error())
-			return
-		}
-		log.Errorf("get group (%s) balance failed: %s", group.ID, err)
-		middleware.ErrorResponse(c, http.StatusInternalServerError, fmt.Sprintf("get group (%s) balance failed", group.ID))
-		return
-	}
-	token := middleware.GetToken(c)
-	quota := token.Quota
-	if quota <= 0 {
-		quota = b
-	}
-	c.JSON(http.StatusOK, openai.SubscriptionResponse{
-		HardLimitUSD:       quota + token.UsedAmount,
-		SoftLimitUSD:       b,
-		SystemHardLimitUSD: quota + token.UsedAmount,
-	})
-}
-
-func GetUsage(c *gin.Context) {
-	token := middleware.GetToken(c)
-	c.JSON(http.StatusOK, openai.UsageResponse{TotalUsage: token.UsedAmount * 100})
-}

+ 45 - 13
controller/channel-test.go

@@ -25,7 +25,7 @@ import (
 	"github.com/labring/aiproxy/monitor"
 	"github.com/labring/aiproxy/relay/channeltype"
 	"github.com/labring/aiproxy/relay/meta"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 	"github.com/labring/aiproxy/relay/utils"
 	log "github.com/sirupsen/logrus"
 )
@@ -60,7 +60,7 @@ func testSingleModel(mc *model.ModelCaches, channel *model.Channel, modelName st
 	if !ok {
 		return nil, errors.New(modelName + " model config not found")
 	}
-	if modelConfig.Type == relaymode.Unknown {
+	if modelConfig.Type == mode.Unknown {
 		newModelConfig := guessModelConfig(modelName)
 		if newModelConfig != nil {
 			modelConfig = newModelConfig
@@ -81,7 +81,7 @@ func testSingleModel(mc *model.ModelCaches, channel *model.Channel, modelName st
 		}, nil
 	}
 
-	body, mode, err := utils.BuildRequest(modelConfig)
+	body, m, err := utils.BuildRequest(modelConfig)
 	if err != nil {
 		return nil, err
 	}
@@ -97,14 +97,14 @@ func testSingleModel(mc *model.ModelCaches, channel *model.Channel, modelName st
 
 	meta := meta.NewMeta(
 		channel,
-		mode,
+		m,
 		modelName,
 		modelConfig,
 		meta.WithRequestID(channelTestRequestID),
 	)
-	relayController, ok := relayController(mode)
+	relayController, ok := relayController(m)
 	if !ok {
-		return nil, fmt.Errorf("relay mode %d not implemented", mode)
+		return nil, fmt.Errorf("relay mode %d not implemented", m)
 	}
 	result := relayController(meta, newc)
 	success := result.Error == nil
@@ -112,8 +112,8 @@ func testSingleModel(mc *model.ModelCaches, channel *model.Channel, modelName st
 	var code int
 	if success {
 		switch meta.Mode {
-		case relaymode.AudioSpeech,
-			relaymode.ImagesGenerations:
+		case mode.AudioSpeech,
+			mode.ImagesGenerations:
 			respStr = ""
 		default:
 			respStr = w.Body.String()
@@ -136,6 +136,18 @@ func testSingleModel(mc *model.ModelCaches, channel *model.Channel, modelName st
 	)
 }
 
+// TestChannel godoc
+//
+//	@Summary		Test channel model
+//	@Description	Tests a single model in the channel
+//	@Tags			channel
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id		path		int		true	"Channel ID"
+//	@Param			model	path		string	true	"Model name"
+//	@Success		200		{object}	middleware.APIResponse{data=model.ChannelTest}
+//	@Router			/api/channel/{id}/{model} [get]
+//
 //nolint:goconst
 func TestChannel(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
@@ -193,13 +205,13 @@ func TestChannel(c *gin.Context) {
 	})
 }
 
-type testResult struct {
+type TestResult struct {
 	Data    *model.ChannelTest `json:"data,omitempty"`
 	Message string             `json:"message,omitempty"`
 	Success bool               `json:"success"`
 }
 
-func processTestResult(mc *model.ModelCaches, channel *model.Channel, modelName string, returnSuccess bool, successResponseBody bool) *testResult {
+func processTestResult(mc *model.ModelCaches, channel *model.Channel, modelName string, returnSuccess bool, successResponseBody bool) *TestResult {
 	ct, err := testSingleModel(mc, channel, modelName)
 
 	e := &utils.UnsupportedModelTypeError{}
@@ -208,7 +220,7 @@ func processTestResult(mc *model.ModelCaches, channel *model.Channel, modelName
 		return nil
 	}
 
-	result := &testResult{
+	result := &TestResult{
 		Success: err == nil,
 	}
 	if err != nil {
@@ -232,6 +244,16 @@ func processTestResult(mc *model.ModelCaches, channel *model.Channel, modelName
 	return result
 }
 
+// TestChannelModels godoc
+//
+//	@Summary		Test channel models
+//	@Description	Tests all models in the channel
+//	@Tags			channel
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id	path		int	true	"Channel ID"
+//	@Success		200	{object}	middleware.APIResponse{data=[]TestResult}
+//	@Router			/api/channel/{id}/models [get]
 func TestChannelModels(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
@@ -259,7 +281,7 @@ func TestChannelModels(c *gin.Context) {
 		common.SetEventStreamHeaders(c)
 	}
 
-	results := make([]*testResult, 0)
+	results := make([]*TestResult, 0)
 	resultsMutex := sync.Mutex{}
 	hasError := atomic.Bool{}
 
@@ -318,6 +340,16 @@ func TestChannelModels(c *gin.Context) {
 	}
 }
 
+// TestAllChannels godoc
+//
+//	@Summary		Test all channels
+//	@Description	Tests all channels
+//	@Tags			channel
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=[]TestResult}
+//
+// @Router			/api/channels/test [get]
 func TestAllChannels(c *gin.Context) {
 	testDisabled := c.Query("test_disabled") == "true"
 	var channels []*model.Channel
@@ -342,7 +374,7 @@ func TestAllChannels(c *gin.Context) {
 		common.SetEventStreamHeaders(c)
 	}
 
-	results := make([]*testResult, 0)
+	results := make([]*TestResult, 0)
 	resultsMutex := sync.Mutex{}
 	hasErrorMap := make(map[int]*atomic.Bool)
 

+ 141 - 1
controller/channel.go

@@ -17,14 +17,49 @@ import (
 	log "github.com/sirupsen/logrus"
 )
 
+// ChannelTypeNames godoc
+//
+//	@Summary		Get all channel type names
+//	@Description	Returns a list of all available channel type names
+//	@Tags			channels
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=map[int]string}
+//	@Router			/api/channels/type_names [get]
 func ChannelTypeNames(c *gin.Context) {
 	middleware.SuccessResponse(c, channeltype.ChannelNames)
 }
 
+// ChannelTypeMetas godoc
+//
+//	@Summary		Get channel type metadata
+//	@Description	Returns metadata for all channel types
+//	@Tags			channels
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=map[int]channeltype.AdaptorMeta}
+//	@Router			/api/channels/type_metas [get]
 func ChannelTypeMetas(c *gin.Context) {
 	middleware.SuccessResponse(c, channeltype.ChannelMetas)
 }
 
+// GetChannels godoc
+//
+//	@Summary		Get channels with pagination
+//	@Description	Returns a paginated list of channels with optional filters
+//	@Tags			channels
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			page			query		int		false	"Page number"
+//	@Param			per_page		query		int		false	"Items per page"
+//	@Param			id				query		int		false	"Filter by id"
+//	@Param			name			query		string	false	"Filter by name"
+//	@Param			key				query		string	false	"Filter by key"
+//	@Param			channel_type	query		int		false	"Filter by channel type"
+//	@Param			base_url		query		string	false	"Filter by base URL"
+//	@Param			order			query		string	false	"Order by field"
+//	@Success		200				{object}	middleware.APIResponse{data=map[string]any{channels=[]model.Channel,total=int}}
+//	@Router			/api/channels [get]
 func GetChannels(c *gin.Context) {
 	page, perPage := parsePageParams(c)
 	id, _ := strconv.Atoi(c.Query("id"))
@@ -44,6 +79,15 @@ func GetChannels(c *gin.Context) {
 	})
 }
 
+// GetAllChannels godoc
+//
+//	@Summary		Get all channels
+//	@Description	Returns a list of all channels without pagination
+//	@Tags			channels
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=[]model.Channel}
+//	@Router			/api/channels/all [get]
 func GetAllChannels(c *gin.Context) {
 	channels, err := model.GetAllChannels()
 	if err != nil {
@@ -53,6 +97,17 @@ func GetAllChannels(c *gin.Context) {
 	middleware.SuccessResponse(c, channels)
 }
 
+// AddChannels godoc
+//
+//	@Summary		Add multiple channels
+//	@Description	Adds multiple channels in a batch operation
+//	@Tags			channels
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			channels	body		[]AddChannelRequest	true	"Channel information"
+//	@Success		200			{object}	middleware.APIResponse
+//	@Router			/api/channels [post]
 func AddChannels(c *gin.Context) {
 	channels := make([]*AddChannelRequest, 0)
 	err := c.ShouldBindJSON(&channels)
@@ -77,6 +132,24 @@ func AddChannels(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// SearchChannels godoc
+//
+//	@Summary		Search channels
+//	@Description	Search channels with keyword and optional filters
+//	@Tags			channels
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			keyword			query		string	true	"Search keyword"
+//	@Param			page			query		int		false	"Page number"
+//	@Param			per_page		query		int		false	"Items per page"
+//	@Param			id				query		int		false	"Filter by id"
+//	@Param			name			query		string	false	"Filter by name"
+//	@Param			key				query		string	false	"Filter by key"
+//	@Param			channel_type	query		int		false	"Filter by channel type"
+//	@Param			base_url		query		string	false	"Filter by base URL"
+//	@Param			order			query		string	false	"Order by field"
+//	@Success		200				{object}	middleware.APIResponse{data=map[string]any{channels=[]model.Channel,total=int}}
+//	@Router			/api/channels/search [get]
 func SearchChannels(c *gin.Context) {
 	keyword := c.Query("keyword")
 	page, perPage := parsePageParams(c)
@@ -97,6 +170,16 @@ func SearchChannels(c *gin.Context) {
 	})
 }
 
+// GetChannel godoc
+//
+//	@Summary		Get a channel by ID
+//	@Description	Returns detailed information about a specific channel
+//	@Tags			channel
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id	path		int	true	"Channel ID"
+//	@Success		200	{object}	middleware.APIResponse{data=model.Channel}
+//	@Router			/api/channel/{id} [get]
 func GetChannel(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
@@ -111,13 +194,13 @@ func GetChannel(c *gin.Context) {
 	middleware.SuccessResponse(c, channel)
 }
 
+// AddChannelRequest represents the request body for adding a channel
 type AddChannelRequest struct {
 	ModelMapping map[string]string    `json:"model_mapping"`
 	Config       *model.ChannelConfig `json:"config"`
 	Name         string               `json:"name"`
 	Key          string               `json:"key"`
 	BaseURL      string               `json:"base_url"`
-	Other        string               `json:"other"`
 	Models       []string             `json:"models"`
 	Type         int                  `json:"type"`
 	Priority     int32                `json:"priority"`
@@ -176,6 +259,17 @@ func (r *AddChannelRequest) ToChannels() ([]*model.Channel, error) {
 	return channels, nil
 }
 
+// AddChannel godoc
+//
+//	@Summary		Add a single channel
+//	@Description	Adds a new channel to the system
+//	@Tags			channel
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			channel	body		AddChannelRequest	true	"Channel information"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/channel [post]
 func AddChannel(c *gin.Context) {
 	channel := AddChannelRequest{}
 	err := c.ShouldBindJSON(&channel)
@@ -196,6 +290,16 @@ func AddChannel(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// DeleteChannel godoc
+//
+//	@Summary		Delete a channel
+//	@Description	Deletes a channel by its ID
+//	@Tags			channel
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id	path		int	true	"Channel ID"
+//	@Success		200	{object}	middleware.APIResponse
+//	@Router			/api/channel/{id} [delete]
 func DeleteChannel(c *gin.Context) {
 	id, _ := strconv.Atoi(c.Param("id"))
 	err := model.DeleteChannelByID(id)
@@ -206,6 +310,17 @@ func DeleteChannel(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// DeleteChannels godoc
+//
+//	@Summary		Delete multiple channels
+//	@Description	Deletes multiple channels by their IDs
+//	@Tags			channels
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			ids	body		[]int	true	"Channel IDs"
+//	@Success		200	{object}	middleware.APIResponse
+//	@Router			/api/channels/batch_delete [post]
 func DeleteChannels(c *gin.Context) {
 	ids := []int{}
 	err := c.ShouldBindJSON(&ids)
@@ -221,6 +336,18 @@ func DeleteChannels(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// UpdateChannel godoc
+//
+//	@Summary		Update a channel
+//	@Description	Updates an existing channel by its ID
+//	@Tags			channel
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id		path		int					true	"Channel ID"
+//	@Param			channel	body		AddChannelRequest	true	"Updated channel information"
+//	@Success		200		{object}	middleware.APIResponse{data=model.Channel}
+//	@Router			/api/channel/{id} [put]
 func UpdateChannel(c *gin.Context) {
 	idStr := c.Param("id")
 	if idStr == "" {
@@ -256,10 +383,23 @@ func UpdateChannel(c *gin.Context) {
 	middleware.SuccessResponse(c, ch)
 }
 
+// UpdateChannelStatusRequest represents the request body for updating a channel's status
 type UpdateChannelStatusRequest struct {
 	Status int `json:"status"`
 }
 
+// UpdateChannelStatus godoc
+//
+//	@Summary		Update channel status
+//	@Description	Updates the status of a channel by its ID
+//	@Tags			channel
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id		path		int							true	"Channel ID"
+//	@Param			status	body		UpdateChannelStatusRequest	true	"Status information"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/channel/{id}/status [post]
 func UpdateChannelStatus(c *gin.Context) {
 	id, _ := strconv.Atoi(c.Param("id"))
 	status := UpdateChannelStatusRequest{}

+ 48 - 0
controller/dashboard.go

@@ -125,6 +125,15 @@ func fillGaps(data []*model.ChartData, start, end time.Time, t model.TimeSpanTyp
 	return result
 }
 
+// GetDashboard godoc
+//
+//	@Summary		Get dashboard data
+//	@Description	Returns the general dashboard data including usage statistics and metrics
+//	@Tags			dashboard
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=model.DashboardResponse}
+//	@Router			/api/dashboard [get]
 func GetDashboard(c *gin.Context) {
 	log := middleware.GetLogger(c)
 
@@ -152,6 +161,16 @@ func GetDashboard(c *gin.Context) {
 	middleware.SuccessResponse(c, dashboards)
 }
 
+// GetGroupDashboard godoc
+//
+//	@Summary		Get dashboard data for a specific group
+//	@Description	Returns dashboard data and metrics specific to the given group
+//	@Tags			dashboard
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name or ID"
+//	@Success		200		{object}	middleware.APIResponse{data=model.GroupDashboardResponse}
+//	@Router			/api/dashboard/{group} [get]
 func GetGroupDashboard(c *gin.Context) {
 	log := middleware.GetLogger(c)
 
@@ -186,6 +205,16 @@ func GetGroupDashboard(c *gin.Context) {
 	middleware.SuccessResponse(c, dashboards)
 }
 
+// GetGroupDashboardModels godoc
+//
+//	@Summary		Get model usage data for a specific group
+//	@Description	Returns model-specific metrics and usage data for the given group
+//	@Tags			dashboard
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name or ID"
+//	@Success		200		{object}	middleware.APIResponse{data=[]model.ModelConfig}
+//	@Router			/api/dashboard/{group}/models [get]
 func GetGroupDashboardModels(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -210,6 +239,15 @@ func GetGroupDashboardModels(c *gin.Context) {
 	middleware.SuccessResponse(c, newEnabledModelConfigs)
 }
 
+// GetModelCostRank godoc
+//
+//	@Summary		Get model cost ranking data
+//	@Description	Returns ranking data for models based on cost
+//	@Tags			dashboard
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=[]model.ModelCostRank}
+//	@Router			/api/model_cost_rank [get]
 func GetModelCostRank(c *gin.Context) {
 	startTime, endTime := parseTimeRange(c)
 	models, err := model.GetModelCostRank("", startTime, endTime)
@@ -220,6 +258,16 @@ func GetModelCostRank(c *gin.Context) {
 	middleware.SuccessResponse(c, models)
 }
 
+// GetGroupModelCostRank godoc
+//
+//	@Summary		Get model cost ranking data for a specific group
+//	@Description	Returns model cost ranking data specific to the given group
+//	@Tags			dashboard
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name or ID"
+//	@Success		200		{object}	middleware.APIResponse{data=[]model.ModelCostRank}
+//	@Router			/api/model_cost_rank/{group} [get]
 func GetGroupModelCostRank(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {

+ 146 - 6
controller/group.go

@@ -29,6 +29,17 @@ func (g *GroupResponse) MarshalJSON() ([]byte, error) {
 	})
 }
 
+// GetGroups godoc
+//
+//	@Summary		Get all groups
+//	@Description	Returns a list of all groups with pagination
+//	@Tags			groups
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			page		query		int	false	"Page number"
+//	@Param			per_page	query		int	false	"Items per page"
+//	@Success		200			{object}	middleware.APIResponse{data=map[string]any{groups=[]GroupResponse,total=int}}
+//	@Router			/api/groups [get]
 func GetGroups(c *gin.Context) {
 	page, perPage := parsePageParams(c)
 	order := c.DefaultQuery("order", "")
@@ -51,6 +62,18 @@ func GetGroups(c *gin.Context) {
 	})
 }
 
+// SearchGroups godoc
+//
+//	@Summary		Search groups
+//	@Description	Search groups with keyword and pagination
+//	@Tags			groups
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			keyword		query		string	true	"Search keyword"
+//	@Param			page		query		int		false	"Page number"
+//	@Param			per_page	query		int		false	"Items per page"
+//	@Success		200			{object}	middleware.APIResponse{data=map[string]any{groups=[]GroupResponse,total=int}}
+//	@Router			/api/groups/search [get]
 func SearchGroups(c *gin.Context) {
 	keyword := c.Query("keyword")
 	page, perPage := parsePageParams(c)
@@ -75,6 +98,16 @@ func SearchGroups(c *gin.Context) {
 	})
 }
 
+// GetGroup godoc
+//
+//	@Summary		Get a group
+//	@Description	Returns detailed information about a specific group
+//	@Tags			group
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Success		200		{object}	middleware.APIResponse{data=GroupResponse}
+//	@Router			/api/group/{group} [get]
 func GetGroup(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -98,6 +131,18 @@ type UpdateGroupRPMRatioRequest struct {
 	RPMRatio float64 `json:"rpm_ratio"`
 }
 
+// UpdateGroupRPMRatio godoc
+//
+//	@Summary		Update group RPM ratio
+//	@Description	Updates the RPM (Requests Per Minute) ratio for a group
+//	@Tags			group
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Param			data	body		object	true	"RPM ratio information"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/group/{group}/rpm_ratio [post]
 func UpdateGroupRPMRatio(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -122,6 +167,18 @@ type UpdateGroupRPMRequest struct {
 	RPM map[string]int64 `json:"rpm"`
 }
 
+// UpdateGroupRPM godoc
+//
+//	@Summary		Update group RPM
+//	@Description	Updates the RPM (Requests Per Minute) for a group
+//	@Tags			group
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Param			data	body		object	true	"RPM information"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/group/{group}/rpm [post]
 func UpdateGroupRPM(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -146,6 +203,18 @@ type UpdateGroupTPMRequest struct {
 	TPM map[string]int64 `json:"tpm"`
 }
 
+// UpdateGroupTPM godoc
+//
+//	@Summary		Update group TPM
+//	@Description	Updates the TPM (Tokens Per Minute) for a group
+//	@Tags			group
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Param			data	body		object	true	"TPM information"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/group/{group}/tpm [post]
 func UpdateGroupTPM(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -170,6 +239,18 @@ type UpdateGroupTPMRatioRequest struct {
 	TPMRatio float64 `json:"tpm_ratio"`
 }
 
+// UpdateGroupTPMRatio godoc
+//
+//	@Summary		Update group TPM ratio
+//	@Description	Updates the TPM (Tokens Per Minute) ratio for a group
+//	@Tags			group
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Param			data	body		object	true	"TPM ratio information"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/group/{group}/tpm_ratio [post]
 func UpdateGroupTPMRatio(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -194,6 +275,18 @@ type UpdateGroupStatusRequest struct {
 	Status int `json:"status"`
 }
 
+// UpdateGroupStatus godoc
+//
+//	@Summary		Update group status
+//	@Description	Updates the status of a group
+//	@Tags			group
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Param			status	body		object	true	"Status information"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/group/{group}/status [post]
 func UpdateGroupStatus(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -214,6 +307,16 @@ func UpdateGroupStatus(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// DeleteGroup godoc
+//
+//	@Summary		Delete a group
+//	@Description	Deletes a group by its name
+//	@Tags			group
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/group/{group} [delete]
 func DeleteGroup(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -228,6 +331,17 @@ func DeleteGroup(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// DeleteGroups godoc
+//
+//	@Summary		Delete multiple groups
+//	@Description	Deletes multiple groups by their IDs
+//	@Tags			groups
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			ids	body		[]string	true	"Group IDs"
+//	@Success		200	{object}	middleware.APIResponse
+//	@Router			/api/groups/batch_delete [post]
 func DeleteGroups(c *gin.Context) {
 	ids := []string{}
 	err := c.ShouldBindJSON(&ids)
@@ -250,6 +364,18 @@ type CreateGroupRequest struct {
 	TPMRatio float64          `json:"tpm_ratio"`
 }
 
+// CreateGroup godoc
+//
+//	@Summary		Create a new group
+//	@Description	Creates a new group with the given information
+//	@Tags			group
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Param			data	body		object	true	"Group information"
+//	@Success		200		{object}	middleware.APIResponse{data=model.Group}
+//	@Router			/api/group/{group} [post]
 func CreateGroup(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -262,19 +388,32 @@ func CreateGroup(c *gin.Context) {
 		middleware.ErrorResponse(c, http.StatusOK, "invalid parameter")
 		return
 	}
-	if err := model.CreateGroup(&model.Group{
+	g := &model.Group{
 		ID:       group,
 		RPMRatio: req.RPMRatio,
 		RPM:      req.RPM,
 		TPMRatio: req.TPMRatio,
 		TPM:      req.TPM,
-	}); err != nil {
+	}
+	if err := model.CreateGroup(g); err != nil {
 		middleware.ErrorResponse(c, http.StatusOK, err.Error())
 		return
 	}
-	middleware.SuccessResponse(c, nil)
+	middleware.SuccessResponse(c, g)
 }
 
+// UpdateGroup godoc
+//
+//	@Summary		Update a group
+//	@Description	Updates an existing group with the given information
+//	@Tags			group
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Param			data	body		object	true	"Updated group information"
+//	@Success		200		{object}	middleware.APIResponse{data=model.Group}
+//	@Router			/api/group/{group} [put]
 func UpdateGroup(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -287,15 +426,16 @@ func UpdateGroup(c *gin.Context) {
 		middleware.ErrorResponse(c, http.StatusOK, "invalid parameter")
 		return
 	}
-	err = model.UpdateGroup(group, &model.Group{
+	g := &model.Group{
 		RPMRatio: req.RPMRatio,
 		RPM:      req.RPM,
 		TPMRatio: req.TPMRatio,
 		TPM:      req.TPM,
-	})
+	}
+	err = model.UpdateGroup(group, g)
 	if err != nil {
 		middleware.ErrorResponse(c, http.StatusOK, err.Error())
 		return
 	}
-	middleware.SuccessResponse(c, nil)
+	middleware.SuccessResponse(c, g)
 }

+ 10 - 0
controller/import.go

@@ -159,6 +159,16 @@ func AddOneAPIChannel(ch OneAPIChannel) error {
 	return model.BatchInsertChannels(chs)
 }
 
+// ImportChannelFromOneAPI godoc
+//
+//	@Summary		Import channel from OneAPI
+//	@Description	Imports channels from OneAPI
+//	@Tags			channels
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			request	body		ImportChannelFromOneAPIRequest	true	"Import channel from OneAPI request"
+//	@Success		200		{object}	middleware.APIResponse{data=[]error}
+//	@Router			/api/channels/import/oneapi [post]
 func ImportChannelFromOneAPI(c *gin.Context) {
 	var req ImportChannelFromOneAPIRequest
 	if err := c.ShouldBindJSON(&req); err != nil {

+ 132 - 1
controller/log.go

@@ -58,7 +58,19 @@ func parseCommonParams(c *gin.Context) (params struct {
 	return
 }
 
-// Handler functions
+// GetLogs godoc
+//
+//	@Summary		Get all logs
+//	@Description	Returns a paginated list of all logs with optional filters
+//	@Tags			logs
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			page		query		int	false	"Page number"
+//	@Param			per_page	query		int	false	"Items per page"
+//	@Param			start_time	query		int	false	"Start timestamp (milliseconds)"
+//	@Param			end_time	query		int	false	"End timestamp (milliseconds)"
+//	@Success		200			{object}	middleware.APIResponse{data=model.GetLogsResult}
+//	@Router			/api/logs [get]
 func GetLogs(c *gin.Context) {
 	page, perPage := parsePageParams(c)
 	startTime, endTime := parseTimeRange(c)
@@ -91,6 +103,20 @@ func GetLogs(c *gin.Context) {
 	middleware.SuccessResponse(c, result)
 }
 
+// GetGroupLogs godoc
+//
+//	@Summary		Get group logs
+//	@Description	Get logs for a specific group
+//	@Tags			log
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group		path		string	true	"Group name"
+//	@Param			page		query		int		false	"Page number"
+//	@Param			per_page	query		int		false	"Items per page"
+//	@Param			start_time	query		int		false	"Start timestamp (milliseconds)"
+//	@Param			end_time	query		int		false	"End timestamp (milliseconds)"
+//	@Success		200			{object}	middleware.APIResponse{data=model.GetGroupLogsResult}
+//	@Router			/api/log/{group} [get]
 func GetGroupLogs(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -128,6 +154,22 @@ func GetGroupLogs(c *gin.Context) {
 	middleware.SuccessResponse(c, result)
 }
 
+// SearchLogs godoc
+//
+//	@Summary		Search logs
+//	@Description	Search logs with various filters
+//	@Tags			logs
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			page		query		int		false	"Page number"
+//	@Param			per_page	query		int		false	"Items per page"
+//	@Param			start_time	query		int		false	"Start timestamp (milliseconds)"
+//	@Param			end_time	query		int		false	"End timestamp (milliseconds)"
+//	@Param			token_name	query		string	false	"Filter by token name"
+//	@Param			model		query		string	false	"Filter by model name"
+//	@Param			status		query		int		false	"Filter by status"
+//	@Success		200			{object}	middleware.APIResponse{data=model.GetLogsResult}
+//	@Router			/api/logs/search [get]
 func SearchLogs(c *gin.Context) {
 	page, perPage := parsePageParams(c)
 	startTime, endTime := parseTimeRange(c)
@@ -163,6 +205,23 @@ func SearchLogs(c *gin.Context) {
 	middleware.SuccessResponse(c, result)
 }
 
+// SearchGroupLogs godoc
+//
+//	@Summary		Search group logs
+//	@Description	Search logs for a specific group with filters
+//	@Tags			log
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group		path		string	true	"Group name"
+//	@Param			page		query		int		false	"Page number"
+//	@Param			per_page	query		int		false	"Items per page"
+//	@Param			start_time	query		int		false	"Start timestamp (milliseconds)"
+//	@Param			end_time	query		int		false	"End timestamp (milliseconds)"
+//	@Param			token_name	query		string	false	"Filter by token name"
+//	@Param			model		query		string	false	"Filter by model name"
+//	@Param			status		query		int		false	"Filter by status"
+//	@Success		200			{object}	middleware.APIResponse{data=model.GetGroupLogsResult}
+//	@Router			/api/log/{group}/search [get]
 func SearchGroupLogs(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -202,6 +261,16 @@ func SearchGroupLogs(c *gin.Context) {
 	middleware.SuccessResponse(c, result)
 }
 
+// GetLogDetail godoc
+//
+//	@Summary		Get log detail
+//	@Description	Get detailed information about a specific log entry
+//	@Tags			logs
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			log_id	path		string	true	"Log ID"
+//	@Success		200		{object}	middleware.APIResponse{data=model.RequestDetail}
+//	@Router			/api/logs/detail/{log_id} [get]
 func GetLogDetail(c *gin.Context) {
 	logID, _ := strconv.Atoi(c.Param("log_id"))
 	log, err := model.GetLogDetail(logID)
@@ -212,6 +281,15 @@ func GetLogDetail(c *gin.Context) {
 	middleware.SuccessResponse(c, log)
 }
 
+// GetUsedModels godoc
+//
+//	@Summary		Get used models
+//	@Description	Get a list of models that have been used in logs
+//	@Tags			logs
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=[]string}
+//	@Router			/api/logs/used/models [get]
 func GetUsedModels(c *gin.Context) {
 	startTime, endTime := parseTimeRange(c)
 	models, err := model.GetUsedModels("", startTime, endTime)
@@ -222,6 +300,17 @@ func GetUsedModels(c *gin.Context) {
 	middleware.SuccessResponse(c, models)
 }
 
+// GetGroupLogDetail godoc
+//
+//	@Summary		Get group log detail
+//	@Description	Get detailed information about a specific log entry in a group
+//	@Tags			log
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Param			log_id	path		string	true	"Log ID"
+//	@Success		200		{object}	middleware.APIResponse{data=model.RequestDetail}
+//	@Router			/api/log/{group}/detail/{log_id} [get]
 func GetGroupLogDetail(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -237,6 +326,16 @@ func GetGroupLogDetail(c *gin.Context) {
 	middleware.SuccessResponse(c, log)
 }
 
+// GetGroupUsedModels godoc
+//
+//	@Summary		Get group used models
+//	@Description	Get a list of models that have been used in a specific group's logs
+//	@Tags			log
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Success		200		{object}	middleware.APIResponse{data=[]string}
+//	@Router			/api/log/{group}/used/models [get]
 func GetGroupUsedModels(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -252,6 +351,16 @@ func GetGroupUsedModels(c *gin.Context) {
 	middleware.SuccessResponse(c, models)
 }
 
+// GetGroupUsedTokenNames godoc
+//
+//	@Summary		Get group used token names
+//	@Description	Get a list of token names that have been used in a specific group's logs
+//	@Tags			log
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Success		200		{object}	middleware.APIResponse{data=[]string}
+//	@Router			/api/log/{group}/used/token_names [get]
 func GetGroupUsedTokenNames(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -267,6 +376,15 @@ func GetGroupUsedTokenNames(c *gin.Context) {
 	middleware.SuccessResponse(c, tokenNames)
 }
 
+// DeleteHistoryLogs godoc
+//
+//	@Summary		Delete historical logs
+//	@Description	Deletes logs older than the specified retention period
+//	@Tags			logs
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=int}
+//	@Router			/api/logs [delete]
 func DeleteHistoryLogs(c *gin.Context) {
 	timestamp, _ := strconv.ParseInt(c.Query("timestamp"), 10, 64)
 	if timestamp == 0 {
@@ -281,6 +399,19 @@ func DeleteHistoryLogs(c *gin.Context) {
 	middleware.SuccessResponse(c, count)
 }
 
+// SearchConsumeError godoc
+//
+//	@Summary		Search consumption errors
+//	@Description	Search for logs with consumption errors
+//	@Tags			logs
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			page		query		int	false	"Page number"
+//	@Param			per_page	query		int	false	"Items per page"
+//	@Param			start_time	query		int	false	"Start timestamp (milliseconds)"
+//	@Param			end_time	query		int	false	"End timestamp (milliseconds)"
+//	@Success		200			{object}	middleware.APIResponse{data=map[string]any{logs=[]model.RequestDetail,total=int}}
+//	@Router			/api/logs/consume_error [get]
 func SearchConsumeError(c *gin.Context) {
 	keyword := c.Query("keyword")
 	group := c.Query("group")

+ 8 - 0
controller/misc.go

@@ -10,6 +10,14 @@ type StatusData struct {
 	StartTime int64 `json:"startTime"`
 }
 
+// GetStatus godoc
+//
+//	@Summary		Get status
+//	@Description	Returns the status of the server
+//	@Tags			misc
+//	@Produce		json
+//	@Success		200	{object}	middleware.APIResponse{data=StatusData}
+//	@Router			/api/status [get]
 func GetStatus(c *gin.Context) {
 	middleware.SuccessResponse(c, &StatusData{
 		StartTime: common.StartTime,

+ 75 - 61
controller/model.go

@@ -1,7 +1,6 @@
 package controller
 
 import (
-	"fmt"
 	"net/http"
 	"slices"
 	"sort"
@@ -13,7 +12,6 @@ import (
 	"github.com/labring/aiproxy/middleware"
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/channeltype"
-	relaymodel "github.com/labring/aiproxy/relay/model"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -121,14 +119,42 @@ func init() {
 	slices.SortStableFunc(builtinModels, SortBuiltinModelConfigsFunc)
 }
 
+// BuiltinModels godoc
+//
+//	@Summary		Get builtin models
+//	@Description	Returns a list of builtin models
+//	@Tags			model
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=[]BuiltinModelConfig}
+//	@Router			/api/models/builtin [get]
 func BuiltinModels(c *gin.Context) {
 	middleware.SuccessResponse(c, builtinModels)
 }
 
+// ChannelBuiltinModels godoc
+//
+//	@Summary		Get channel builtin models
+//	@Description	Returns a list of channel builtin models
+//	@Tags			model
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=map[int][]BuiltinModelConfig}
+//	@Router			/api/models/builtin/channel [get]
 func ChannelBuiltinModels(c *gin.Context) {
 	middleware.SuccessResponse(c, builtinChannelID2Models)
 }
 
+// ChannelBuiltinModelsByType godoc
+//
+//	@Summary		Get channel builtin models by type
+//	@Description	Returns a list of channel builtin models by type
+//	@Tags			model
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			type	path		string	true	"Channel type"
+//	@Success		200		{object}	middleware.APIResponse{data=[]BuiltinModelConfig}
+//	@Router			/api/models/builtin/channel/{type} [get]
 func ChannelBuiltinModelsByType(c *gin.Context) {
 	channelType := c.Param("type")
 	if channelType == "" {
@@ -143,6 +169,15 @@ func ChannelBuiltinModelsByType(c *gin.Context) {
 	middleware.SuccessResponse(c, builtinChannelID2Models[channelTypeInt])
 }
 
+// ChannelDefaultModelsAndMapping godoc
+//
+//	@Summary		Get channel default models and mapping
+//	@Description	Returns a list of channel default models and mapping
+//	@Tags			model
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=map[string]any{models=[]string,mapping=map[string]string}}
+//	@Router			/api/models/default [get]
 func ChannelDefaultModelsAndMapping(c *gin.Context) {
 	middleware.SuccessResponse(c, gin.H{
 		"models":  config.GetDefaultChannelModels(),
@@ -150,6 +185,16 @@ func ChannelDefaultModelsAndMapping(c *gin.Context) {
 	})
 }
 
+// ChannelDefaultModelsAndMappingByType godoc
+//
+//	@Summary		Get channel default models and mapping by type
+//	@Description	Returns a list of channel default models and mapping by type
+//	@Tags			model
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			type	path		string	true	"Channel type"
+//	@Success		200		{object}	middleware.APIResponse{data=map[string]any{models=[]string,mapping=map[string]string}}
+//	@Router			/api/models/default/{type} [get]
 func ChannelDefaultModelsAndMappingByType(c *gin.Context) {
 	channelType := c.Param("type")
 	if channelType == "" {
@@ -167,14 +212,42 @@ func ChannelDefaultModelsAndMappingByType(c *gin.Context) {
 	})
 }
 
+// EnabledModels godoc
+//
+//	@Summary		Get enabled models
+//	@Description	Returns a list of enabled models
+//	@Tags			model
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=[]model.ModelConfig}
+//	@Router			/api/models/enabled [get]
 func EnabledModels(c *gin.Context) {
 	middleware.SuccessResponse(c, model.LoadModelCaches().EnabledModelConfigs)
 }
 
+// ChannelEnabledModels godoc
+//
+//	@Summary		Get channel enabled models
+//	@Description	Returns a list of channel enabled models
+//	@Tags			model
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=map[int][]model.ModelConfig}
+//	@Router			/api/models/enabled/channel [get]
 func ChannelEnabledModels(c *gin.Context) {
 	middleware.SuccessResponse(c, model.LoadModelCaches().EnabledChannelType2ModelConfigs)
 }
 
+// ChannelEnabledModelsByType godoc
+//
+//	@Summary		Get channel enabled models by type
+//	@Description	Returns a list of channel enabled models by type
+//	@Tags			model
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			type	path		string	true	"Channel type"
+//	@Success		200		{object}	middleware.APIResponse{data=[]model.ModelConfig}
+//	@Router			/api/models/enabled/channel/{type} [get]
 func ChannelEnabledModelsByType(c *gin.Context) {
 	channelTypeStr := c.Param("type")
 	if channelTypeStr == "" {
@@ -188,62 +261,3 @@ func ChannelEnabledModelsByType(c *gin.Context) {
 	}
 	middleware.SuccessResponse(c, model.LoadModelCaches().EnabledChannelType2ModelConfigs[channelTypeInt])
 }
-
-func ListModels(c *gin.Context) {
-	enabledModelConfigsMap := middleware.GetModelCaches(c).EnabledModelConfigsMap
-	token := middleware.GetToken(c)
-
-	availableOpenAIModels := make([]*OpenAIModels, 0, len(token.Models))
-
-	for _, model := range token.Models {
-		if mc, ok := enabledModelConfigsMap[model]; ok {
-			availableOpenAIModels = append(availableOpenAIModels, &OpenAIModels{
-				ID:         model,
-				Object:     "model",
-				Created:    1626777600,
-				OwnedBy:    string(mc.Owner),
-				Root:       model,
-				Permission: permission,
-				Parent:     nil,
-			})
-		}
-	}
-
-	c.JSON(http.StatusOK, gin.H{
-		"object": "list",
-		"data":   availableOpenAIModels,
-	})
-}
-
-func RetrieveModel(c *gin.Context) {
-	modelName := c.Param("model")
-	enabledModelConfigsMap := middleware.GetModelCaches(c).EnabledModelConfigsMap
-
-	mc, ok := enabledModelConfigsMap[modelName]
-	if ok {
-		token := middleware.GetToken(c)
-		ok = slices.Contains(token.Models, modelName)
-	}
-
-	if !ok {
-		c.JSON(200, gin.H{
-			"error": &relaymodel.Error{
-				Message: fmt.Sprintf("the model '%s' does not exist", modelName),
-				Type:    "invalid_request_error",
-				Param:   "model",
-				Code:    "model_not_found",
-			},
-		})
-		return
-	}
-
-	c.JSON(200, &OpenAIModels{
-		ID:         modelName,
-		Object:     "model",
-		Created:    1626777600,
-		OwnedBy:    string(mc.Owner),
-		Root:       modelName,
-		Permission: permission,
-		Parent:     nil,
-	})
-}

+ 86 - 0
controller/modelconfig.go

@@ -8,6 +8,15 @@ import (
 	"github.com/labring/aiproxy/model"
 )
 
+// GetModelConfigs godoc
+//
+//	@Summary		Get model configs
+//	@Description	Returns a list of model configs with pagination
+//	@Tags			modelconfig
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=map[string]any{configs=[]model.ModelConfig,total=int}}
+//	@Router			/api/modelconfigs [get]
 func GetModelConfigs(c *gin.Context) {
 	page, perPage := parsePageParams(c)
 	_model := c.Query("model")
@@ -22,6 +31,15 @@ func GetModelConfigs(c *gin.Context) {
 	})
 }
 
+// GetAllModelConfigs godoc
+//
+//	@Summary		Get all model configs
+//	@Description	Returns a list of all model configs
+//	@Tags			modelconfig
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=[]model.ModelConfig}
+//	@Router			/api/modelconfigs/all [get]
 func GetAllModelConfigs(c *gin.Context) {
 	configs, err := model.GetAllModelConfigs()
 	if err != nil {
@@ -35,6 +53,15 @@ type GetModelConfigsByModelsContainsRequest struct {
 	Models []string `json:"models"`
 }
 
+// GetModelConfigsByModelsContains godoc
+//
+//	@Summary		Get model configs by models contains
+//	@Description	Returns a list of model configs by models contains
+//	@Tags			modelconfig
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=[]model.ModelConfig}
+//	@Router			/api/modelconfigs/contains [post]
 func GetModelConfigsByModelsContains(c *gin.Context) {
 	request := GetModelConfigsByModelsContainsRequest{}
 	err := c.ShouldBindJSON(&request)
@@ -50,6 +77,15 @@ func GetModelConfigsByModelsContains(c *gin.Context) {
 	middleware.SuccessResponse(c, configs)
 }
 
+// SearchModelConfigs godoc
+//
+//	@Summary		Search model configs
+//	@Description	Returns a list of model configs by keyword
+//	@Tags			modelconfig
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=map[string]any{configs=[]model.ModelConfig,total=int}}
+//	@Router			/api/modelconfigs/search [get]
 func SearchModelConfigs(c *gin.Context) {
 	keyword := c.Query("keyword")
 	page, perPage := parsePageParams(c)
@@ -72,6 +108,16 @@ type SaveModelConfigsRequest struct {
 	*model.ModelConfig
 }
 
+// SaveModelConfigs godoc
+//
+//	@Summary		Save model configs
+//	@Description	Saves a list of model configs
+//	@Tags			modelconfig
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			configs	body		[]SaveModelConfigsRequest	true	"Model configs"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/model_configs [post]
 func SaveModelConfigs(c *gin.Context) {
 	var configs []*SaveModelConfigsRequest
 	if err := c.ShouldBindJSON(&configs); err != nil {
@@ -90,6 +136,16 @@ func SaveModelConfigs(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// SaveModelConfig godoc
+//
+//	@Summary		Save model config
+//	@Description	Saves a model config
+//	@Tags			modelconfig
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			config	body		SaveModelConfigsRequest	true	"Model config"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/model_config [post]
 func SaveModelConfig(c *gin.Context) {
 	var config SaveModelConfigsRequest
 	if err := c.ShouldBindJSON(&config); err != nil {
@@ -104,6 +160,16 @@ func SaveModelConfig(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// DeleteModelConfig godoc
+//
+//	@Summary		Delete model config
+//	@Description	Deletes a model config
+//	@Tags			modelconfig
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			model	path		string	true	"Model name"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/model_config/{model} [delete]
 func DeleteModelConfig(c *gin.Context) {
 	_model := c.Param("model")
 	err := model.DeleteModelConfig(_model)
@@ -114,6 +180,16 @@ func DeleteModelConfig(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// DeleteModelConfigs godoc
+//
+//	@Summary		Delete model configs
+//	@Description	Deletes a list of model configs
+//	@Tags			modelconfig
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			models	body		[]string	true	"Model names"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/model_configs/batch_delete [post]
 func DeleteModelConfigs(c *gin.Context) {
 	models := []string{}
 	err := c.ShouldBindJSON(&models)
@@ -129,6 +205,16 @@ func DeleteModelConfigs(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// GetModelConfig godoc
+//
+//	@Summary		Get model config
+//	@Description	Returns a model config
+//	@Tags			modelconfig
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			model	path		string	true	"Model name"
+//	@Success		200		{object}	middleware.APIResponse{data=model.ModelConfig}
+//	@Router			/api/model_config/{model} [get]
 func GetModelConfig(c *gin.Context) {
 	_model := c.Param("model")
 	config, err := model.GetModelConfig(_model)

+ 74 - 7
controller/monitor.go

@@ -9,15 +9,34 @@ import (
 	"github.com/labring/aiproxy/monitor"
 )
 
+// GetAllChannelModelErrorRates godoc
+//
+//	@Summary		Get all channel model error rates
+//	@Description	Returns a list of all channel model error rates
+//	@Tags			monitor
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=map[int64]map[string]float64}
+//	@Router			/api/monitor [get]
 func GetAllChannelModelErrorRates(c *gin.Context) {
 	rates, err := monitor.GetAllChannelModelErrorRates(c.Request.Context())
 	if err != nil {
 		middleware.ErrorResponse(c, http.StatusOK, err.Error())
 		return
 	}
-	c.JSON(http.StatusOK, rates)
+	middleware.SuccessResponse(c, rates)
 }
 
+// GetChannelModelErrorRates godoc
+//
+//	@Summary		Get channel model error rates
+//	@Description	Returns a list of channel model error rates
+//	@Tags			monitor
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id	path		int	true	"Channel ID"
+//	@Success		200	{object}	middleware.APIResponse{data=[]map[string]float64}
+//	@Router			/api/monitor/{id} [get]
 func GetChannelModelErrorRates(c *gin.Context) {
 	channelID := c.Param("id")
 	channelIDInt, err := strconv.ParseInt(channelID, 10, 64)
@@ -30,18 +49,37 @@ func GetChannelModelErrorRates(c *gin.Context) {
 		middleware.ErrorResponse(c, http.StatusOK, err.Error())
 		return
 	}
-	c.JSON(http.StatusOK, rates)
+	middleware.SuccessResponse(c, rates)
 }
 
+// ClearAllModelErrors godoc
+//
+//	@Summary		Clear all model errors
+//	@Description	Clears all model errors
+//	@Tags			monitor
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		204	{object}	middleware.APIResponse
+//	@Router			/api/monitor [delete]
 func ClearAllModelErrors(c *gin.Context) {
 	err := monitor.ClearAllModelErrors(c.Request.Context())
 	if err != nil {
 		middleware.ErrorResponse(c, http.StatusOK, err.Error())
 		return
 	}
-	c.Status(http.StatusNoContent)
+	middleware.SuccessResponse(c, nil)
 }
 
+// ClearChannelAllModelErrors godoc
+//
+//	@Summary		Clear channel all model errors
+//	@Description	Clears all model errors for a specific channel
+//	@Tags			monitor
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id	path		int	true	"Channel ID"
+//	@Success		204	{object}	middleware.APIResponse
+//	@Router			/api/monitor/{id} [delete]
 func ClearChannelAllModelErrors(c *gin.Context) {
 	channelID := c.Param("id")
 	channelIDInt, err := strconv.ParseInt(channelID, 10, 64)
@@ -54,9 +92,20 @@ func ClearChannelAllModelErrors(c *gin.Context) {
 		middleware.ErrorResponse(c, http.StatusOK, err.Error())
 		return
 	}
-	c.Status(http.StatusNoContent)
+	middleware.SuccessResponse(c, nil)
 }
 
+// ClearChannelModelErrors godoc
+//
+//	@Summary		Clear channel model errors
+//	@Description	Clears model errors for a specific channel and model
+//	@Tags			monitor
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id		path		int		true	"Channel ID"
+//	@Param			model	path		string	true	"Model name"
+//	@Success		204		{object}	middleware.APIResponse
+//	@Router			/api/monitor/{id}/{model} [delete]
 func ClearChannelModelErrors(c *gin.Context) {
 	channelID := c.Param("id")
 	model := c.Param("model")
@@ -70,23 +119,41 @@ func ClearChannelModelErrors(c *gin.Context) {
 		middleware.ErrorResponse(c, http.StatusOK, err.Error())
 		return
 	}
-	c.Status(http.StatusNoContent)
+	middleware.SuccessResponse(c, nil)
 }
 
+// GetModelsErrorRate godoc
+//
+//	@Summary		Get models error rate
+//	@Description	Returns a list of models error rate
+//	@Tags			monitor
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=map[string]float64}
+//	@Router			/api/monitor/models [get]
 func GetModelsErrorRate(c *gin.Context) {
 	rates, err := monitor.GetModelsErrorRate(c.Request.Context())
 	if err != nil {
 		middleware.ErrorResponse(c, http.StatusOK, err.Error())
 		return
 	}
-	c.JSON(http.StatusOK, rates)
+	middleware.SuccessResponse(c, rates)
 }
 
+// GetAllBannedModelChannels godoc
+//
+//	@Summary		Get all banned model channels
+//	@Description	Returns a list of all banned model channels
+//	@Tags			monitor
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=map[string][]int64}
+//	@Router			/api/monitor/banned_channels [get]
 func GetAllBannedModelChannels(c *gin.Context) {
 	channels, err := monitor.GetAllBannedModelChannels(c.Request.Context())
 	if err != nil {
 		middleware.ErrorResponse(c, http.StatusOK, err.Error())
 		return
 	}
-	c.JSON(http.StatusOK, channels)
+	middleware.SuccessResponse(c, channels)
 }

+ 40 - 0
controller/option.go

@@ -8,6 +8,15 @@ import (
 	"github.com/labring/aiproxy/model"
 )
 
+// GetOptions godoc
+//
+//	@Summary		Get options
+//	@Description	Returns a list of options
+//	@Tags			option
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	middleware.APIResponse{data=map[string]string}
+//	@Router			/api/options [get]
 func GetOptions(c *gin.Context) {
 	dbOptions, err := model.GetAllOption()
 	if err != nil {
@@ -21,6 +30,16 @@ func GetOptions(c *gin.Context) {
 	middleware.SuccessResponse(c, options)
 }
 
+// GetOption godoc
+//
+//	@Summary		Get option
+//	@Description	Returns a single option
+//	@Tags			option
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			key	path		string	true	"Option key"
+//	@Success		200	{object}	middleware.APIResponse{data=model.Option}
+//	@Router			/api/options/{key} [get]
 func GetOption(c *gin.Context) {
 	key := c.Param("key")
 	if key == "" {
@@ -35,6 +54,17 @@ func GetOption(c *gin.Context) {
 	middleware.SuccessResponse(c, option)
 }
 
+// UpdateOption godoc
+//
+//	@Summary		Update option
+//	@Description	Updates a single option
+//	@Tags			option
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			key		path		string	true	"Option key"
+//	@Param			value	body		string	true	"Option value"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/options/{key} [put]
 func UpdateOption(c *gin.Context) {
 	var option model.Option
 	err := c.BindJSON(&option)
@@ -50,6 +80,16 @@ func UpdateOption(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// UpdateOptions godoc
+//
+//	@Summary		Update options
+//	@Description	Updates multiple options
+//	@Tags			option
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			options	body		map[string]string	true	"Options"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/options [put]
 func UpdateOptions(c *gin.Context) {
 	var options map[string]string
 	err := c.BindJSON(&options)

+ 530 - 0
controller/relay-controller.go

@@ -0,0 +1,530 @@
+package controller
+
+import (
+	"bytes"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"math/rand/v2"
+	"net/http"
+	"slices"
+	"strconv"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/labring/aiproxy/common"
+	"github.com/labring/aiproxy/common/config"
+	"github.com/labring/aiproxy/common/consume"
+	"github.com/labring/aiproxy/common/notify"
+	"github.com/labring/aiproxy/middleware"
+	dbmodel "github.com/labring/aiproxy/model"
+	"github.com/labring/aiproxy/monitor"
+	"github.com/labring/aiproxy/relay/controller"
+	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
+	relaymodel "github.com/labring/aiproxy/relay/model"
+	log "github.com/sirupsen/logrus"
+)
+
+// https://platform.openai.com/docs/api-reference/chat
+
+type RelayController func(*meta.Meta, *gin.Context) *controller.HandleResult
+
+func relayController(m mode.Mode) (RelayController, bool) {
+	var relayController RelayController
+	switch m {
+	case mode.ImagesGenerations, mode.Edits:
+		relayController = controller.RelayImageHelper
+	case mode.AudioSpeech:
+		relayController = controller.RelayTTSHelper
+	case mode.AudioTranslation,
+		mode.AudioTranscription:
+		relayController = controller.RelaySTTHelper
+	case mode.ParsePdf:
+		relayController = controller.RelayParsePdfHelper
+	case mode.Rerank:
+		relayController = controller.RerankHelper
+	case mode.ChatCompletions,
+		mode.Embeddings,
+		mode.Completions,
+		mode.Moderations:
+		relayController = controller.RelayTextHelper
+	default:
+		return nil, false
+	}
+	return func(meta *meta.Meta, c *gin.Context) *controller.HandleResult {
+		log := middleware.GetLogger(c)
+		middleware.SetLogFieldsFromMeta(meta, log.Data)
+		return relayController(meta, c)
+	}, true
+}
+
+func RelayHelper(meta *meta.Meta, c *gin.Context, relayController RelayController) (*controller.HandleResult, bool) {
+	result := relayController(meta, c)
+	if result.Error == nil {
+		if _, _, err := monitor.AddRequest(
+			context.Background(),
+			meta.OriginModel,
+			int64(meta.Channel.ID),
+			false,
+			false,
+		); err != nil {
+			log.Errorf("add request failed: %+v", err)
+		}
+		return result, false
+	}
+	if result.Error.Error.Code == middleware.GroupBalanceNotEnough {
+		return result, false
+	}
+	shouldRetry := shouldRetry(c, result.Error.StatusCode)
+	if shouldRetry {
+		hasPermission := channelHasPermission(result.Error.StatusCode)
+		beyondThreshold, banExecution, err := monitor.AddRequest(
+			context.Background(),
+			meta.OriginModel,
+			int64(meta.Channel.ID),
+			true,
+			!hasPermission,
+		)
+		if err != nil {
+			log.Errorf("add request failed: %+v", err)
+		}
+		switch {
+		case banExecution:
+			notify.ErrorThrottle(
+				fmt.Sprintf("autoBanned:%d:%s", meta.Channel.ID, meta.OriginModel),
+				time.Minute,
+				fmt.Sprintf("channel[%d] %s(%d) model %s is auto banned",
+					meta.Channel.Type, meta.Channel.Name, meta.Channel.ID, meta.OriginModel),
+				result.Error.JSONOrEmpty(),
+			)
+		case beyondThreshold:
+			notify.WarnThrottle(
+				fmt.Sprintf("beyondThreshold:%d:%s", meta.Channel.ID, meta.OriginModel),
+				time.Minute,
+				fmt.Sprintf("channel[%d] %s(%d) model %s error rate is beyond threshold",
+					meta.Channel.Type, meta.Channel.Name, meta.Channel.ID, meta.OriginModel),
+				result.Error.JSONOrEmpty(),
+			)
+		case !hasPermission:
+			notify.ErrorThrottle(
+				fmt.Sprintf("channelHasPermission:%d:%s", meta.Channel.ID, meta.OriginModel),
+				time.Minute,
+				fmt.Sprintf("channel[%d] %s(%d) model %s has no permission",
+					meta.Channel.Type, meta.Channel.Name, meta.Channel.ID, meta.OriginModel),
+				result.Error.JSONOrEmpty(),
+			)
+		}
+	}
+	return result, shouldRetry
+}
+
+func filterChannels(channels []*dbmodel.Channel, ignoreChannel ...int64) []*dbmodel.Channel {
+	filtered := make([]*dbmodel.Channel, 0)
+	for _, channel := range channels {
+		if channel.Status != dbmodel.ChannelStatusEnabled {
+			continue
+		}
+		if slices.Contains(ignoreChannel, int64(channel.ID)) {
+			continue
+		}
+		filtered = append(filtered, channel)
+	}
+	return filtered
+}
+
+var (
+	ErrChannelsNotFound  = errors.New("channels not found")
+	ErrChannelsExhausted = errors.New("channels exhausted")
+)
+
+func GetRandomChannel(c *dbmodel.ModelCaches, model string, errorRates map[int64]float64, ignoreChannel ...int64) (*dbmodel.Channel, error) {
+	return getRandomChannel(c.EnabledModel2Channels[model], errorRates, ignoreChannel...)
+}
+
+func getPriority(channel *dbmodel.Channel, errorRate float64) int32 {
+	priority := channel.GetPriority()
+	if errorRate > 1 {
+		errorRate = 1
+	} else if errorRate < 0.1 {
+		errorRate = 0.1
+	}
+	return int32(float64(priority) / errorRate)
+}
+
+//nolint:gosec
+func getRandomChannel(channels []*dbmodel.Channel, errorRates map[int64]float64, ignoreChannel ...int64) (*dbmodel.Channel, error) {
+	if len(channels) == 0 {
+		return nil, ErrChannelsNotFound
+	}
+
+	channels = filterChannels(channels, ignoreChannel...)
+	if len(channels) == 0 {
+		return nil, ErrChannelsExhausted
+	}
+
+	if len(channels) == 1 {
+		return channels[0], nil
+	}
+
+	var totalWeight int32
+	cachedPrioritys := make([]int32, len(channels))
+	for i, ch := range channels {
+		priority := getPriority(ch, errorRates[int64(ch.ID)])
+		totalWeight += priority
+		cachedPrioritys[i] = priority
+	}
+
+	if totalWeight == 0 {
+		return channels[rand.IntN(len(channels))], nil
+	}
+
+	r := rand.Int32N(totalWeight)
+	for i, ch := range channels {
+		r -= cachedPrioritys[i]
+		if r < 0 {
+			return ch, nil
+		}
+	}
+
+	return channels[rand.IntN(len(channels))], nil
+}
+
+func getChannelWithFallback(cache *dbmodel.ModelCaches, model string, errorRates map[int64]float64, ignoreChannelIDs ...int64) (*dbmodel.Channel, error) {
+	channel, err := GetRandomChannel(cache, model, errorRates, ignoreChannelIDs...)
+	if err == nil {
+		return channel, nil
+	}
+	if !errors.Is(err, ErrChannelsExhausted) {
+		return nil, err
+	}
+	return GetRandomChannel(cache, model, errorRates)
+}
+
+func NewRelay(mode mode.Mode) func(c *gin.Context) {
+	relayController, ok := relayController(mode)
+	if !ok {
+		log.Fatalf("relay mode %d not implemented", mode)
+	}
+	return func(c *gin.Context) {
+		relay(c, mode, relayController)
+	}
+}
+
+func relay(c *gin.Context, mode mode.Mode, relayController RelayController) {
+	log := middleware.GetLogger(c)
+	requestModel := middleware.GetRequestModel(c)
+
+	// Get initial channel
+	initialChannel, err := getInitialChannel(c, requestModel, log)
+	if err != nil || initialChannel == nil || initialChannel.channel == nil {
+		c.JSON(http.StatusServiceUnavailable, gin.H{
+			"error": &relaymodel.Error{
+				Message: "the upstream load is saturated, please try again later",
+				Code:    "upstream_load_saturated",
+				Type:    middleware.ErrorTypeAIPROXY,
+			},
+		})
+		return
+	}
+
+	// First attempt
+	meta := middleware.NewMetaByContext(c, initialChannel.channel, mode)
+	result, retry := RelayHelper(meta, c, relayController)
+
+	retryTimes := int(config.GetRetryTimes())
+	if handleRelayResult(c, result.Error, retry, retryTimes) {
+		recordResult(c, meta, result, 0, true)
+		return
+	}
+
+	// Setup retry state
+	retryState := initRetryState(
+		retryTimes,
+		initialChannel,
+		meta,
+		result,
+	)
+
+	// Retry loop
+	retryLoop(c, mode, requestModel, retryState, relayController, log)
+}
+
+// recordResult records the consumption for the final result
+func recordResult(c *gin.Context, meta *meta.Meta, result *controller.HandleResult, retryTimes int, downstreamResult bool) {
+	code := http.StatusOK
+	content := ""
+	if result.Error != nil {
+		code = result.Error.StatusCode
+		content = result.Error.JSONOrEmpty()
+	}
+
+	detail := result.Detail
+	if code == http.StatusOK && !config.GetSaveAllLogDetail() {
+		detail = nil
+	}
+
+	gbc := middleware.GetGroupBalanceConsumerFromContext(c)
+
+	amount := consume.CalculateAmount(
+		result.Usage,
+		result.InputPrice,
+		result.OutputPrice,
+		result.CachedPrice,
+		result.CacheCreationPrice,
+	)
+	if amount > 0 {
+		log := middleware.GetLogger(c)
+		log.Data["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
+	}
+
+	consume.AsyncConsume(
+		gbc.Consumer,
+		code,
+		result.Usage,
+		meta,
+		result.InputPrice,
+		result.OutputPrice,
+		result.CachedPrice,
+		result.CacheCreationPrice,
+		content,
+		c.ClientIP(),
+		retryTimes,
+		detail,
+		downstreamResult,
+	)
+}
+
+type retryState struct {
+	retryTimes               int
+	lastHasPermissionChannel *dbmodel.Channel
+	ignoreChannelIDs         []int64
+	errorRates               map[int64]float64
+	exhausted                bool
+
+	meta   *meta.Meta
+	result *controller.HandleResult
+}
+
+type initialChannel struct {
+	channel           *dbmodel.Channel
+	designatedChannel bool
+	ignoreChannelIDs  []int64
+	errorRates        map[int64]float64
+}
+
+func getInitialChannel(c *gin.Context, model string, log *log.Entry) (*initialChannel, error) {
+	if channel := middleware.GetChannel(c); channel != nil {
+		log.Data["designated_channel"] = "true"
+		return &initialChannel{channel: channel, designatedChannel: true}, nil
+	}
+
+	mc := middleware.GetModelCaches(c)
+
+	ids, err := monitor.GetBannedChannelsWithModel(c.Request.Context(), model)
+	if err != nil {
+		log.Errorf("get %s auto banned channels failed: %+v", model, err)
+	}
+	log.Debugf("%s model banned channels: %+v", model, ids)
+
+	errorRates, err := monitor.GetModelChannelErrorRate(c.Request.Context(), model)
+	if err != nil {
+		log.Errorf("get channel model error rates failed: %+v", err)
+	}
+
+	channel, err := getChannelWithFallback(mc, model, errorRates, ids...)
+	if err != nil {
+		return nil, err
+	}
+
+	return &initialChannel{
+		channel:          channel,
+		ignoreChannelIDs: ids,
+		errorRates:       errorRates,
+	}, nil
+}
+
+func handleRelayResult(c *gin.Context, bizErr *relaymodel.ErrorWithStatusCode, retry bool, retryTimes int) (done bool) {
+	if bizErr == nil {
+		return true
+	}
+	if !retry ||
+		retryTimes == 0 ||
+		c.Request.Context().Err() != nil {
+		bizErr.Error.Message = middleware.MessageWithRequestID(c, bizErr.Error.Message)
+		c.JSON(bizErr.StatusCode, bizErr)
+		return true
+	}
+	return false
+}
+
+func initRetryState(retryTimes int, channel *initialChannel, meta *meta.Meta, result *controller.HandleResult) *retryState {
+	state := &retryState{
+		retryTimes:       retryTimes,
+		ignoreChannelIDs: channel.ignoreChannelIDs,
+		errorRates:       channel.errorRates,
+		meta:             meta,
+		result:           result,
+	}
+
+	if channel.designatedChannel {
+		state.exhausted = true
+	}
+
+	if !channelHasPermission(result.Error.StatusCode) {
+		state.ignoreChannelIDs = append(state.ignoreChannelIDs, int64(channel.channel.ID))
+	} else {
+		state.lastHasPermissionChannel = channel.channel
+	}
+
+	return state
+}
+
+func retryLoop(c *gin.Context, mode mode.Mode, requestModel string, state *retryState, relayController RelayController, log *log.Entry) {
+	mc := middleware.GetModelCaches(c)
+
+	// do not use for i := range state.retryTimes, because the retryTimes is constant
+	i := 0
+
+	for {
+		newChannel, err := getRetryChannel(mc, requestModel, state)
+		if err == nil {
+			err = prepareRetry(c)
+		}
+		if err != nil {
+			if !errors.Is(err, ErrChannelsExhausted) {
+				log.Errorf("prepare retry failed: %+v", err)
+			}
+			// when the last request has not recorded the result, record the result
+			if state.meta != nil && state.result != nil {
+				recordResult(c, state.meta, state.result, i, true)
+			}
+			break
+		}
+		// when the last request has not recorded the result, record the result
+		if state.meta != nil && state.result != nil {
+			recordResult(c, state.meta, state.result, i, false)
+			state.meta = nil
+			state.result = nil
+		}
+
+		log.Data["retry"] = strconv.Itoa(i + 1)
+
+		log.Warnf("using channel %s (type: %d, id: %d) to retry (remain times %d)",
+			newChannel.Name,
+			newChannel.Type,
+			newChannel.ID,
+			state.retryTimes-i,
+		)
+
+		state.meta = middleware.NewMetaByContext(c, newChannel, mode)
+		var retry bool
+		state.result, retry = RelayHelper(state.meta, c, relayController)
+
+		done := handleRetryResult(c, retry, newChannel, state)
+		if done || i == state.retryTimes-1 {
+			recordResult(c, state.meta, state.result, i+1, true)
+			break
+		}
+
+		i++
+	}
+
+	if state.result.Error != nil {
+		state.result.Error.Error.Message = middleware.MessageWithRequestID(c, state.result.Error.Error.Message)
+		c.JSON(state.result.Error.StatusCode, state.result.Error)
+	}
+}
+
+func getRetryChannel(mc *dbmodel.ModelCaches, model string, state *retryState) (*dbmodel.Channel, error) {
+	if state.exhausted {
+		if state.lastHasPermissionChannel == nil {
+			return nil, ErrChannelsExhausted
+		}
+		if shouldDelay(state.result.Error.StatusCode) {
+			//nolint:gosec
+			time.Sleep(time.Duration(rand.Float64()*float64(time.Second)) + time.Second)
+		}
+		return state.lastHasPermissionChannel, nil
+	}
+
+	newChannel, err := GetRandomChannel(mc, model, state.errorRates, state.ignoreChannelIDs...)
+	if err != nil {
+		if !errors.Is(err, ErrChannelsExhausted) || state.lastHasPermissionChannel == nil {
+			return nil, err
+		}
+		state.exhausted = true
+		if shouldDelay(state.result.Error.StatusCode) {
+			//nolint:gosec
+			time.Sleep(time.Duration(rand.Float64()*float64(time.Second)) + time.Second)
+		}
+		return state.lastHasPermissionChannel, nil
+	}
+
+	return newChannel, nil
+}
+
+func prepareRetry(c *gin.Context) error {
+	requestBody, err := common.GetRequestBody(c.Request)
+	if err != nil {
+		return fmt.Errorf("get request body failed in prepare retry: %w", err)
+	}
+	c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
+	return nil
+}
+
+func handleRetryResult(ctx *gin.Context, retry bool, newChannel *dbmodel.Channel, state *retryState) (done bool) {
+	if ctx.Request.Context().Err() != nil {
+		return true
+	}
+	if !retry || state.result.Error == nil {
+		return true
+	}
+
+	if state.exhausted {
+		if !channelHasPermission(state.result.Error.StatusCode) {
+			return true
+		}
+	} else {
+		if !channelHasPermission(state.result.Error.StatusCode) {
+			state.ignoreChannelIDs = append(state.ignoreChannelIDs, int64(newChannel.ID))
+			state.retryTimes++
+		} else {
+			state.lastHasPermissionChannel = newChannel
+		}
+	}
+
+	return false
+}
+
+// 仅当是channel错误时,才需要记录,用户请求参数错误时,不需要记录
+func shouldRetry(_ *gin.Context, statusCode int) bool {
+	return statusCode != http.StatusBadRequest &&
+		statusCode != http.StatusRequestEntityTooLarge
+}
+
+var channelNoPermissionStatusCodesMap = map[int]struct{}{
+	http.StatusUnauthorized:    {},
+	http.StatusPaymentRequired: {},
+	http.StatusForbidden:       {},
+}
+
+func channelHasPermission(statusCode int) bool {
+	_, ok := channelNoPermissionStatusCodesMap[statusCode]
+	return !ok
+}
+
+func shouldDelay(statusCode int) bool {
+	return statusCode == http.StatusTooManyRequests
+}
+
+func RelayNotImplemented(c *gin.Context) {
+	c.JSON(http.StatusNotImplemented, gin.H{
+		"error": &relaymodel.Error{
+			Message: "API not implemented",
+			Type:    middleware.ErrorTypeAIPROXY,
+			Code:    "api_not_implemented",
+		},
+	})
+}

+ 60 - 0
controller/relay-dashboard.go

@@ -0,0 +1,60 @@
+package controller
+
+import (
+	"errors"
+	"fmt"
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+	"github.com/labring/aiproxy/common/balance"
+	"github.com/labring/aiproxy/middleware"
+	"github.com/labring/aiproxy/relay/adaptor/openai"
+	log "github.com/sirupsen/logrus"
+)
+
+// GetSubscription godoc
+//
+//	@Summary		Get subscription
+//	@Description	Get subscription
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	openai.SubscriptionResponse
+//	@Router			/v1/dashboard/subscription [get]
+func GetSubscription(c *gin.Context) {
+	group := middleware.GetGroup(c)
+	b, _, err := balance.GetGroupRemainBalance(c, *group)
+	if err != nil {
+		if errors.Is(err, balance.ErrNoRealNameUsedAmountLimit) {
+			middleware.ErrorResponse(c, http.StatusForbidden, err.Error())
+			return
+		}
+		log.Errorf("get group (%s) balance failed: %s", group.ID, err)
+		middleware.ErrorResponse(c, http.StatusInternalServerError, fmt.Sprintf("get group (%s) balance failed", group.ID))
+		return
+	}
+	token := middleware.GetToken(c)
+	quota := token.Quota
+	if quota <= 0 {
+		quota = b
+	}
+	c.JSON(http.StatusOK, openai.SubscriptionResponse{
+		HardLimitUSD:       quota + token.UsedAmount,
+		SoftLimitUSD:       b,
+		SystemHardLimitUSD: quota + token.UsedAmount,
+	})
+}
+
+// GetUsage godoc
+//
+//	@Summary		Get usage
+//	@Description	Get usage
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	openai.UsageResponse
+//	@Router			/v1/dashboard/usage [get]
+func GetUsage(c *gin.Context) {
+	token := middleware.GetToken(c)
+	c.JSON(http.StatusOK, openai.UsageResponse{TotalUsage: token.UsedAmount * 100})
+}

+ 88 - 0
controller/relay-model.go

@@ -0,0 +1,88 @@
+package controller
+
+import (
+	"fmt"
+	"net/http"
+	"slices"
+
+	"github.com/gin-gonic/gin"
+	"github.com/labring/aiproxy/middleware"
+	model "github.com/labring/aiproxy/relay/model"
+)
+
+// ListModels godoc
+//
+//	@Summary		List models
+//	@Description	List all models
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	object{object=string,data=[]OpenAIModels}
+//	@Router			/v1/models [get]
+func ListModels(c *gin.Context) {
+	enabledModelConfigsMap := middleware.GetModelCaches(c).EnabledModelConfigsMap
+	token := middleware.GetToken(c)
+
+	availableOpenAIModels := make([]*OpenAIModels, 0, len(token.Models))
+
+	for _, model := range token.Models {
+		if mc, ok := enabledModelConfigsMap[model]; ok {
+			availableOpenAIModels = append(availableOpenAIModels, &OpenAIModels{
+				ID:         model,
+				Object:     "model",
+				Created:    1626777600,
+				OwnedBy:    string(mc.Owner),
+				Root:       model,
+				Permission: permission,
+				Parent:     nil,
+			})
+		}
+	}
+
+	c.JSON(http.StatusOK, gin.H{
+		"object": "list",
+		"data":   availableOpenAIModels,
+	})
+}
+
+// RetrieveModel godoc
+//
+//	@Summary		Retrieve model
+//	@Description	Retrieve a model
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Success		200	{object}	OpenAIModels
+//	@Router			/v1/models/{model} [get]
+func RetrieveModel(c *gin.Context) {
+	modelName := c.Param("model")
+	enabledModelConfigsMap := middleware.GetModelCaches(c).EnabledModelConfigsMap
+
+	mc, ok := enabledModelConfigsMap[modelName]
+	if ok {
+		token := middleware.GetToken(c)
+		ok = slices.Contains(token.Models, modelName)
+	}
+
+	if !ok {
+		c.JSON(200, gin.H{
+			"error": &model.Error{
+				Message: fmt.Sprintf("the model '%s' does not exist", modelName),
+				Type:    "invalid_request_error",
+				Param:   "model",
+				Code:    "model_not_found",
+			},
+		})
+		return
+	}
+
+	c.JSON(200, &OpenAIModels{
+		ID:         modelName,
+		Object:     "model",
+		Created:    1626777600,
+		OwnedBy:    string(mc.Owner),
+		Root:       modelName,
+		Permission: permission,
+		Parent:     nil,
+	})
+}

+ 233 - 521
controller/relay.go

@@ -1,531 +1,243 @@
 package controller
 
 import (
-	"bytes"
-	"context"
-	"errors"
-	"fmt"
-	"io"
-	"math/rand/v2"
-	"net/http"
-	"slices"
-	"strconv"
-	"time"
-
 	"github.com/gin-gonic/gin"
-	"github.com/labring/aiproxy/common"
-	"github.com/labring/aiproxy/common/config"
-	"github.com/labring/aiproxy/common/consume"
-	"github.com/labring/aiproxy/common/notify"
 	"github.com/labring/aiproxy/middleware"
-	dbmodel "github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/monitor"
-	"github.com/labring/aiproxy/relay/controller"
-	"github.com/labring/aiproxy/relay/meta"
-	"github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
-	log "github.com/sirupsen/logrus"
-)
-
-// https://platform.openai.com/docs/api-reference/chat
-
-type RelayController func(*meta.Meta, *gin.Context) *controller.HandleResult
-
-func relayController(mode relaymode.Mode) (RelayController, bool) {
-	var relayController RelayController
-	switch mode {
-	case relaymode.ImagesGenerations,
-		relaymode.Edits:
-		relayController = controller.RelayImageHelper
-	case relaymode.AudioSpeech:
-		relayController = controller.RelayTTSHelper
-	case relaymode.AudioTranslation,
-		relaymode.AudioTranscription:
-		relayController = controller.RelaySTTHelper
-	case relaymode.ParsePdf:
-		relayController = controller.RelayParsePdfHelper
-	case relaymode.Rerank:
-		relayController = controller.RerankHelper
-	case relaymode.ChatCompletions,
-		relaymode.Embeddings,
-		relaymode.Completions,
-		relaymode.Moderations:
-		relayController = controller.RelayTextHelper
-	default:
-		return nil, false
-	}
-	return func(meta *meta.Meta, c *gin.Context) *controller.HandleResult {
-		log := middleware.GetLogger(c)
-		middleware.SetLogFieldsFromMeta(meta, log.Data)
-		return relayController(meta, c)
-	}, true
-}
-
-func RelayHelper(meta *meta.Meta, c *gin.Context, relayController RelayController) (*controller.HandleResult, bool) {
-	result := relayController(meta, c)
-	if result.Error == nil {
-		if _, _, err := monitor.AddRequest(
-			context.Background(),
-			meta.OriginModel,
-			int64(meta.Channel.ID),
-			false,
-			false,
-		); err != nil {
-			log.Errorf("add request failed: %+v", err)
-		}
-		return result, false
-	}
-	if result.Error.Error.Code == middleware.GroupBalanceNotEnough {
-		return result, false
-	}
-	shouldRetry := shouldRetry(c, result.Error.StatusCode)
-	if shouldRetry {
-		hasPermission := channelHasPermission(result.Error.StatusCode)
-		beyondThreshold, banExecution, err := monitor.AddRequest(
-			context.Background(),
-			meta.OriginModel,
-			int64(meta.Channel.ID),
-			true,
-			!hasPermission,
-		)
-		if err != nil {
-			log.Errorf("add request failed: %+v", err)
-		}
-		switch {
-		case banExecution:
-			notify.ErrorThrottle(
-				fmt.Sprintf("autoBanned:%d:%s", meta.Channel.ID, meta.OriginModel),
-				time.Minute,
-				fmt.Sprintf("channel[%d] %s(%d) model %s is auto banned",
-					meta.Channel.Type, meta.Channel.Name, meta.Channel.ID, meta.OriginModel),
-				result.Error.JSONOrEmpty(),
-			)
-		case beyondThreshold:
-			notify.WarnThrottle(
-				fmt.Sprintf("beyondThreshold:%d:%s", meta.Channel.ID, meta.OriginModel),
-				time.Minute,
-				fmt.Sprintf("channel[%d] %s(%d) model %s error rate is beyond threshold",
-					meta.Channel.Type, meta.Channel.Name, meta.Channel.ID, meta.OriginModel),
-				result.Error.JSONOrEmpty(),
-			)
-		case !hasPermission:
-			notify.ErrorThrottle(
-				fmt.Sprintf("channelHasPermission:%d:%s", meta.Channel.ID, meta.OriginModel),
-				time.Minute,
-				fmt.Sprintf("channel[%d] %s(%d) model %s has no permission",
-					meta.Channel.Type, meta.Channel.Name, meta.Channel.ID, meta.OriginModel),
-				result.Error.JSONOrEmpty(),
-			)
-		}
-	}
-	return result, shouldRetry
-}
+	"github.com/labring/aiproxy/relay/mode"
 
-func filterChannels(channels []*dbmodel.Channel, ignoreChannel ...int64) []*dbmodel.Channel {
-	filtered := make([]*dbmodel.Channel, 0)
-	for _, channel := range channels {
-		if channel.Status != dbmodel.ChannelStatusEnabled {
-			continue
-		}
-		if slices.Contains(ignoreChannel, int64(channel.ID)) {
-			continue
-		}
-		filtered = append(filtered, channel)
-	}
-	return filtered
-}
-
-var (
-	ErrChannelsNotFound  = errors.New("channels not found")
-	ErrChannelsExhausted = errors.New("channels exhausted")
+	// relay model used by swagger
+	_ "github.com/labring/aiproxy/relay/model"
 )
 
-func GetRandomChannel(c *dbmodel.ModelCaches, model string, errorRates map[int64]float64, ignoreChannel ...int64) (*dbmodel.Channel, error) {
-	return getRandomChannel(c.EnabledModel2Channels[model], errorRates, ignoreChannel...)
-}
-
-func getPriority(channel *dbmodel.Channel, errorRate float64) int32 {
-	priority := channel.GetPriority()
-	if errorRate > 1 {
-		errorRate = 1
-	} else if errorRate < 0.1 {
-		errorRate = 0.1
-	}
-	return int32(float64(priority) / errorRate)
-}
-
-//nolint:gosec
-func getRandomChannel(channels []*dbmodel.Channel, errorRates map[int64]float64, ignoreChannel ...int64) (*dbmodel.Channel, error) {
-	if len(channels) == 0 {
-		return nil, ErrChannelsNotFound
-	}
-
-	channels = filterChannels(channels, ignoreChannel...)
-	if len(channels) == 0 {
-		return nil, ErrChannelsExhausted
-	}
-
-	if len(channels) == 1 {
-		return channels[0], nil
-	}
-
-	var totalWeight int32
-	cachedPrioritys := make([]int32, len(channels))
-	for i, ch := range channels {
-		priority := getPriority(ch, errorRates[int64(ch.ID)])
-		totalWeight += priority
-		cachedPrioritys[i] = priority
-	}
-
-	if totalWeight == 0 {
-		return channels[rand.IntN(len(channels))], nil
-	}
-
-	r := rand.Int32N(totalWeight)
-	for i, ch := range channels {
-		r -= cachedPrioritys[i]
-		if r < 0 {
-			return ch, nil
-		}
-	}
-
-	return channels[rand.IntN(len(channels))], nil
-}
-
-func getChannelWithFallback(cache *dbmodel.ModelCaches, model string, errorRates map[int64]float64, ignoreChannelIDs ...int64) (*dbmodel.Channel, error) {
-	channel, err := GetRandomChannel(cache, model, errorRates, ignoreChannelIDs...)
-	if err == nil {
-		return channel, nil
-	}
-	if !errors.Is(err, ErrChannelsExhausted) {
-		return nil, err
-	}
-	return GetRandomChannel(cache, model, errorRates)
-}
-
-func NewRelay(mode relaymode.Mode) func(c *gin.Context) {
-	relayController, ok := relayController(mode)
-	if !ok {
-		log.Fatalf("relay mode %d not implemented", mode)
-	}
-	return func(c *gin.Context) {
-		relay(c, mode, relayController)
-	}
-}
-
-func relay(c *gin.Context, mode relaymode.Mode, relayController RelayController) {
-	log := middleware.GetLogger(c)
-	requestModel := middleware.GetRequestModel(c)
-
-	// Get initial channel
-	initialChannel, err := getInitialChannel(c, requestModel, log)
-	if err != nil || initialChannel == nil || initialChannel.channel == nil {
-		c.JSON(http.StatusServiceUnavailable, gin.H{
-			"error": &model.Error{
-				Message: "the upstream load is saturated, please try again later",
-				Code:    "upstream_load_saturated",
-				Type:    middleware.ErrorTypeAIPROXY,
-			},
-		})
-		return
+// Completions godoc
+//
+//	@Summary		Completions
+//	@Description	Completions
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			request			body		model.GeneralOpenAIRequest	true	"Request"
+//	@Param			Aiproxy-Channel	header		string						false	"Optional Aiproxy-Channel header"
+//	@Success		200				{object}	model.TextResponse
+//	@Header			all				{integer}	X-RateLimit-Limit-Requests		"X-RateLimit-Limit-Requests"
+//	@Header			all				{integer}	X-RateLimit-Limit-Tokens		"X-RateLimit-Limit-Tokens"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Requests	"X-RateLimit-Remaining-Requests"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Tokens	"X-RateLimit-Remaining-Tokens"
+//	@Header			all				{string}	X-RateLimit-Reset-Requests		"X-RateLimit-Reset-Requests"
+//	@Header			all				{string}	X-RateLimit-Reset-Tokens		"X-RateLimit-Reset-Tokens"
+//	@Router			/v1/completions [post]
+func Completions() []gin.HandlerFunc {
+	return []gin.HandlerFunc{
+		middleware.NewDistribute(mode.Completions),
+		NewRelay(mode.Completions),
+	}
+}
+
+// ChatCompletions godoc
+//
+//	@Summary		ChatCompletions
+//	@Description	ChatCompletions
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			request			body		model.GeneralOpenAIRequest		true	"Request"
+//	@Param			Aiproxy-Channel	header		string							false	"Optional Aiproxy-Channel header"
+//	@Success		200				{object}	model.TextResponse				|		model.ChatCompletionsStreamResponse
+//	@Header			all				{integer}	X-RateLimit-Limit-Requests		"X-RateLimit-Limit-Requests"
+//	@Header			all				{integer}	X-RateLimit-Limit-Tokens		"X-RateLimit-Limit-Tokens"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Requests	"X-RateLimit-Remaining-Requests"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Tokens	"X-RateLimit-Remaining-Tokens"
+//	@Header			all				{string}	X-RateLimit-Reset-Requests		"X-RateLimit-Reset-Requests"
+//	@Header			all				{string}	X-RateLimit-Reset-Tokens		"X-RateLimit-Reset-Tokens"
+//	@Router			/v1/chat/completions [post]
+func ChatCompletions() []gin.HandlerFunc {
+	return []gin.HandlerFunc{
+		middleware.NewDistribute(mode.ChatCompletions),
+		NewRelay(mode.ChatCompletions),
+	}
+}
+
+// Embeddings godoc
+//
+//	@Summary		Embeddings
+//	@Description	Embeddings
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			request			body		model.EmbeddingRequest	true	"Request"
+//	@Param			Aiproxy-Channel	header		string					false	"Optional Aiproxy-Channel header"
+//	@Success		200				{object}	model.EmbeddingResponse
+//	@Header			all				{integer}	X-RateLimit-Limit-Requests		"X-RateLimit-Limit-Requests"
+//	@Header			all				{integer}	X-RateLimit-Limit-Tokens		"X-RateLimit-Limit-Tokens"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Requests	"X-RateLimit-Remaining-Requests"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Tokens	"X-RateLimit-Remaining-Tokens"
+//	@Header			all				{string}	X-RateLimit-Reset-Requests		"X-RateLimit-Reset-Requests"
+//	@Header			all				{string}	X-RateLimit-Reset-Tokens		"X-RateLimit-Reset-Tokens"
+//	@Router			/v1/embeddings [post]
+func Embeddings() []gin.HandlerFunc {
+	return []gin.HandlerFunc{
+		middleware.NewDistribute(mode.Embeddings),
+		NewRelay(mode.Embeddings),
+	}
+}
+
+func Edits() []gin.HandlerFunc {
+	return []gin.HandlerFunc{
+		middleware.NewDistribute(mode.Edits),
+		NewRelay(mode.Edits),
+	}
+}
+
+// ImagesGenerations godoc
+//
+//	@Summary		ImagesGenerations
+//	@Description	ImagesGenerations
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			request			body		model.ImageRequest	true	"Request"
+//	@Param			Aiproxy-Channel	header		string				false	"Optional Aiproxy-Channel header"
+//	@Success		200				{object}	model.ImageResponse
+//	@Header			all				{integer}	X-RateLimit-Limit-Requests		"X-RateLimit-Limit-Requests"
+//	@Header			all				{integer}	X-RateLimit-Limit-Tokens		"X-RateLimit-Limit-Tokens"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Requests	"X-RateLimit-Remaining-Requests"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Tokens	"X-RateLimit-Remaining-Tokens"
+//	@Header			all				{string}	X-RateLimit-Reset-Requests		"X-RateLimit-Reset-Requests"
+//	@Header			all				{string}	X-RateLimit-Reset-Tokens		"X-RateLimit-Reset-Tokens"
+//	@Router			/v1/images/generations [post]
+func ImagesGenerations() []gin.HandlerFunc {
+	return []gin.HandlerFunc{
+		middleware.NewDistribute(mode.ImagesGenerations),
+		NewRelay(mode.ImagesGenerations),
+	}
+}
+
+// AudioSpeech godoc
+//
+//	@Summary		AudioSpeech
+//	@Description	AudioSpeech
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			request			body		model.TextToSpeechRequest		true	"Request"
+//	@Param			Aiproxy-Channel	header		string							false	"Optional Aiproxy-Channel header"
+//	@Success		200				{file}		file							"audio binary"
+//	@Header			all				{integer}	X-RateLimit-Limit-Requests		"X-RateLimit-Limit-Requests"
+//	@Header			all				{integer}	X-RateLimit-Limit-Tokens		"X-RateLimit-Limit-Tokens"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Requests	"X-RateLimit-Remaining-Requests"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Tokens	"X-RateLimit-Remaining-Tokens"
+//	@Header			all				{string}	X-RateLimit-Reset-Requests		"X-RateLimit-Reset-Requests"
+//	@Header			all				{string}	X-RateLimit-Reset-Tokens		"X-RateLimit-Reset-Tokens"
+//	@Router			/v1/audio/speech [post]
+func AudioSpeech() []gin.HandlerFunc {
+	return []gin.HandlerFunc{
+		middleware.NewDistribute(mode.AudioSpeech),
+		NewRelay(mode.AudioSpeech),
+	}
+}
+
+// AudioTranscription godoc
+//
+//	@Summary		AudioTranscription
+//	@Description	AudioTranscription
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			model			formData	string	true	"Model"
+//	@Param			file			formData	file	true	"File"
+//	@Param			Aiproxy-Channel	header		string	false	"Optional Aiproxy-Channel header"
+//	@Success		200				{object}	model.SttJSONResponse
+//	@Header			all				{integer}	X-RateLimit-Limit-Requests		"X-RateLimit-Limit-Requests"
+//	@Header			all				{integer}	X-RateLimit-Limit-Tokens		"X-RateLimit-Limit-Tokens"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Requests	"X-RateLimit-Remaining-Requests"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Tokens	"X-RateLimit-Remaining-Tokens"
+//	@Header			all				{string}	X-RateLimit-Reset-Requests		"X-RateLimit-Reset-Requests"
+//	@Header			all				{string}	X-RateLimit-Reset-Tokens		"X-RateLimit-Reset-Tokens"
+//	@Router			/v1/audio/transcription [post]
+func AudioTranscription() []gin.HandlerFunc {
+	return []gin.HandlerFunc{
+		middleware.NewDistribute(mode.AudioTranscription),
+		NewRelay(mode.AudioTranscription),
+	}
+}
+
+// AudioTranslation godoc
+//
+//	@Summary		AudioTranslation
+//	@Description	AudioTranslation
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			model			formData	string	true	"Model"
+//	@Param			file			formData	file	true	"File"
+//	@Param			Aiproxy-Channel	header		string	false	"Optional Aiproxy-Channel header"
+//	@Success		200				{object}	model.SttJSONResponse
+//	@Header			all				{integer}	X-RateLimit-Limit-Requests		"X-RateLimit-Limit-Requests"
+//	@Header			all				{integer}	X-RateLimit-Limit-Tokens		"X-RateLimit-Limit-Tokens"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Requests	"X-RateLimit-Remaining-Requests"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Tokens	"X-RateLimit-Remaining-Tokens"
+//	@Header			all				{string}	X-RateLimit-Reset-Requests		"X-RateLimit-Reset-Requests"
+//	@Header			all				{string}	X-RateLimit-Reset-Tokens		"X-RateLimit-Reset-Tokens"
+//	@Router			/v1/audio/translation [post]
+func AudioTranslation() []gin.HandlerFunc {
+	return []gin.HandlerFunc{
+		middleware.NewDistribute(mode.AudioTranslation),
+		NewRelay(mode.AudioTranslation),
+	}
+}
+
+func Moderations() []gin.HandlerFunc {
+	return []gin.HandlerFunc{
+		middleware.NewDistribute(mode.Moderations),
+		NewRelay(mode.Moderations),
+	}
+}
+
+// Rerank godoc
+//
+//	@Summary		Rerank
+//	@Description	Rerank
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			request			body		model.RerankRequest	true	"Request"
+//	@Param			Aiproxy-Channel	header		string				false	"Optional Aiproxy-Channel header"
+//	@Success		200				{object}	model.RerankResponse
+//	@Header			all				{integer}	X-RateLimit-Limit-Requests		"X-RateLimit-Limit-Requests"
+//	@Header			all				{integer}	X-RateLimit-Limit-Tokens		"X-RateLimit-Limit-Tokens"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Requests	"X-RateLimit-Remaining-Requests"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Tokens	"X-RateLimit-Remaining-Tokens"
+//	@Header			all				{string}	X-RateLimit-Reset-Requests		"X-RateLimit-Reset-Requests"
+//	@Header			all				{string}	X-RateLimit-Reset-Tokens		"X-RateLimit-Reset-Tokens"
+//	@Router			/v1/rerank [post]
+func Rerank() []gin.HandlerFunc {
+	return []gin.HandlerFunc{
+		middleware.NewDistribute(mode.Rerank),
+		NewRelay(mode.Rerank),
+	}
+}
+
+// ParsePdf godoc
+//
+//	@Summary		ParsePdf
+//	@Description	ParsePdf
+//	@Tags			relay
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			model			formData	string	true	"Model"
+//	@Param			file			formData	file	true	"File"
+//	@Param			Aiproxy-Channel	header		string	false	"Optional Aiproxy-Channel header"
+//	@Success		200				{object}	model.ParsePdfResponse
+//	@Header			all				{integer}	X-RateLimit-Limit-Requests		"X-RateLimit-Limit-Requests"
+//	@Header			all				{integer}	X-RateLimit-Limit-Tokens		"X-RateLimit-Limit-Tokens"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Requests	"X-RateLimit-Remaining-Requests"
+//	@Header			all				{integer}	X-RateLimit-Remaining-Tokens	"X-RateLimit-Remaining-Tokens"
+//	@Header			all				{string}	X-RateLimit-Reset-Requests		"X-RateLimit-Reset-Requests"
+//	@Header			all				{string}	X-RateLimit-Reset-Tokens		"X-RateLimit-Reset-Tokens"
+//	@Router			/v1/parse-pdf [post]
+func ParsePdf() []gin.HandlerFunc {
+	return []gin.HandlerFunc{
+		middleware.NewDistribute(mode.ParsePdf),
+		NewRelay(mode.ParsePdf),
 	}
-
-	// First attempt
-	meta := middleware.NewMetaByContext(c, initialChannel.channel, mode)
-	result, retry := RelayHelper(meta, c, relayController)
-
-	retryTimes := int(config.GetRetryTimes())
-	if handleRelayResult(c, result.Error, retry, retryTimes) {
-		recordResult(c, meta, result, 0, true)
-		return
-	}
-
-	// Setup retry state
-	retryState := initRetryState(
-		retryTimes,
-		initialChannel,
-		meta,
-		result,
-	)
-
-	// Retry loop
-	retryLoop(c, mode, requestModel, retryState, relayController, log)
-}
-
-// recordResult records the consumption for the final result
-func recordResult(c *gin.Context, meta *meta.Meta, result *controller.HandleResult, retryTimes int, downstreamResult bool) {
-	code := http.StatusOK
-	content := ""
-	if result.Error != nil {
-		code = result.Error.StatusCode
-		content = result.Error.JSONOrEmpty()
-	}
-
-	detail := result.Detail
-	if code == http.StatusOK && !config.GetSaveAllLogDetail() {
-		detail = nil
-	}
-
-	gbc := middleware.GetGroupBalanceConsumerFromContext(c)
-
-	amount := consume.CalculateAmount(
-		result.Usage,
-		result.InputPrice,
-		result.OutputPrice,
-		result.CachedPrice,
-		result.CacheCreationPrice,
-	)
-	if amount > 0 {
-		log := middleware.GetLogger(c)
-		log.Data["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
-	}
-
-	consume.AsyncConsume(
-		gbc.Consumer,
-		code,
-		result.Usage,
-		meta,
-		result.InputPrice,
-		result.OutputPrice,
-		result.CachedPrice,
-		result.CacheCreationPrice,
-		content,
-		c.ClientIP(),
-		retryTimes,
-		detail,
-		downstreamResult,
-	)
-}
-
-type retryState struct {
-	retryTimes               int
-	lastHasPermissionChannel *dbmodel.Channel
-	ignoreChannelIDs         []int64
-	errorRates               map[int64]float64
-	exhausted                bool
-
-	meta   *meta.Meta
-	result *controller.HandleResult
-}
-
-type initialChannel struct {
-	channel           *dbmodel.Channel
-	designatedChannel bool
-	ignoreChannelIDs  []int64
-	errorRates        map[int64]float64
-}
-
-func getInitialChannel(c *gin.Context, model string, log *log.Entry) (*initialChannel, error) {
-	if channel := middleware.GetChannel(c); channel != nil {
-		log.Data["designated_channel"] = "true"
-		return &initialChannel{channel: channel, designatedChannel: true}, nil
-	}
-
-	mc := middleware.GetModelCaches(c)
-
-	ids, err := monitor.GetBannedChannelsWithModel(c.Request.Context(), model)
-	if err != nil {
-		log.Errorf("get %s auto banned channels failed: %+v", model, err)
-	}
-	log.Debugf("%s model banned channels: %+v", model, ids)
-
-	errorRates, err := monitor.GetModelChannelErrorRate(c.Request.Context(), model)
-	if err != nil {
-		log.Errorf("get channel model error rates failed: %+v", err)
-	}
-
-	channel, err := getChannelWithFallback(mc, model, errorRates, ids...)
-	if err != nil {
-		return nil, err
-	}
-
-	return &initialChannel{
-		channel:          channel,
-		ignoreChannelIDs: ids,
-		errorRates:       errorRates,
-	}, nil
-}
-
-func handleRelayResult(c *gin.Context, bizErr *model.ErrorWithStatusCode, retry bool, retryTimes int) (done bool) {
-	if bizErr == nil {
-		return true
-	}
-	if !retry ||
-		retryTimes == 0 ||
-		c.Request.Context().Err() != nil {
-		bizErr.Error.Message = middleware.MessageWithRequestID(c, bizErr.Error.Message)
-		c.JSON(bizErr.StatusCode, bizErr)
-		return true
-	}
-	return false
-}
-
-func initRetryState(retryTimes int, channel *initialChannel, meta *meta.Meta, result *controller.HandleResult) *retryState {
-	state := &retryState{
-		retryTimes:       retryTimes,
-		ignoreChannelIDs: channel.ignoreChannelIDs,
-		errorRates:       channel.errorRates,
-		meta:             meta,
-		result:           result,
-	}
-
-	if channel.designatedChannel {
-		state.exhausted = true
-	}
-
-	if !channelHasPermission(result.Error.StatusCode) {
-		state.ignoreChannelIDs = append(state.ignoreChannelIDs, int64(channel.channel.ID))
-	} else {
-		state.lastHasPermissionChannel = channel.channel
-	}
-
-	return state
-}
-
-func retryLoop(c *gin.Context, mode relaymode.Mode, requestModel string, state *retryState, relayController RelayController, log *log.Entry) {
-	mc := middleware.GetModelCaches(c)
-
-	// do not use for i := range state.retryTimes, because the retryTimes is constant
-	i := 0
-
-	for {
-		newChannel, err := getRetryChannel(mc, requestModel, state)
-		if err == nil {
-			err = prepareRetry(c)
-		}
-		if err != nil {
-			if !errors.Is(err, ErrChannelsExhausted) {
-				log.Errorf("prepare retry failed: %+v", err)
-			}
-			// when the last request has not recorded the result, record the result
-			if state.meta != nil && state.result != nil {
-				recordResult(c, state.meta, state.result, i, true)
-			}
-			break
-		}
-		// when the last request has not recorded the result, record the result
-		if state.meta != nil && state.result != nil {
-			recordResult(c, state.meta, state.result, i, false)
-			state.meta = nil
-			state.result = nil
-		}
-
-		log.Data["retry"] = strconv.Itoa(i + 1)
-
-		log.Warnf("using channel %s (type: %d, id: %d) to retry (remain times %d)",
-			newChannel.Name,
-			newChannel.Type,
-			newChannel.ID,
-			state.retryTimes-i,
-		)
-
-		state.meta = middleware.NewMetaByContext(c, newChannel, mode)
-		var retry bool
-		state.result, retry = RelayHelper(state.meta, c, relayController)
-
-		done := handleRetryResult(c, retry, newChannel, state)
-		if done || i == state.retryTimes-1 {
-			recordResult(c, state.meta, state.result, i+1, true)
-			break
-		}
-
-		i++
-	}
-
-	if state.result.Error != nil {
-		state.result.Error.Error.Message = middleware.MessageWithRequestID(c, state.result.Error.Error.Message)
-		c.JSON(state.result.Error.StatusCode, state.result.Error)
-	}
-}
-
-func getRetryChannel(mc *dbmodel.ModelCaches, model string, state *retryState) (*dbmodel.Channel, error) {
-	if state.exhausted {
-		if state.lastHasPermissionChannel == nil {
-			return nil, ErrChannelsExhausted
-		}
-		if shouldDelay(state.result.Error.StatusCode) {
-			//nolint:gosec
-			time.Sleep(time.Duration(rand.Float64()*float64(time.Second)) + time.Second)
-		}
-		return state.lastHasPermissionChannel, nil
-	}
-
-	newChannel, err := GetRandomChannel(mc, model, state.errorRates, state.ignoreChannelIDs...)
-	if err != nil {
-		if !errors.Is(err, ErrChannelsExhausted) || state.lastHasPermissionChannel == nil {
-			return nil, err
-		}
-		state.exhausted = true
-		if shouldDelay(state.result.Error.StatusCode) {
-			//nolint:gosec
-			time.Sleep(time.Duration(rand.Float64()*float64(time.Second)) + time.Second)
-		}
-		return state.lastHasPermissionChannel, nil
-	}
-
-	return newChannel, nil
-}
-
-func prepareRetry(c *gin.Context) error {
-	requestBody, err := common.GetRequestBody(c.Request)
-	if err != nil {
-		return fmt.Errorf("get request body failed in prepare retry: %w", err)
-	}
-	c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
-	return nil
-}
-
-func handleRetryResult(ctx *gin.Context, retry bool, newChannel *dbmodel.Channel, state *retryState) (done bool) {
-	if ctx.Request.Context().Err() != nil {
-		return true
-	}
-	if !retry || state.result.Error == nil {
-		return true
-	}
-
-	if state.exhausted {
-		if !channelHasPermission(state.result.Error.StatusCode) {
-			return true
-		}
-	} else {
-		if !channelHasPermission(state.result.Error.StatusCode) {
-			state.ignoreChannelIDs = append(state.ignoreChannelIDs, int64(newChannel.ID))
-			state.retryTimes++
-		} else {
-			state.lastHasPermissionChannel = newChannel
-		}
-	}
-
-	return false
-}
-
-// 仅当是channel错误时,才需要记录,用户请求参数错误时,不需要记录
-func shouldRetry(_ *gin.Context, statusCode int) bool {
-	return statusCode != http.StatusBadRequest &&
-		statusCode != http.StatusRequestEntityTooLarge
-}
-
-var channelNoPermissionStatusCodesMap = map[int]struct{}{
-	http.StatusUnauthorized:    {},
-	http.StatusPaymentRequired: {},
-	http.StatusForbidden:       {},
-}
-
-func channelHasPermission(statusCode int) bool {
-	_, ok := channelNoPermissionStatusCodesMap[statusCode]
-	return !ok
-}
-
-func shouldDelay(statusCode int) bool {
-	return statusCode == http.StatusTooManyRequests
-}
-
-func RelayNotImplemented(c *gin.Context) {
-	c.JSON(http.StatusNotImplemented, gin.H{
-		"error": &model.Error{
-			Message: "API not implemented",
-			Type:    middleware.ErrorTypeAIPROXY,
-			Code:    "api_not_implemented",
-		},
-	})
 }

+ 197 - 4
controller/token.go

@@ -103,7 +103,17 @@ func buildTokenResponses(tokens []*model.Token) []*TokenResponse {
 	return responses
 }
 
-// Token list handlers
+// GetTokens godoc
+//
+//	@Summary		Get all tokens
+//	@Description	Returns a paginated list of all tokens
+//	@Tags			tokens
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			page		query		int	false	"Page number"
+//	@Param			per_page	query		int	false	"Items per page"
+//	@Success		200			{object}	middleware.APIResponse{data=map[string]any{tokens=[]TokenResponse,total=int}}
+//	@Router			/api/tokens [get]
 func GetTokens(c *gin.Context) {
 	page, perPage := parsePageParams(c)
 	group := c.Query("group")
@@ -122,6 +132,16 @@ func GetTokens(c *gin.Context) {
 	})
 }
 
+// GetGroupTokens godoc
+//
+//	@Summary		Get all tokens for a specific group
+//	@Description	Returns a paginated list of all tokens for a specific group
+//	@Tags			tokens
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Success		200		{object}	middleware.APIResponse{data=map[string]any{tokens=[]TokenResponse,total=int}}
+//	@Router			/api/tokens/{group} [get]
 func GetGroupTokens(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -145,6 +165,21 @@ func GetGroupTokens(c *gin.Context) {
 	})
 }
 
+// SearchTokens godoc
+//
+//	@Summary		Search tokens
+//	@Description	Returns a paginated list of tokens based on search criteria
+//	@Tags			tokens
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			keyword	query		string	false	"Keyword"
+//	@Param			order	query		string	false	"Order"
+//	@Param			name	query		string	false	"Name"
+//	@Param			key		query		string	false	"Key"
+//	@Param			status	query		int		false	"Status"
+//	@Param			group	query		string	false	"Group"
+//	@Success		200		{object}	middleware.APIResponse{data=map[string]any{tokens=[]TokenResponse,total=int}}
+//	@Router			/api/tokens/search [get]
 func SearchTokens(c *gin.Context) {
 	page, perPage := parsePageParams(c)
 	keyword := c.Query("keyword")
@@ -166,6 +201,16 @@ func SearchTokens(c *gin.Context) {
 	})
 }
 
+// SearchGroupTokens godoc
+//
+//	@Summary		Search tokens for a specific group
+//	@Description	Returns a paginated list of tokens for a specific group based on search criteria
+//	@Tags			tokens
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Success		200		{object}	middleware.APIResponse{data=map[string]any{tokens=[]TokenResponse,total=int}}
+//	@Router			/api/token/{group}/search [get]
 func SearchGroupTokens(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -192,7 +237,16 @@ func SearchGroupTokens(c *gin.Context) {
 	})
 }
 
-// Single token handlers
+// GetToken godoc
+//
+//	@Summary		Get token by ID
+//	@Description	Returns detailed information about a specific token
+//	@Tags			tokens
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id	path		int	true	"Token ID"
+//	@Success		200	{object}	middleware.APIResponse{data=TokenResponse}
+//	@Router			/api/tokens/{id} [get]
 func GetToken(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
@@ -209,6 +263,17 @@ func GetToken(c *gin.Context) {
 	middleware.SuccessResponse(c, buildTokenResponse(token))
 }
 
+// GetGroupToken godoc
+//
+//	@Summary		Get token by ID for a specific group
+//	@Description	Returns detailed information about a specific token for a specific group
+//	@Tags			tokens
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Param			id		path		int		true	"Token ID"
+//	@Success		200		{object}	middleware.APIResponse{data=TokenResponse}
+//	@Router			/api/token/{group}/{id} [get]
 func GetGroupToken(c *gin.Context) {
 	group := c.Param("group")
 	if group == "" {
@@ -231,6 +296,18 @@ func GetGroupToken(c *gin.Context) {
 	middleware.SuccessResponse(c, buildTokenResponse(token))
 }
 
+// AddGroupToken godoc
+//
+//	@Summary		Add group token
+//	@Description	Adds a new token to a specific group
+//	@Tags			token
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string		true	"Group name"
+//	@Param			token	body		model.Token	true	"Token information"
+//	@Success		200		{object}	middleware.APIResponse{data=TokenResponse}
+//	@Router			/api/token/{group} [post]
 func AddGroupToken(c *gin.Context) {
 	group := c.Param("group")
 	var req AddTokenRequest
@@ -255,7 +332,16 @@ func AddGroupToken(c *gin.Context) {
 	middleware.SuccessResponse(c, &TokenResponse{Token: token})
 }
 
-// Delete handlers
+// DeleteToken godoc
+//
+//	@Summary		Delete token
+//	@Description	Deletes a specific token by ID
+//	@Tags			tokens
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id	path		int	true	"Token ID"
+//	@Success		200	{object}	middleware.APIResponse
+//	@Router			/api/tokens/{id} [delete]
 func DeleteToken(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
@@ -271,6 +357,17 @@ func DeleteToken(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// DeleteTokens godoc
+//
+//	@Summary		Delete multiple tokens
+//	@Description	Deletes multiple tokens by their IDs
+//	@Tags			tokens
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			ids	body		[]int	true	"Token IDs"
+//	@Success		200	{object}	middleware.APIResponse
+//	@Router			/api/tokens/batch_delete [post]
 func DeleteTokens(c *gin.Context) {
 	var ids []int
 	if err := c.ShouldBindJSON(&ids); err != nil {
@@ -286,6 +383,17 @@ func DeleteTokens(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// DeleteGroupToken godoc
+//
+//	@Summary		Delete group token
+//	@Description	Deletes a specific token from a group
+//	@Tags			token
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Param			id		path		int		true	"Token ID"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/token/{group}/{id} [delete]
 func DeleteGroupToken(c *gin.Context) {
 	group := c.Param("group")
 	id, err := strconv.Atoi(c.Param("id"))
@@ -302,6 +410,17 @@ func DeleteGroupToken(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// DeleteGroupTokens godoc
+//
+//	@Summary		Delete group tokens
+//	@Description	Deletes multiple tokens from a specific group
+//	@Tags			token
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string	true	"Group name"
+//	@Param			ids		body		[]int	true	"Token IDs"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/token/{group}/batch_delete [post]
 func DeleteGroupTokens(c *gin.Context) {
 	group := c.Param("group")
 	var ids []int
@@ -318,7 +437,18 @@ func DeleteGroupTokens(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
-// Update handlers
+// UpdateToken godoc
+//
+//	@Summary		Update token
+//	@Description	Updates an existing token's information
+//	@Tags			tokens
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id		path		int			true	"Token ID"
+//	@Param			token	body		model.Token	true	"Updated token information"
+//	@Success		200		{object}	middleware.APIResponse{data=TokenResponse}
+//	@Router			/api/tokens/{id} [put]
 func UpdateToken(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
@@ -347,6 +477,19 @@ func UpdateToken(c *gin.Context) {
 	middleware.SuccessResponse(c, &TokenResponse{Token: token})
 }
 
+// UpdateGroupToken godoc
+//
+//	@Summary		Update group token
+//	@Description	Updates an existing token in a specific group
+//	@Tags			token
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string		true	"Group name"
+//	@Param			id		path		int			true	"Token ID"
+//	@Param			token	body		model.Token	true	"Updated token information"
+//	@Success		200		{object}	middleware.APIResponse{data=TokenResponse}
+//	@Router			/api/token/{group}/{id} [put]
 func UpdateGroupToken(c *gin.Context) {
 	group := c.Param("group")
 	id, err := strconv.Atoi(c.Param("id"))
@@ -376,6 +519,18 @@ func UpdateGroupToken(c *gin.Context) {
 	middleware.SuccessResponse(c, &TokenResponse{Token: token})
 }
 
+// UpdateTokenStatus godoc
+//
+//	@Summary		Update token status
+//	@Description	Updates the status of a specific token
+//	@Tags			tokens
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id		path		int							true	"Token ID"
+//	@Param			status	body		UpdateTokenStatusRequest	true	"Status information"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/tokens/{id}/status [post]
 func UpdateTokenStatus(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
@@ -397,6 +552,19 @@ func UpdateTokenStatus(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// UpdateGroupTokenStatus godoc
+//
+//	@Summary		Update group token status
+//	@Description	Updates the status of a token in a specific group
+//	@Tags			token
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string						true	"Group name"
+//	@Param			id		path		int							true	"Token ID"
+//	@Param			status	body		UpdateTokenStatusRequest	true	"Status information"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/token/{group}/{id}/status [post]
 func UpdateGroupTokenStatus(c *gin.Context) {
 	group := c.Param("group")
 	id, err := strconv.Atoi(c.Param("id"))
@@ -419,6 +587,18 @@ func UpdateGroupTokenStatus(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// UpdateTokenName godoc
+//
+//	@Summary		Update token name
+//	@Description	Updates the name of a specific token
+//	@Tags			tokens
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			id		path		int						true	"Token ID"
+//	@Param			name	body		UpdateTokenNameRequest	true	"Name information"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/tokens/{id}/name [post]
 func UpdateTokenName(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
@@ -440,6 +620,19 @@ func UpdateTokenName(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
+// UpdateGroupTokenName godoc
+//
+//	@Summary		Update group token name
+//	@Description	Updates the name of a token in a specific group
+//	@Tags			token
+//	@Accept			json
+//	@Produce		json
+//	@Security		ApiKeyAuth
+//	@Param			group	path		string					true	"Group name"
+//	@Param			id		path		int						true	"Token ID"
+//	@Param			name	body		UpdateTokenNameRequest	true	"Name information"
+//	@Success		200		{object}	middleware.APIResponse
+//	@Router			/api/token/{group}/{id}/name [post]
 func UpdateGroupTokenName(c *gin.Context) {
 	group := c.Param("group")
 	id, err := strconv.Atoi(c.Param("id"))

+ 6913 - 0
docs/docs.go

@@ -0,0 +1,6913 @@
+// Package docs Code generated by swaggo/swag. DO NOT EDIT
+package docs
+
+import "github.com/swaggo/swag"
+
+const docTemplate = `{
+    "schemes": {{ marshal .Schemes }},
+    "swagger": "2.0",
+    "info": {
+        "description": "{{escape .Description}}",
+        "title": "{{.Title}}",
+        "contact": {},
+        "version": "{{.Version}}"
+    },
+    "host": "{{.Host}}",
+    "basePath": "{{.BasePath}}",
+    "paths": {
+        "/api/channel": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Adds a new channel to the system",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Add a single channel",
+                "parameters": [
+                    {
+                        "description": "Channel information",
+                        "name": "channel",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.AddChannelRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channel/{id}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns detailed information about a specific channel",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Get a channel by ID",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.Channel"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "put": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates an existing channel by its ID",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Update a channel",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Updated channel information",
+                        "name": "channel",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.AddChannelRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.Channel"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes a channel by its ID",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Delete a channel",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channel/{id}/balance": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the balance for a single channel",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Update channel balance",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "number"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channel/{id}/models": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Tests all models in the channel",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Test channel models",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/controller.TestResult"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channel/{id}/status": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the status of a channel by its ID",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Update channel status",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Status information",
+                        "name": "status",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.UpdateChannelStatusRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channel/{id}/{model}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Tests a single model in the channel",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Test channel model",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "Model name",
+                        "name": "model",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.ChannelTest"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a paginated list of channels with optional filters",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Get channels with pagination",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Filter by id",
+                        "name": "id",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by name",
+                        "name": "name",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by key",
+                        "name": "key",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Filter by channel type",
+                        "name": "channel_type",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by base URL",
+                        "name": "base_url",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Order by field",
+                        "name": "order",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "channels": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/model.Channel"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Adds multiple channels in a batch operation",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Add multiple channels",
+                "parameters": [
+                    {
+                        "description": "Channel information",
+                        "name": "channels",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "$ref": "#/definitions/controller.AddChannelRequest"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/all": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of all channels without pagination",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Get all channels",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.Channel"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/balance": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the balance for all channels",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Update all channels balance",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/batch_delete": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes multiple channels by their IDs",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Delete multiple channels",
+                "parameters": [
+                    {
+                        "description": "Channel IDs",
+                        "name": "ids",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "integer"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/import/oneapi": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Imports channels from OneAPI",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Import channel from OneAPI",
+                "parameters": [
+                    {
+                        "description": "Import channel from OneAPI request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.ImportChannelFromOneAPIRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {}
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Search channels with keyword and optional filters",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Search channels",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Search keyword",
+                        "name": "keyword",
+                        "in": "query",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Filter by id",
+                        "name": "id",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by name",
+                        "name": "name",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by key",
+                        "name": "key",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Filter by channel type",
+                        "name": "channel_type",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by base URL",
+                        "name": "base_url",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Order by field",
+                        "name": "order",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "channels": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/model.Channel"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/test": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Tests all channels",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Test all channels",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/controller.TestResult"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/type_metas": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns metadata for all channel types",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Get channel type metadata",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "$ref": "#/definitions/channeltype.AdaptorMeta"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/type_names": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of all available channel type names",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Get all channel type names",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "string"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/dashboard": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns the general dashboard data including usage statistics and metrics",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "dashboard"
+                ],
+                "summary": "Get dashboard data",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.DashboardResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/dashboard/{group}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns dashboard data and metrics specific to the given group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "dashboard"
+                ],
+                "summary": "Get dashboard data for a specific group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name or ID",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.GroupDashboardResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/dashboard/{group}/models": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns model-specific metrics and usage data for the given group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "dashboard"
+                ],
+                "summary": "Get model usage data for a specific group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name or ID",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/group/{group}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns detailed information about a specific group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Get a group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.GroupResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "put": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates an existing group with the given information",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Update a group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Updated group information",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.Group"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Creates a new group with the given information",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Create a new group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Group information",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.Group"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes a group by its name",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Delete a group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/group/{group}/rpm": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the RPM (Requests Per Minute) for a group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Update group RPM",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "RPM information",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/group/{group}/rpm_ratio": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the RPM (Requests Per Minute) ratio for a group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Update group RPM ratio",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "RPM ratio information",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/group/{group}/status": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the status of a group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Update group status",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Status information",
+                        "name": "status",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/group/{group}/tpm": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the TPM (Tokens Per Minute) for a group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Update group TPM",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "TPM information",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/group/{group}/tpm_ratio": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the TPM (Tokens Per Minute) ratio for a group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Update group TPM ratio",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "TPM ratio information",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/groups": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of all groups with pagination",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "groups"
+                ],
+                "summary": "Get all groups",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "groups": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/controller.GroupResponse"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/groups/batch_delete": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes multiple groups by their IDs",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "groups"
+                ],
+                "summary": "Delete multiple groups",
+                "parameters": [
+                    {
+                        "description": "Group IDs",
+                        "name": "ids",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "string"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/groups/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Search groups with keyword and pagination",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "groups"
+                ],
+                "summary": "Search groups",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Search keyword",
+                        "name": "keyword",
+                        "in": "query",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "groups": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/controller.GroupResponse"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/log/{group}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get logs for a specific group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "log"
+                ],
+                "summary": "Get group logs",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Start timestamp (milliseconds)",
+                        "name": "start_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "End timestamp (milliseconds)",
+                        "name": "end_time",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.GetGroupLogsResult"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/log/{group}/detail/{log_id}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get detailed information about a specific log entry in a group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "log"
+                ],
+                "summary": "Get group log detail",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "Log ID",
+                        "name": "log_id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.RequestDetail"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/log/{group}/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Search logs for a specific group with filters",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "log"
+                ],
+                "summary": "Search group logs",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Start timestamp (milliseconds)",
+                        "name": "start_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "End timestamp (milliseconds)",
+                        "name": "end_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by token name",
+                        "name": "token_name",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by model name",
+                        "name": "model",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Filter by status",
+                        "name": "status",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.GetGroupLogsResult"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/log/{group}/used/models": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get a list of models that have been used in a specific group's logs",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "log"
+                ],
+                "summary": "Get group used models",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "type": "string"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/log/{group}/used/token_names": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get a list of token names that have been used in a specific group's logs",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "log"
+                ],
+                "summary": "Get group used token names",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "type": "string"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/logs": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a paginated list of all logs with optional filters",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "logs"
+                ],
+                "summary": "Get all logs",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Start timestamp (milliseconds)",
+                        "name": "start_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "End timestamp (milliseconds)",
+                        "name": "end_time",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.GetLogsResult"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes logs older than the specified retention period",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "logs"
+                ],
+                "summary": "Delete historical logs",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "integer"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/logs/consume_error": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Search for logs with consumption errors",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "logs"
+                ],
+                "summary": "Search consumption errors",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Start timestamp (milliseconds)",
+                        "name": "start_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "End timestamp (milliseconds)",
+                        "name": "end_time",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "logs": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/model.RequestDetail"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/logs/detail/{log_id}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get detailed information about a specific log entry",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "logs"
+                ],
+                "summary": "Get log detail",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Log ID",
+                        "name": "log_id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.RequestDetail"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/logs/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Search logs with various filters",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "logs"
+                ],
+                "summary": "Search logs",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Start timestamp (milliseconds)",
+                        "name": "start_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "End timestamp (milliseconds)",
+                        "name": "end_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by token name",
+                        "name": "token_name",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by model name",
+                        "name": "model",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Filter by status",
+                        "name": "status",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.GetLogsResult"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/logs/used/models": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get a list of models that have been used in logs",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "logs"
+                ],
+                "summary": "Get used models",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "type": "string"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/model_config": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Saves a model config",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Save model config",
+                "parameters": [
+                    {
+                        "description": "Model config",
+                        "name": "config",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.SaveModelConfigsRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/model_config/{model}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a model config",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Get model config",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Model name",
+                        "name": "model",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.ModelConfig"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes a model config",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Delete model config",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Model name",
+                        "name": "model",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/model_configs": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Saves a list of model configs",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Save model configs",
+                "parameters": [
+                    {
+                        "description": "Model configs",
+                        "name": "configs",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "$ref": "#/definitions/controller.SaveModelConfigsRequest"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/model_configs/batch_delete": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes a list of model configs",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Delete model configs",
+                "parameters": [
+                    {
+                        "description": "Model names",
+                        "name": "models",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "string"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/model_cost_rank": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns ranking data for models based on cost",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "dashboard"
+                ],
+                "summary": "Get model cost ranking data",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelCostRank"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/model_cost_rank/{group}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns model cost ranking data specific to the given group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "dashboard"
+                ],
+                "summary": "Get model cost ranking data for a specific group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name or ID",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelCostRank"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/modelconfigs": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of model configs with pagination",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Get model configs",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "configs": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/model.ModelConfig"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/modelconfigs/all": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of all model configs",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Get all model configs",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/modelconfigs/contains": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of model configs by models contains",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Get model configs by models contains",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/modelconfigs/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of model configs by keyword",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Search model configs",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "configs": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/model.ModelConfig"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/builtin": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of builtin models",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get builtin models",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/controller.BuiltinModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/builtin/channel": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel builtin models",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get channel builtin models",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "array",
+                                                "items": {
+                                                    "$ref": "#/definitions/controller.BuiltinModelConfig"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/builtin/channel/{type}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel builtin models by type",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get channel builtin models by type",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Channel type",
+                        "name": "type",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/controller.BuiltinModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/default": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel default models and mapping",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get channel default models and mapping",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "mapping": {
+                                                                "type": "object",
+                                                                "additionalProperties": {
+                                                                    "type": "string"
+                                                                }
+                                                            },
+                                                            "models": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "type": "string"
+                                                                }
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/default/{type}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel default models and mapping by type",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get channel default models and mapping by type",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Channel type",
+                        "name": "type",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "mapping": {
+                                                                "type": "object",
+                                                                "additionalProperties": {
+                                                                    "type": "string"
+                                                                }
+                                                            },
+                                                            "models": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "type": "string"
+                                                                }
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/enabled": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of enabled models",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get enabled models",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/enabled/channel": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel enabled models",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get channel enabled models",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "array",
+                                                "items": {
+                                                    "$ref": "#/definitions/model.ModelConfig"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/enabled/channel/{type}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel enabled models by type",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get channel enabled models by type",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Channel type",
+                        "name": "type",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/monitor": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of all channel model error rates",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Get all channel model error rates",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "object",
+                                                "additionalProperties": {
+                                                    "type": "number"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Clears all model errors",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Clear all model errors",
+                "responses": {
+                    "204": {
+                        "description": "No Content",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/monitor/banned_channels": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of all banned model channels",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Get all banned model channels",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "array",
+                                                "items": {
+                                                    "type": "integer"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/monitor/models": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of models error rate",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Get models error rate",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "number"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/monitor/{id}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel model error rates",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Get channel model error rates",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "type": "object",
+                                                "additionalProperties": {
+                                                    "type": "number"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Clears all model errors for a specific channel",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Clear channel all model errors",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "204": {
+                        "description": "No Content",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/monitor/{id}/{model}": {
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Clears model errors for a specific channel and model",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Clear channel model errors",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "Model name",
+                        "name": "model",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "204": {
+                        "description": "No Content",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/options": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of options",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "option"
+                ],
+                "summary": "Get options",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "string"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "put": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates multiple options",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "option"
+                ],
+                "summary": "Update options",
+                "parameters": [
+                    {
+                        "description": "Options",
+                        "name": "options",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object",
+                            "additionalProperties": {
+                                "type": "string"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/options/{key}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a single option",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "option"
+                ],
+                "summary": "Get option",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Option key",
+                        "name": "key",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.Option"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "put": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates a single option",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "option"
+                ],
+                "summary": "Update option",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Option key",
+                        "name": "key",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Option value",
+                        "name": "value",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/status": {
+            "get": {
+                "description": "Returns the status of the server",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "misc"
+                ],
+                "summary": "Get status",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.StatusData"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/token/{group}": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Adds a new token to a specific group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "token"
+                ],
+                "summary": "Add group token",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Token information",
+                        "name": "token",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.Token"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.TokenResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/token/{group}/batch_delete": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes multiple tokens from a specific group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "token"
+                ],
+                "summary": "Delete group tokens",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Token IDs",
+                        "name": "ids",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "integer"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/token/{group}/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a paginated list of tokens for a specific group based on search criteria",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Search tokens for a specific group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "tokens": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/controller.TokenResponse"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/token/{group}/{id}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns detailed information about a specific token for a specific group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Get token by ID for a specific group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.TokenResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "put": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates an existing token in a specific group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "token"
+                ],
+                "summary": "Update group token",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Updated token information",
+                        "name": "token",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.Token"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.TokenResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes a specific token from a group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "token"
+                ],
+                "summary": "Delete group token",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/token/{group}/{id}/name": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the name of a token in a specific group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "token"
+                ],
+                "summary": "Update group token name",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Name information",
+                        "name": "name",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.UpdateTokenNameRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/token/{group}/{id}/status": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the status of a token in a specific group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "token"
+                ],
+                "summary": "Update group token status",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Status information",
+                        "name": "status",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.UpdateTokenStatusRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a paginated list of all tokens",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Get all tokens",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "tokens": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/controller.TokenResponse"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens/batch_delete": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes multiple tokens by their IDs",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Delete multiple tokens",
+                "parameters": [
+                    {
+                        "description": "Token IDs",
+                        "name": "ids",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "integer"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a paginated list of tokens based on search criteria",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Search tokens",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Keyword",
+                        "name": "keyword",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Order",
+                        "name": "order",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Name",
+                        "name": "name",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Key",
+                        "name": "key",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Status",
+                        "name": "status",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Group",
+                        "name": "group",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "tokens": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/controller.TokenResponse"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens/{group}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a paginated list of all tokens for a specific group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Get all tokens for a specific group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "tokens": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/controller.TokenResponse"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens/{id}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns detailed information about a specific token",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Get token by ID",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.TokenResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "put": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates an existing token's information",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Update token",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Updated token information",
+                        "name": "token",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.Token"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.TokenResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes a specific token by ID",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Delete token",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens/{id}/name": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the name of a specific token",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Update token name",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Name information",
+                        "name": "name",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.UpdateTokenNameRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens/{id}/status": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the status of a specific token",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Update token status",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Status information",
+                        "name": "status",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.UpdateTokenStatusRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/audio/speech": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "AudioSpeech",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "AudioSpeech",
+                "parameters": [
+                    {
+                        "description": "Request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.TextToSpeechRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "audio binary",
+                        "schema": {
+                            "type": "file"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/audio/transcription": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "AudioTranscription",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "AudioTranscription",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Model",
+                        "name": "model",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "file",
+                        "description": "File",
+                        "name": "file",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.SttJSONResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/audio/translation": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "AudioTranslation",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "AudioTranslation",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Model",
+                        "name": "model",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "file",
+                        "description": "File",
+                        "name": "file",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.SttJSONResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/chat/completions": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "ChatCompletions",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "ChatCompletions",
+                "parameters": [
+                    {
+                        "description": "Request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.GeneralOpenAIRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.TextResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/completions": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Completions",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "Completions",
+                "parameters": [
+                    {
+                        "description": "Request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.GeneralOpenAIRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.TextResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/dashboard/subscription": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get subscription",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "Get subscription",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/openai.SubscriptionResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/dashboard/usage": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get usage",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "Get usage",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/openai.UsageResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/embeddings": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Embeddings",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "Embeddings",
+                "parameters": [
+                    {
+                        "description": "Request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.EmbeddingRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.EmbeddingResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/images/generations": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "ImagesGenerations",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "ImagesGenerations",
+                "parameters": [
+                    {
+                        "description": "Request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.ImageRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.ImageResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/models": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "List all models",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "List models",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "type": "object",
+                            "properties": {
+                                "data": {
+                                    "type": "array",
+                                    "items": {
+                                        "$ref": "#/definitions/controller.OpenAIModels"
+                                    }
+                                },
+                                "object": {
+                                    "type": "string"
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/models/{model}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Retrieve a model",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "Retrieve model",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/controller.OpenAIModels"
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/parse-pdf": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "ParsePdf",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "ParsePdf",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Model",
+                        "name": "model",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "file",
+                        "description": "File",
+                        "name": "file",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.ParsePdfResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/rerank": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Rerank",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "Rerank",
+                "parameters": [
+                    {
+                        "description": "Request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.RerankRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.RerankResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    },
+    "definitions": {
+        "channeltype.AdaptorMeta": {
+            "type": "object",
+            "properties": {
+                "defaultBaseUrl": {
+                    "type": "string"
+                },
+                "keyHelp": {
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.AddChannelRequest": {
+            "type": "object",
+            "properties": {
+                "base_url": {
+                    "type": "string"
+                },
+                "config": {
+                    "$ref": "#/definitions/model.ChannelConfig"
+                },
+                "key": {
+                    "type": "string"
+                },
+                "model_mapping": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "string"
+                    }
+                },
+                "models": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "name": {
+                    "type": "string"
+                },
+                "priority": {
+                    "type": "integer"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "type": {
+                    "type": "integer"
+                }
+            }
+        },
+        "controller.BuiltinModelConfig": {
+            "type": "object",
+            "properties": {
+                "cache_creation_price": {
+                    "type": "number"
+                },
+                "cached_price": {
+                    "type": "number"
+                },
+                "config": {
+                    "type": "object",
+                    "additionalProperties": {}
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "exclude_from_tests": {
+                    "type": "boolean"
+                },
+                "image_batch_size": {
+                    "type": "integer"
+                },
+                "image_prices": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "number"
+                    }
+                },
+                "input_price": {
+                    "type": "number"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "output_price": {
+                    "type": "number"
+                },
+                "owner": {
+                    "$ref": "#/definitions/model.ModelOwner"
+                },
+                "rpm": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "integer"
+                },
+                "type": {
+                    "$ref": "#/definitions/mode.Mode"
+                },
+                "updated_at": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.GroupResponse": {
+            "type": "object",
+            "properties": {
+                "accessed_at": {
+                    "type": "string"
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "request_count": {
+                    "type": "integer"
+                },
+                "rpm": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "integer"
+                    }
+                },
+                "rpm_ratio": {
+                    "type": "number"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "integer"
+                    }
+                },
+                "tpm_ratio": {
+                    "type": "number"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "controller.ImportChannelFromOneAPIRequest": {
+            "type": "object",
+            "properties": {
+                "dsn": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.OpenAIModelPermission": {
+            "type": "object",
+            "properties": {
+                "allow_create_engine": {
+                    "type": "boolean"
+                },
+                "allow_fine_tuning": {
+                    "type": "boolean"
+                },
+                "allow_logprobs": {
+                    "type": "boolean"
+                },
+                "allow_sampling": {
+                    "type": "boolean"
+                },
+                "allow_search_indices": {
+                    "type": "boolean"
+                },
+                "allow_view": {
+                    "type": "boolean"
+                },
+                "created": {
+                    "type": "integer"
+                },
+                "group": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "is_blocking": {
+                    "type": "boolean"
+                },
+                "object": {
+                    "type": "string"
+                },
+                "organization": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.OpenAIModels": {
+            "type": "object",
+            "properties": {
+                "created": {
+                    "type": "integer"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "object": {
+                    "type": "string"
+                },
+                "owned_by": {
+                    "type": "string"
+                },
+                "parent": {
+                    "type": "string"
+                },
+                "permission": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/controller.OpenAIModelPermission"
+                    }
+                },
+                "root": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.SaveModelConfigsRequest": {
+            "type": "object",
+            "properties": {
+                "cache_creation_price": {
+                    "type": "number"
+                },
+                "cached_price": {
+                    "type": "number"
+                },
+                "config": {
+                    "type": "object",
+                    "additionalProperties": {}
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "exclude_from_tests": {
+                    "type": "boolean"
+                },
+                "image_batch_size": {
+                    "type": "integer"
+                },
+                "image_prices": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "number"
+                    }
+                },
+                "input_price": {
+                    "type": "number"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "output_price": {
+                    "type": "number"
+                },
+                "owner": {
+                    "$ref": "#/definitions/model.ModelOwner"
+                },
+                "rpm": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "integer"
+                },
+                "type": {
+                    "$ref": "#/definitions/mode.Mode"
+                },
+                "updated_at": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.StatusData": {
+            "type": "object",
+            "properties": {
+                "startTime": {
+                    "type": "integer"
+                }
+            }
+        },
+        "controller.TestResult": {
+            "type": "object",
+            "properties": {
+                "data": {
+                    "$ref": "#/definitions/model.ChannelTest"
+                },
+                "message": {
+                    "type": "string"
+                },
+                "success": {
+                    "type": "boolean"
+                }
+            }
+        },
+        "controller.TokenResponse": {
+            "type": "object",
+            "properties": {
+                "accessed_at": {
+                    "type": "string"
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "expired_at": {
+                    "type": "string"
+                },
+                "group": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "integer"
+                },
+                "key": {
+                    "type": "string"
+                },
+                "models": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "name": {
+                    "type": "string"
+                },
+                "quota": {
+                    "type": "number"
+                },
+                "request_count": {
+                    "type": "integer"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "subnets": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "controller.UpdateChannelStatusRequest": {
+            "type": "object",
+            "properties": {
+                "status": {
+                    "type": "integer"
+                }
+            }
+        },
+        "controller.UpdateTokenNameRequest": {
+            "type": "object",
+            "properties": {
+                "name": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.UpdateTokenStatusRequest": {
+            "type": "object",
+            "properties": {
+                "status": {
+                    "type": "integer"
+                }
+            }
+        },
+        "middleware.APIResponse": {
+            "type": "object",
+            "properties": {
+                "data": {},
+                "message": {
+                    "type": "string"
+                },
+                "success": {
+                    "type": "boolean"
+                }
+            }
+        },
+        "mode.Mode": {
+            "type": "integer",
+            "enum": [
+                0,
+                1,
+                2,
+                3,
+                4,
+                5,
+                6,
+                7,
+                8,
+                9,
+                10,
+                11
+            ],
+            "x-enum-varnames": [
+                "Unknown",
+                "ChatCompletions",
+                "Completions",
+                "Embeddings",
+                "Moderations",
+                "ImagesGenerations",
+                "Edits",
+                "AudioSpeech",
+                "AudioTranscription",
+                "AudioTranslation",
+                "Rerank",
+                "ParsePdf"
+            ]
+        },
+        "model.Audio": {
+            "type": "object",
+            "properties": {
+                "format": {
+                    "type": "string"
+                },
+                "voice": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.Channel": {
+            "type": "object",
+            "properties": {
+                "balance": {
+                    "type": "number"
+                },
+                "balance_threshold": {
+                    "type": "number"
+                },
+                "balance_updated_at": {
+                    "type": "string"
+                },
+                "base_url": {
+                    "type": "string"
+                },
+                "channel_tests": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.ChannelTest"
+                    }
+                },
+                "config": {
+                    "$ref": "#/definitions/model.ChannelConfig"
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "enabled_auto_balance_check": {
+                    "type": "boolean"
+                },
+                "id": {
+                    "type": "integer"
+                },
+                "key": {
+                    "type": "string"
+                },
+                "last_test_error_at": {
+                    "type": "string"
+                },
+                "model_mapping": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "string"
+                    }
+                },
+                "models": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "name": {
+                    "type": "string"
+                },
+                "priority": {
+                    "type": "integer"
+                },
+                "request_count": {
+                    "type": "integer"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "type": {
+                    "type": "integer"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.ChannelConfig": {
+            "type": "object",
+            "properties": {
+                "split_think": {
+                    "type": "boolean"
+                }
+            }
+        },
+        "model.ChannelTest": {
+            "type": "object",
+            "properties": {
+                "actual_model": {
+                    "type": "string"
+                },
+                "channel_id": {
+                    "type": "integer"
+                },
+                "channel_name": {
+                    "type": "string"
+                },
+                "channel_type": {
+                    "type": "integer"
+                },
+                "code": {
+                    "type": "integer"
+                },
+                "mode": {
+                    "$ref": "#/definitions/mode.Mode"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "response": {
+                    "type": "string"
+                },
+                "success": {
+                    "type": "boolean"
+                },
+                "test_at": {
+                    "type": "string"
+                },
+                "took": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.ChartData": {
+            "type": "object",
+            "properties": {
+                "exception_count": {
+                    "type": "integer"
+                },
+                "request_count": {
+                    "type": "integer"
+                },
+                "timestamp": {
+                    "type": "integer"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.DashboardResponse": {
+            "type": "object",
+            "properties": {
+                "chart_data": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.ChartData"
+                    }
+                },
+                "exception_count": {
+                    "type": "integer"
+                },
+                "rpm": {
+                    "type": "integer"
+                },
+                "total_count": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "integer"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.Document": {
+            "type": "object",
+            "properties": {
+                "text": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.EmbeddingRequest": {
+            "type": "object",
+            "properties": {
+                "dimensions": {
+                    "type": "integer"
+                },
+                "encoding_format": {
+                    "type": "string"
+                },
+                "input": {
+                    "type": "string"
+                },
+                "model": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.EmbeddingResponse": {
+            "type": "object",
+            "properties": {
+                "data": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.EmbeddingResponseItem"
+                    }
+                },
+                "model": {
+                    "type": "string"
+                },
+                "object": {
+                    "type": "string"
+                },
+                "usage": {
+                    "$ref": "#/definitions/model.Usage"
+                }
+            }
+        },
+        "model.EmbeddingResponseItem": {
+            "type": "object",
+            "properties": {
+                "embedding": {
+                    "type": "array",
+                    "items": {
+                        "type": "number"
+                    }
+                },
+                "index": {
+                    "type": "integer"
+                },
+                "object": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.Function": {
+            "type": "object",
+            "properties": {
+                "arguments": {
+                    "type": "string"
+                },
+                "description": {
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                },
+                "parameters": {}
+            }
+        },
+        "model.GeneralOpenAIRequest": {
+            "type": "object",
+            "properties": {
+                "audio": {
+                    "$ref": "#/definitions/model.Audio"
+                },
+                "dimensions": {
+                    "type": "integer"
+                },
+                "encoding_format": {
+                    "type": "string"
+                },
+                "frequency_penalty": {
+                    "type": "number"
+                },
+                "function_call": {},
+                "functions": {},
+                "input": {},
+                "instruction": {
+                    "type": "string"
+                },
+                "logit_bias": {},
+                "logprobs": {
+                    "type": "boolean"
+                },
+                "max_completion_tokens": {
+                    "type": "integer"
+                },
+                "max_tokens": {
+                    "type": "integer"
+                },
+                "messages": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.Message"
+                    }
+                },
+                "metadata": {},
+                "modalities": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "model": {
+                    "type": "string"
+                },
+                "n": {
+                    "type": "integer"
+                },
+                "num_ctx": {
+                    "type": "integer"
+                },
+                "parallel_tool_calls": {
+                    "type": "boolean"
+                },
+                "prediction": {},
+                "presence_penalty": {
+                    "type": "number"
+                },
+                "prompt": {},
+                "quality": {
+                    "type": "string"
+                },
+                "response_format": {
+                    "$ref": "#/definitions/model.ResponseFormat"
+                },
+                "seed": {
+                    "type": "number"
+                },
+                "service_tier": {
+                    "type": "string"
+                },
+                "size": {
+                    "type": "string"
+                },
+                "stop": {},
+                "store": {
+                    "type": "boolean"
+                },
+                "stream": {
+                    "type": "boolean"
+                },
+                "stream_options": {
+                    "$ref": "#/definitions/model.StreamOptions"
+                },
+                "style": {
+                    "type": "string"
+                },
+                "temperature": {
+                    "type": "number"
+                },
+                "tool_choice": {},
+                "tools": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.Tool"
+                    }
+                },
+                "top_k": {
+                    "type": "integer"
+                },
+                "top_logprobs": {
+                    "type": "integer"
+                },
+                "top_p": {
+                    "type": "number"
+                },
+                "user": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.GetGroupLogsResult": {
+            "type": "object",
+            "properties": {
+                "logs": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.Log"
+                    }
+                },
+                "models": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "token_names": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "total": {
+                    "type": "integer"
+                }
+            }
+        },
+        "model.GetLogsResult": {
+            "type": "object",
+            "properties": {
+                "logs": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.Log"
+                    }
+                },
+                "total": {
+                    "type": "integer"
+                }
+            }
+        },
+        "model.Group": {
+            "type": "object",
+            "properties": {
+                "created_at": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "request_count": {
+                    "type": "integer"
+                },
+                "rpm": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "integer"
+                    }
+                },
+                "rpm_ratio": {
+                    "type": "number"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "integer"
+                    }
+                },
+                "tpm_ratio": {
+                    "type": "number"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.GroupDashboardResponse": {
+            "type": "object",
+            "properties": {
+                "chart_data": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.ChartData"
+                    }
+                },
+                "exception_count": {
+                    "type": "integer"
+                },
+                "models": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "rpm": {
+                    "type": "integer"
+                },
+                "token_names": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "total_count": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "integer"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.ImageData": {
+            "type": "object",
+            "properties": {
+                "b64_json": {
+                    "type": "string"
+                },
+                "revised_prompt": {
+                    "type": "string"
+                },
+                "url": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.ImageRequest": {
+            "type": "object",
+            "properties": {
+                "model": {
+                    "type": "string"
+                },
+                "n": {
+                    "type": "integer"
+                },
+                "prompt": {
+                    "type": "string"
+                },
+                "quality": {
+                    "type": "string"
+                },
+                "response_format": {
+                    "type": "string"
+                },
+                "size": {
+                    "type": "string"
+                },
+                "style": {
+                    "type": "string"
+                },
+                "user": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.ImageResponse": {
+            "type": "object",
+            "properties": {
+                "created": {
+                    "type": "integer"
+                },
+                "data": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.ImageData"
+                    }
+                }
+            }
+        },
+        "model.JSONSchema": {
+            "type": "object",
+            "properties": {
+                "description": {
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                },
+                "schema": {
+                    "type": "object",
+                    "additionalProperties": true
+                },
+                "strict": {
+                    "type": "boolean"
+                }
+            }
+        },
+        "model.Log": {
+            "type": "object",
+            "properties": {
+                "cache_creation_price": {
+                    "type": "number"
+                },
+                "cache_creation_tokens": {
+                    "type": "integer"
+                },
+                "cached_price": {
+                    "type": "number"
+                },
+                "cached_tokens": {
+                    "type": "integer"
+                },
+                "channel": {
+                    "type": "integer"
+                },
+                "code": {
+                    "type": "integer"
+                },
+                "completion_price": {
+                    "type": "number"
+                },
+                "completion_tokens": {
+                    "type": "integer"
+                },
+                "content": {
+                    "type": "string"
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "downstream_result": {
+                    "type": "boolean"
+                },
+                "endpoint": {
+                    "type": "string"
+                },
+                "group": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "integer"
+                },
+                "ip": {
+                    "type": "string"
+                },
+                "mode": {
+                    "type": "integer"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "price": {
+                    "type": "number"
+                },
+                "prompt_tokens": {
+                    "type": "integer"
+                },
+                "request_at": {
+                    "type": "string"
+                },
+                "request_detail": {
+                    "$ref": "#/definitions/model.RequestDetail"
+                },
+                "request_id": {
+                    "type": "string"
+                },
+                "retry_times": {
+                    "type": "integer"
+                },
+                "timestamp_trunc_by_day": {
+                    "type": "integer"
+                },
+                "timestamp_trunc_by_hour": {
+                    "type": "integer"
+                },
+                "token_id": {
+                    "type": "integer"
+                },
+                "token_name": {
+                    "type": "string"
+                },
+                "total_tokens": {
+                    "type": "integer"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.Message": {
+            "type": "object",
+            "properties": {
+                "content": {},
+                "name": {
+                    "type": "string"
+                },
+                "reasoning_content": {
+                    "type": "string"
+                },
+                "role": {
+                    "type": "string"
+                },
+                "tool_call_id": {
+                    "type": "string"
+                },
+                "tool_calls": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.Tool"
+                    }
+                }
+            }
+        },
+        "model.ModelConfig": {
+            "type": "object",
+            "properties": {
+                "cache_creation_price": {
+                    "type": "number"
+                },
+                "cached_price": {
+                    "type": "number"
+                },
+                "config": {
+                    "type": "object",
+                    "additionalProperties": {}
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "exclude_from_tests": {
+                    "type": "boolean"
+                },
+                "image_batch_size": {
+                    "type": "integer"
+                },
+                "image_prices": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "number"
+                    }
+                },
+                "input_price": {
+                    "type": "number"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "output_price": {
+                    "type": "number"
+                },
+                "owner": {
+                    "$ref": "#/definitions/model.ModelOwner"
+                },
+                "rpm": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "integer"
+                },
+                "type": {
+                    "$ref": "#/definitions/mode.Mode"
+                },
+                "updated_at": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.ModelCostRank": {
+            "type": "object",
+            "properties": {
+                "model": {
+                    "type": "string"
+                },
+                "total": {
+                    "type": "integer"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.ModelOwner": {
+            "type": "string",
+            "enum": [
+                "openai",
+                "alibaba",
+                "tencent",
+                "xunfei",
+                "deepseek",
+                "moonshot",
+                "minimax",
+                "baidu",
+                "google",
+                "baai",
+                "funaudiollm",
+                "doubao",
+                "fishaudio",
+                "chatglm",
+                "stabilityai",
+                "netease",
+                "ai360",
+                "anthropic",
+                "meta",
+                "baichuan",
+                "mistral",
+                "openchat",
+                "microsoft",
+                "defog",
+                "nexusflow",
+                "cohere",
+                "huggingface",
+                "lingyiwanwu",
+                "stepfun",
+                "xai",
+                "doc2x"
+            ],
+            "x-enum-varnames": [
+                "ModelOwnerOpenAI",
+                "ModelOwnerAlibaba",
+                "ModelOwnerTencent",
+                "ModelOwnerXunfei",
+                "ModelOwnerDeepSeek",
+                "ModelOwnerMoonshot",
+                "ModelOwnerMiniMax",
+                "ModelOwnerBaidu",
+                "ModelOwnerGoogle",
+                "ModelOwnerBAAI",
+                "ModelOwnerFunAudioLLM",
+                "ModelOwnerDoubao",
+                "ModelOwnerFishAudio",
+                "ModelOwnerChatGLM",
+                "ModelOwnerStabilityAI",
+                "ModelOwnerNetease",
+                "ModelOwnerAI360",
+                "ModelOwnerAnthropic",
+                "ModelOwnerMeta",
+                "ModelOwnerBaichuan",
+                "ModelOwnerMistral",
+                "ModelOwnerOpenChat",
+                "ModelOwnerMicrosoft",
+                "ModelOwnerDefog",
+                "ModelOwnerNexusFlow",
+                "ModelOwnerCohere",
+                "ModelOwnerHuggingFace",
+                "ModelOwnerLingyiWanwu",
+                "ModelOwnerStepFun",
+                "ModelOwnerXAI",
+                "ModelOwnerDoc2x"
+            ]
+        },
+        "model.Option": {
+            "type": "object",
+            "properties": {
+                "key": {
+                    "type": "string"
+                },
+                "value": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.ParsePdfResponse": {
+            "type": "object",
+            "properties": {
+                "markdown": {
+                    "type": "string"
+                },
+                "pages": {
+                    "type": "integer"
+                }
+            }
+        },
+        "model.PromptTokensDetails": {
+            "type": "object",
+            "properties": {
+                "cache_creation_tokens": {
+                    "type": "integer"
+                },
+                "cached_tokens": {
+                    "type": "integer"
+                }
+            }
+        },
+        "model.RequestDetail": {
+            "type": "object",
+            "properties": {
+                "id": {
+                    "type": "integer"
+                },
+                "log_id": {
+                    "type": "integer"
+                },
+                "request_body": {
+                    "type": "string"
+                },
+                "request_body_truncated": {
+                    "type": "boolean"
+                },
+                "response_body": {
+                    "type": "string"
+                },
+                "response_body_truncated": {
+                    "type": "boolean"
+                }
+            }
+        },
+        "model.RerankMeta": {
+            "type": "object",
+            "properties": {
+                "model": {
+                    "type": "string"
+                },
+                "tokens": {
+                    "$ref": "#/definitions/model.RerankMetaTokens"
+                }
+            }
+        },
+        "model.RerankMetaTokens": {
+            "type": "object",
+            "properties": {
+                "input_tokens": {
+                    "type": "integer"
+                },
+                "output_tokens": {
+                    "type": "integer"
+                }
+            }
+        },
+        "model.RerankRequest": {
+            "type": "object",
+            "properties": {
+                "documents": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "max_chunks_per_doc": {
+                    "type": "integer"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "overlap_tokens": {
+                    "type": "integer"
+                },
+                "query": {
+                    "type": "string"
+                },
+                "return_documents": {
+                    "type": "boolean"
+                },
+                "top_n": {
+                    "type": "integer"
+                }
+            }
+        },
+        "model.RerankResponse": {
+            "type": "object",
+            "properties": {
+                "id": {
+                    "type": "string"
+                },
+                "meta": {
+                    "$ref": "#/definitions/model.RerankMeta"
+                },
+                "results": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.RerankResult"
+                    }
+                }
+            }
+        },
+        "model.RerankResult": {
+            "type": "object",
+            "properties": {
+                "document": {
+                    "$ref": "#/definitions/model.Document"
+                },
+                "index": {
+                    "type": "integer"
+                },
+                "relevance_score": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.ResponseFormat": {
+            "type": "object",
+            "properties": {
+                "json_schema": {
+                    "$ref": "#/definitions/model.JSONSchema"
+                },
+                "type": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.StreamOptions": {
+            "type": "object",
+            "properties": {
+                "include_usage": {
+                    "type": "boolean"
+                }
+            }
+        },
+        "model.SttJSONResponse": {
+            "type": "object",
+            "properties": {
+                "text": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.TextResponse": {
+            "type": "object",
+            "properties": {
+                "choices": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.TextResponseChoice"
+                    }
+                },
+                "created": {
+                    "type": "integer"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "object": {
+                    "type": "string"
+                },
+                "usage": {
+                    "$ref": "#/definitions/model.Usage"
+                }
+            }
+        },
+        "model.TextResponseChoice": {
+            "type": "object",
+            "properties": {
+                "finish_reason": {
+                    "type": "string"
+                },
+                "index": {
+                    "type": "integer"
+                },
+                "message": {
+                    "$ref": "#/definitions/model.Message"
+                },
+                "text": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.TextToSpeechRequest": {
+            "type": "object",
+            "required": [
+                "input",
+                "model",
+                "voice"
+            ],
+            "properties": {
+                "input": {
+                    "type": "string"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "response_format": {
+                    "type": "string"
+                },
+                "speed": {
+                    "type": "number"
+                },
+                "voice": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.Token": {
+            "type": "object",
+            "properties": {
+                "created_at": {
+                    "type": "string"
+                },
+                "expired_at": {
+                    "type": "string"
+                },
+                "group": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "integer"
+                },
+                "key": {
+                    "type": "string"
+                },
+                "models": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "name": {
+                    "type": "string"
+                },
+                "quota": {
+                    "type": "number"
+                },
+                "request_count": {
+                    "type": "integer"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "subnets": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.Tool": {
+            "type": "object",
+            "properties": {
+                "function": {
+                    "$ref": "#/definitions/model.Function"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "type": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.Usage": {
+            "type": "object",
+            "properties": {
+                "completion_tokens": {
+                    "type": "integer"
+                },
+                "prompt_tokens": {
+                    "type": "integer"
+                },
+                "prompt_tokens_details": {
+                    "$ref": "#/definitions/model.PromptTokensDetails"
+                },
+                "total_tokens": {
+                    "type": "integer"
+                }
+            }
+        },
+        "openai.SubscriptionResponse": {
+            "type": "object",
+            "properties": {
+                "access_until": {
+                    "type": "integer"
+                },
+                "hard_limit_usd": {
+                    "type": "number"
+                },
+                "has_payment_method": {
+                    "type": "boolean"
+                },
+                "object": {
+                    "type": "string"
+                },
+                "soft_limit_usd": {
+                    "type": "number"
+                },
+                "system_hard_limit_usd": {
+                    "type": "number"
+                }
+            }
+        },
+        "openai.UsageResponse": {
+            "type": "object",
+            "properties": {
+                "object": {
+                    "type": "string"
+                },
+                "total_usage": {
+                    "description": "DailyCosts []OpenAIUsageDailyCost ` + "`" + `json:\"daily_costs\"` + "`" + `",
+                    "type": "number"
+                }
+            }
+        }
+    },
+    "securityDefinitions": {
+        "ApiKeyAuth": {
+            "type": "apiKey",
+            "name": "Authorization",
+            "in": "header"
+        }
+    }
+}`
+
+// SwaggerInfo holds exported Swagger Info so clients can modify it
+var SwaggerInfo = &swag.Spec{
+	Version:          "",
+	Host:             "",
+	BasePath:         "",
+	Schemes:          []string{},
+	Title:            "",
+	Description:      "",
+	InfoInstanceName: "swagger",
+	SwaggerTemplate:  docTemplate,
+	LeftDelim:        "{{",
+	RightDelim:       "}}",
+}
+
+func init() {
+	swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
+}

+ 6884 - 0
docs/swagger.json

@@ -0,0 +1,6884 @@
+{
+    "swagger": "2.0",
+    "info": {
+        "contact": {}
+    },
+    "paths": {
+        "/api/channel": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Adds a new channel to the system",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Add a single channel",
+                "parameters": [
+                    {
+                        "description": "Channel information",
+                        "name": "channel",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.AddChannelRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channel/{id}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns detailed information about a specific channel",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Get a channel by ID",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.Channel"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "put": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates an existing channel by its ID",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Update a channel",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Updated channel information",
+                        "name": "channel",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.AddChannelRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.Channel"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes a channel by its ID",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Delete a channel",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channel/{id}/balance": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the balance for a single channel",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Update channel balance",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "number"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channel/{id}/models": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Tests all models in the channel",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Test channel models",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/controller.TestResult"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channel/{id}/status": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the status of a channel by its ID",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Update channel status",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Status information",
+                        "name": "status",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.UpdateChannelStatusRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channel/{id}/{model}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Tests a single model in the channel",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Test channel model",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "Model name",
+                        "name": "model",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.ChannelTest"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a paginated list of channels with optional filters",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Get channels with pagination",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Filter by id",
+                        "name": "id",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by name",
+                        "name": "name",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by key",
+                        "name": "key",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Filter by channel type",
+                        "name": "channel_type",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by base URL",
+                        "name": "base_url",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Order by field",
+                        "name": "order",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "channels": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/model.Channel"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Adds multiple channels in a batch operation",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Add multiple channels",
+                "parameters": [
+                    {
+                        "description": "Channel information",
+                        "name": "channels",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "$ref": "#/definitions/controller.AddChannelRequest"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/all": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of all channels without pagination",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Get all channels",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.Channel"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/balance": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the balance for all channels",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Update all channels balance",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/batch_delete": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes multiple channels by their IDs",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Delete multiple channels",
+                "parameters": [
+                    {
+                        "description": "Channel IDs",
+                        "name": "ids",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "integer"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/import/oneapi": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Imports channels from OneAPI",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Import channel from OneAPI",
+                "parameters": [
+                    {
+                        "description": "Import channel from OneAPI request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.ImportChannelFromOneAPIRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {}
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Search channels with keyword and optional filters",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Search channels",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Search keyword",
+                        "name": "keyword",
+                        "in": "query",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Filter by id",
+                        "name": "id",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by name",
+                        "name": "name",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by key",
+                        "name": "key",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Filter by channel type",
+                        "name": "channel_type",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by base URL",
+                        "name": "base_url",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Order by field",
+                        "name": "order",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "channels": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/model.Channel"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/test": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Tests all channels",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channel"
+                ],
+                "summary": "Test all channels",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/controller.TestResult"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/type_metas": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns metadata for all channel types",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Get channel type metadata",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "$ref": "#/definitions/channeltype.AdaptorMeta"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/channels/type_names": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of all available channel type names",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "channels"
+                ],
+                "summary": "Get all channel type names",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "string"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/dashboard": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns the general dashboard data including usage statistics and metrics",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "dashboard"
+                ],
+                "summary": "Get dashboard data",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.DashboardResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/dashboard/{group}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns dashboard data and metrics specific to the given group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "dashboard"
+                ],
+                "summary": "Get dashboard data for a specific group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name or ID",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.GroupDashboardResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/dashboard/{group}/models": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns model-specific metrics and usage data for the given group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "dashboard"
+                ],
+                "summary": "Get model usage data for a specific group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name or ID",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/group/{group}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns detailed information about a specific group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Get a group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.GroupResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "put": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates an existing group with the given information",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Update a group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Updated group information",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.Group"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Creates a new group with the given information",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Create a new group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Group information",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.Group"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes a group by its name",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Delete a group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/group/{group}/rpm": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the RPM (Requests Per Minute) for a group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Update group RPM",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "RPM information",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/group/{group}/rpm_ratio": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the RPM (Requests Per Minute) ratio for a group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Update group RPM ratio",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "RPM ratio information",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/group/{group}/status": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the status of a group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Update group status",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Status information",
+                        "name": "status",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/group/{group}/tpm": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the TPM (Tokens Per Minute) for a group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Update group TPM",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "TPM information",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/group/{group}/tpm_ratio": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the TPM (Tokens Per Minute) ratio for a group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "group"
+                ],
+                "summary": "Update group TPM ratio",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "TPM ratio information",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/groups": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of all groups with pagination",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "groups"
+                ],
+                "summary": "Get all groups",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "groups": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/controller.GroupResponse"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/groups/batch_delete": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes multiple groups by their IDs",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "groups"
+                ],
+                "summary": "Delete multiple groups",
+                "parameters": [
+                    {
+                        "description": "Group IDs",
+                        "name": "ids",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "string"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/groups/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Search groups with keyword and pagination",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "groups"
+                ],
+                "summary": "Search groups",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Search keyword",
+                        "name": "keyword",
+                        "in": "query",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "groups": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/controller.GroupResponse"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/log/{group}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get logs for a specific group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "log"
+                ],
+                "summary": "Get group logs",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Start timestamp (milliseconds)",
+                        "name": "start_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "End timestamp (milliseconds)",
+                        "name": "end_time",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.GetGroupLogsResult"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/log/{group}/detail/{log_id}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get detailed information about a specific log entry in a group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "log"
+                ],
+                "summary": "Get group log detail",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "Log ID",
+                        "name": "log_id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.RequestDetail"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/log/{group}/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Search logs for a specific group with filters",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "log"
+                ],
+                "summary": "Search group logs",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Start timestamp (milliseconds)",
+                        "name": "start_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "End timestamp (milliseconds)",
+                        "name": "end_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by token name",
+                        "name": "token_name",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by model name",
+                        "name": "model",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Filter by status",
+                        "name": "status",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.GetGroupLogsResult"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/log/{group}/used/models": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get a list of models that have been used in a specific group's logs",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "log"
+                ],
+                "summary": "Get group used models",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "type": "string"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/log/{group}/used/token_names": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get a list of token names that have been used in a specific group's logs",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "log"
+                ],
+                "summary": "Get group used token names",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "type": "string"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/logs": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a paginated list of all logs with optional filters",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "logs"
+                ],
+                "summary": "Get all logs",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Start timestamp (milliseconds)",
+                        "name": "start_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "End timestamp (milliseconds)",
+                        "name": "end_time",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.GetLogsResult"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes logs older than the specified retention period",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "logs"
+                ],
+                "summary": "Delete historical logs",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "integer"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/logs/consume_error": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Search for logs with consumption errors",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "logs"
+                ],
+                "summary": "Search consumption errors",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Start timestamp (milliseconds)",
+                        "name": "start_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "End timestamp (milliseconds)",
+                        "name": "end_time",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "logs": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/model.RequestDetail"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/logs/detail/{log_id}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get detailed information about a specific log entry",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "logs"
+                ],
+                "summary": "Get log detail",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Log ID",
+                        "name": "log_id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.RequestDetail"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/logs/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Search logs with various filters",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "logs"
+                ],
+                "summary": "Search logs",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Start timestamp (milliseconds)",
+                        "name": "start_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "End timestamp (milliseconds)",
+                        "name": "end_time",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by token name",
+                        "name": "token_name",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Filter by model name",
+                        "name": "model",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Filter by status",
+                        "name": "status",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.GetLogsResult"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/logs/used/models": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get a list of models that have been used in logs",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "logs"
+                ],
+                "summary": "Get used models",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "type": "string"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/model_config": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Saves a model config",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Save model config",
+                "parameters": [
+                    {
+                        "description": "Model config",
+                        "name": "config",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.SaveModelConfigsRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/model_config/{model}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a model config",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Get model config",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Model name",
+                        "name": "model",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.ModelConfig"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes a model config",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Delete model config",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Model name",
+                        "name": "model",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/model_configs": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Saves a list of model configs",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Save model configs",
+                "parameters": [
+                    {
+                        "description": "Model configs",
+                        "name": "configs",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "$ref": "#/definitions/controller.SaveModelConfigsRequest"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/model_configs/batch_delete": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes a list of model configs",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Delete model configs",
+                "parameters": [
+                    {
+                        "description": "Model names",
+                        "name": "models",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "string"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/model_cost_rank": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns ranking data for models based on cost",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "dashboard"
+                ],
+                "summary": "Get model cost ranking data",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelCostRank"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/model_cost_rank/{group}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns model cost ranking data specific to the given group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "dashboard"
+                ],
+                "summary": "Get model cost ranking data for a specific group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name or ID",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelCostRank"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/modelconfigs": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of model configs with pagination",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Get model configs",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "configs": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/model.ModelConfig"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/modelconfigs/all": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of all model configs",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Get all model configs",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/modelconfigs/contains": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of model configs by models contains",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Get model configs by models contains",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/modelconfigs/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of model configs by keyword",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "modelconfig"
+                ],
+                "summary": "Search model configs",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "configs": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/model.ModelConfig"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/builtin": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of builtin models",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get builtin models",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/controller.BuiltinModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/builtin/channel": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel builtin models",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get channel builtin models",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "array",
+                                                "items": {
+                                                    "$ref": "#/definitions/controller.BuiltinModelConfig"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/builtin/channel/{type}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel builtin models by type",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get channel builtin models by type",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Channel type",
+                        "name": "type",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/controller.BuiltinModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/default": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel default models and mapping",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get channel default models and mapping",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "mapping": {
+                                                                "type": "object",
+                                                                "additionalProperties": {
+                                                                    "type": "string"
+                                                                }
+                                                            },
+                                                            "models": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "type": "string"
+                                                                }
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/default/{type}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel default models and mapping by type",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get channel default models and mapping by type",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Channel type",
+                        "name": "type",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "mapping": {
+                                                                "type": "object",
+                                                                "additionalProperties": {
+                                                                    "type": "string"
+                                                                }
+                                                            },
+                                                            "models": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "type": "string"
+                                                                }
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/enabled": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of enabled models",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get enabled models",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/enabled/channel": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel enabled models",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get channel enabled models",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "array",
+                                                "items": {
+                                                    "$ref": "#/definitions/model.ModelConfig"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/models/enabled/channel/{type}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel enabled models by type",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "model"
+                ],
+                "summary": "Get channel enabled models by type",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Channel type",
+                        "name": "type",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.ModelConfig"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/monitor": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of all channel model error rates",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Get all channel model error rates",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "object",
+                                                "additionalProperties": {
+                                                    "type": "number"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Clears all model errors",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Clear all model errors",
+                "responses": {
+                    "204": {
+                        "description": "No Content",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/monitor/banned_channels": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of all banned model channels",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Get all banned model channels",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "array",
+                                                "items": {
+                                                    "type": "integer"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/monitor/models": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of models error rate",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Get models error rate",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "number"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/monitor/{id}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of channel model error rates",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Get channel model error rates",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "type": "object",
+                                                "additionalProperties": {
+                                                    "type": "number"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Clears all model errors for a specific channel",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Clear channel all model errors",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "204": {
+                        "description": "No Content",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/monitor/{id}/{model}": {
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Clears model errors for a specific channel and model",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "monitor"
+                ],
+                "summary": "Clear channel model errors",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Channel ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "Model name",
+                        "name": "model",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "204": {
+                        "description": "No Content",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/options": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a list of options",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "option"
+                ],
+                "summary": "Get options",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "string"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "put": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates multiple options",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "option"
+                ],
+                "summary": "Update options",
+                "parameters": [
+                    {
+                        "description": "Options",
+                        "name": "options",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "object",
+                            "additionalProperties": {
+                                "type": "string"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/options/{key}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a single option",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "option"
+                ],
+                "summary": "Get option",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Option key",
+                        "name": "key",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/model.Option"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "put": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates a single option",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "option"
+                ],
+                "summary": "Update option",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Option key",
+                        "name": "key",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Option value",
+                        "name": "value",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/status": {
+            "get": {
+                "description": "Returns the status of the server",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "misc"
+                ],
+                "summary": "Get status",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.StatusData"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/token/{group}": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Adds a new token to a specific group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "token"
+                ],
+                "summary": "Add group token",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Token information",
+                        "name": "token",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.Token"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.TokenResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/token/{group}/batch_delete": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes multiple tokens from a specific group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "token"
+                ],
+                "summary": "Delete group tokens",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Token IDs",
+                        "name": "ids",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "integer"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/token/{group}/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a paginated list of tokens for a specific group based on search criteria",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Search tokens for a specific group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "tokens": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/controller.TokenResponse"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/token/{group}/{id}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns detailed information about a specific token for a specific group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Get token by ID for a specific group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.TokenResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "put": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates an existing token in a specific group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "token"
+                ],
+                "summary": "Update group token",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Updated token information",
+                        "name": "token",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.Token"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.TokenResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes a specific token from a group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "token"
+                ],
+                "summary": "Delete group token",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/token/{group}/{id}/name": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the name of a token in a specific group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "token"
+                ],
+                "summary": "Update group token name",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Name information",
+                        "name": "name",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.UpdateTokenNameRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/token/{group}/{id}/status": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the status of a token in a specific group",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "token"
+                ],
+                "summary": "Update group token status",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Status information",
+                        "name": "status",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.UpdateTokenStatusRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a paginated list of all tokens",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Get all tokens",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Page number",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Items per page",
+                        "name": "per_page",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "tokens": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/controller.TokenResponse"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens/batch_delete": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes multiple tokens by their IDs",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Delete multiple tokens",
+                "parameters": [
+                    {
+                        "description": "Token IDs",
+                        "name": "ids",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "integer"
+                            }
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens/search": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a paginated list of tokens based on search criteria",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Search tokens",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Keyword",
+                        "name": "keyword",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Order",
+                        "name": "order",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Name",
+                        "name": "name",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Key",
+                        "name": "key",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "Status",
+                        "name": "status",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "Group",
+                        "name": "group",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "tokens": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/controller.TokenResponse"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens/{group}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns a paginated list of all tokens for a specific group",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Get all tokens for a specific group",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Group name",
+                        "name": "group",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "allOf": [
+                                                    {},
+                                                    {
+                                                        "type": "object",
+                                                        "properties": {
+                                                            "tokens": {
+                                                                "type": "array",
+                                                                "items": {
+                                                                    "$ref": "#/definitions/controller.TokenResponse"
+                                                                }
+                                                            },
+                                                            "total": {
+                                                                "type": "integer"
+                                                            }
+                                                        }
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens/{id}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Returns detailed information about a specific token",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Get token by ID",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.TokenResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "put": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates an existing token's information",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Update token",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Updated token information",
+                        "name": "token",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.Token"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/middleware.APIResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/controller.TokenResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Deletes a specific token by ID",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Delete token",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens/{id}/name": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the name of a specific token",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Update token name",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Name information",
+                        "name": "name",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.UpdateTokenNameRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/tokens/{id}/status": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Updates the status of a specific token",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "tokens"
+                ],
+                "summary": "Update token status",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "Token ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Status information",
+                        "name": "status",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/controller.UpdateTokenStatusRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/middleware.APIResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/audio/speech": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "AudioSpeech",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "AudioSpeech",
+                "parameters": [
+                    {
+                        "description": "Request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.TextToSpeechRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "audio binary",
+                        "schema": {
+                            "type": "file"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/audio/transcription": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "AudioTranscription",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "AudioTranscription",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Model",
+                        "name": "model",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "file",
+                        "description": "File",
+                        "name": "file",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.SttJSONResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/audio/translation": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "AudioTranslation",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "AudioTranslation",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Model",
+                        "name": "model",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "file",
+                        "description": "File",
+                        "name": "file",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.SttJSONResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/chat/completions": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "ChatCompletions",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "ChatCompletions",
+                "parameters": [
+                    {
+                        "description": "Request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.GeneralOpenAIRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.TextResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/completions": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Completions",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "Completions",
+                "parameters": [
+                    {
+                        "description": "Request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.GeneralOpenAIRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.TextResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/dashboard/subscription": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get subscription",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "Get subscription",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/openai.SubscriptionResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/dashboard/usage": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Get usage",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "Get usage",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/openai.UsageResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/embeddings": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Embeddings",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "Embeddings",
+                "parameters": [
+                    {
+                        "description": "Request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.EmbeddingRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.EmbeddingResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/images/generations": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "ImagesGenerations",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "ImagesGenerations",
+                "parameters": [
+                    {
+                        "description": "Request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.ImageRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.ImageResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/models": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "List all models",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "List models",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "type": "object",
+                            "properties": {
+                                "data": {
+                                    "type": "array",
+                                    "items": {
+                                        "$ref": "#/definitions/controller.OpenAIModels"
+                                    }
+                                },
+                                "object": {
+                                    "type": "string"
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/models/{model}": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Retrieve a model",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "Retrieve model",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/controller.OpenAIModels"
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/parse-pdf": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "ParsePdf",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "ParsePdf",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Model",
+                        "name": "model",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "file",
+                        "description": "File",
+                        "name": "file",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.ParsePdfResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "/v1/rerank": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "Rerank",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "relay"
+                ],
+                "summary": "Rerank",
+                "parameters": [
+                    {
+                        "description": "Request",
+                        "name": "request",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/model.RerankRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "Optional Aiproxy-Channel header",
+                        "name": "Aiproxy-Channel",
+                        "in": "header"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.RerankResponse"
+                        },
+                        "headers": {
+                            "X-RateLimit-Limit-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Requests"
+                            },
+                            "X-RateLimit-Limit-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Limit-Tokens"
+                            },
+                            "X-RateLimit-Remaining-Requests": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Requests"
+                            },
+                            "X-RateLimit-Remaining-Tokens": {
+                                "type": "integer",
+                                "description": "X-RateLimit-Remaining-Tokens"
+                            },
+                            "X-RateLimit-Reset-Requests": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Requests"
+                            },
+                            "X-RateLimit-Reset-Tokens": {
+                                "type": "string",
+                                "description": "X-RateLimit-Reset-Tokens"
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    },
+    "definitions": {
+        "channeltype.AdaptorMeta": {
+            "type": "object",
+            "properties": {
+                "defaultBaseUrl": {
+                    "type": "string"
+                },
+                "keyHelp": {
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.AddChannelRequest": {
+            "type": "object",
+            "properties": {
+                "base_url": {
+                    "type": "string"
+                },
+                "config": {
+                    "$ref": "#/definitions/model.ChannelConfig"
+                },
+                "key": {
+                    "type": "string"
+                },
+                "model_mapping": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "string"
+                    }
+                },
+                "models": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "name": {
+                    "type": "string"
+                },
+                "priority": {
+                    "type": "integer"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "type": {
+                    "type": "integer"
+                }
+            }
+        },
+        "controller.BuiltinModelConfig": {
+            "type": "object",
+            "properties": {
+                "cache_creation_price": {
+                    "type": "number"
+                },
+                "cached_price": {
+                    "type": "number"
+                },
+                "config": {
+                    "type": "object",
+                    "additionalProperties": {}
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "exclude_from_tests": {
+                    "type": "boolean"
+                },
+                "image_batch_size": {
+                    "type": "integer"
+                },
+                "image_prices": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "number"
+                    }
+                },
+                "input_price": {
+                    "type": "number"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "output_price": {
+                    "type": "number"
+                },
+                "owner": {
+                    "$ref": "#/definitions/model.ModelOwner"
+                },
+                "rpm": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "integer"
+                },
+                "type": {
+                    "$ref": "#/definitions/mode.Mode"
+                },
+                "updated_at": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.GroupResponse": {
+            "type": "object",
+            "properties": {
+                "accessed_at": {
+                    "type": "string"
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "request_count": {
+                    "type": "integer"
+                },
+                "rpm": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "integer"
+                    }
+                },
+                "rpm_ratio": {
+                    "type": "number"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "integer"
+                    }
+                },
+                "tpm_ratio": {
+                    "type": "number"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "controller.ImportChannelFromOneAPIRequest": {
+            "type": "object",
+            "properties": {
+                "dsn": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.OpenAIModelPermission": {
+            "type": "object",
+            "properties": {
+                "allow_create_engine": {
+                    "type": "boolean"
+                },
+                "allow_fine_tuning": {
+                    "type": "boolean"
+                },
+                "allow_logprobs": {
+                    "type": "boolean"
+                },
+                "allow_sampling": {
+                    "type": "boolean"
+                },
+                "allow_search_indices": {
+                    "type": "boolean"
+                },
+                "allow_view": {
+                    "type": "boolean"
+                },
+                "created": {
+                    "type": "integer"
+                },
+                "group": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "is_blocking": {
+                    "type": "boolean"
+                },
+                "object": {
+                    "type": "string"
+                },
+                "organization": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.OpenAIModels": {
+            "type": "object",
+            "properties": {
+                "created": {
+                    "type": "integer"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "object": {
+                    "type": "string"
+                },
+                "owned_by": {
+                    "type": "string"
+                },
+                "parent": {
+                    "type": "string"
+                },
+                "permission": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/controller.OpenAIModelPermission"
+                    }
+                },
+                "root": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.SaveModelConfigsRequest": {
+            "type": "object",
+            "properties": {
+                "cache_creation_price": {
+                    "type": "number"
+                },
+                "cached_price": {
+                    "type": "number"
+                },
+                "config": {
+                    "type": "object",
+                    "additionalProperties": {}
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "exclude_from_tests": {
+                    "type": "boolean"
+                },
+                "image_batch_size": {
+                    "type": "integer"
+                },
+                "image_prices": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "number"
+                    }
+                },
+                "input_price": {
+                    "type": "number"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "output_price": {
+                    "type": "number"
+                },
+                "owner": {
+                    "$ref": "#/definitions/model.ModelOwner"
+                },
+                "rpm": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "integer"
+                },
+                "type": {
+                    "$ref": "#/definitions/mode.Mode"
+                },
+                "updated_at": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.StatusData": {
+            "type": "object",
+            "properties": {
+                "startTime": {
+                    "type": "integer"
+                }
+            }
+        },
+        "controller.TestResult": {
+            "type": "object",
+            "properties": {
+                "data": {
+                    "$ref": "#/definitions/model.ChannelTest"
+                },
+                "message": {
+                    "type": "string"
+                },
+                "success": {
+                    "type": "boolean"
+                }
+            }
+        },
+        "controller.TokenResponse": {
+            "type": "object",
+            "properties": {
+                "accessed_at": {
+                    "type": "string"
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "expired_at": {
+                    "type": "string"
+                },
+                "group": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "integer"
+                },
+                "key": {
+                    "type": "string"
+                },
+                "models": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "name": {
+                    "type": "string"
+                },
+                "quota": {
+                    "type": "number"
+                },
+                "request_count": {
+                    "type": "integer"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "subnets": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "controller.UpdateChannelStatusRequest": {
+            "type": "object",
+            "properties": {
+                "status": {
+                    "type": "integer"
+                }
+            }
+        },
+        "controller.UpdateTokenNameRequest": {
+            "type": "object",
+            "properties": {
+                "name": {
+                    "type": "string"
+                }
+            }
+        },
+        "controller.UpdateTokenStatusRequest": {
+            "type": "object",
+            "properties": {
+                "status": {
+                    "type": "integer"
+                }
+            }
+        },
+        "middleware.APIResponse": {
+            "type": "object",
+            "properties": {
+                "data": {},
+                "message": {
+                    "type": "string"
+                },
+                "success": {
+                    "type": "boolean"
+                }
+            }
+        },
+        "mode.Mode": {
+            "type": "integer",
+            "enum": [
+                0,
+                1,
+                2,
+                3,
+                4,
+                5,
+                6,
+                7,
+                8,
+                9,
+                10,
+                11
+            ],
+            "x-enum-varnames": [
+                "Unknown",
+                "ChatCompletions",
+                "Completions",
+                "Embeddings",
+                "Moderations",
+                "ImagesGenerations",
+                "Edits",
+                "AudioSpeech",
+                "AudioTranscription",
+                "AudioTranslation",
+                "Rerank",
+                "ParsePdf"
+            ]
+        },
+        "model.Audio": {
+            "type": "object",
+            "properties": {
+                "format": {
+                    "type": "string"
+                },
+                "voice": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.Channel": {
+            "type": "object",
+            "properties": {
+                "balance": {
+                    "type": "number"
+                },
+                "balance_threshold": {
+                    "type": "number"
+                },
+                "balance_updated_at": {
+                    "type": "string"
+                },
+                "base_url": {
+                    "type": "string"
+                },
+                "channel_tests": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.ChannelTest"
+                    }
+                },
+                "config": {
+                    "$ref": "#/definitions/model.ChannelConfig"
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "enabled_auto_balance_check": {
+                    "type": "boolean"
+                },
+                "id": {
+                    "type": "integer"
+                },
+                "key": {
+                    "type": "string"
+                },
+                "last_test_error_at": {
+                    "type": "string"
+                },
+                "model_mapping": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "string"
+                    }
+                },
+                "models": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "name": {
+                    "type": "string"
+                },
+                "priority": {
+                    "type": "integer"
+                },
+                "request_count": {
+                    "type": "integer"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "type": {
+                    "type": "integer"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.ChannelConfig": {
+            "type": "object",
+            "properties": {
+                "split_think": {
+                    "type": "boolean"
+                }
+            }
+        },
+        "model.ChannelTest": {
+            "type": "object",
+            "properties": {
+                "actual_model": {
+                    "type": "string"
+                },
+                "channel_id": {
+                    "type": "integer"
+                },
+                "channel_name": {
+                    "type": "string"
+                },
+                "channel_type": {
+                    "type": "integer"
+                },
+                "code": {
+                    "type": "integer"
+                },
+                "mode": {
+                    "$ref": "#/definitions/mode.Mode"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "response": {
+                    "type": "string"
+                },
+                "success": {
+                    "type": "boolean"
+                },
+                "test_at": {
+                    "type": "string"
+                },
+                "took": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.ChartData": {
+            "type": "object",
+            "properties": {
+                "exception_count": {
+                    "type": "integer"
+                },
+                "request_count": {
+                    "type": "integer"
+                },
+                "timestamp": {
+                    "type": "integer"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.DashboardResponse": {
+            "type": "object",
+            "properties": {
+                "chart_data": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.ChartData"
+                    }
+                },
+                "exception_count": {
+                    "type": "integer"
+                },
+                "rpm": {
+                    "type": "integer"
+                },
+                "total_count": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "integer"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.Document": {
+            "type": "object",
+            "properties": {
+                "text": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.EmbeddingRequest": {
+            "type": "object",
+            "properties": {
+                "dimensions": {
+                    "type": "integer"
+                },
+                "encoding_format": {
+                    "type": "string"
+                },
+                "input": {
+                    "type": "string"
+                },
+                "model": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.EmbeddingResponse": {
+            "type": "object",
+            "properties": {
+                "data": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.EmbeddingResponseItem"
+                    }
+                },
+                "model": {
+                    "type": "string"
+                },
+                "object": {
+                    "type": "string"
+                },
+                "usage": {
+                    "$ref": "#/definitions/model.Usage"
+                }
+            }
+        },
+        "model.EmbeddingResponseItem": {
+            "type": "object",
+            "properties": {
+                "embedding": {
+                    "type": "array",
+                    "items": {
+                        "type": "number"
+                    }
+                },
+                "index": {
+                    "type": "integer"
+                },
+                "object": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.Function": {
+            "type": "object",
+            "properties": {
+                "arguments": {
+                    "type": "string"
+                },
+                "description": {
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                },
+                "parameters": {}
+            }
+        },
+        "model.GeneralOpenAIRequest": {
+            "type": "object",
+            "properties": {
+                "audio": {
+                    "$ref": "#/definitions/model.Audio"
+                },
+                "dimensions": {
+                    "type": "integer"
+                },
+                "encoding_format": {
+                    "type": "string"
+                },
+                "frequency_penalty": {
+                    "type": "number"
+                },
+                "function_call": {},
+                "functions": {},
+                "input": {},
+                "instruction": {
+                    "type": "string"
+                },
+                "logit_bias": {},
+                "logprobs": {
+                    "type": "boolean"
+                },
+                "max_completion_tokens": {
+                    "type": "integer"
+                },
+                "max_tokens": {
+                    "type": "integer"
+                },
+                "messages": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.Message"
+                    }
+                },
+                "metadata": {},
+                "modalities": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "model": {
+                    "type": "string"
+                },
+                "n": {
+                    "type": "integer"
+                },
+                "num_ctx": {
+                    "type": "integer"
+                },
+                "parallel_tool_calls": {
+                    "type": "boolean"
+                },
+                "prediction": {},
+                "presence_penalty": {
+                    "type": "number"
+                },
+                "prompt": {},
+                "quality": {
+                    "type": "string"
+                },
+                "response_format": {
+                    "$ref": "#/definitions/model.ResponseFormat"
+                },
+                "seed": {
+                    "type": "number"
+                },
+                "service_tier": {
+                    "type": "string"
+                },
+                "size": {
+                    "type": "string"
+                },
+                "stop": {},
+                "store": {
+                    "type": "boolean"
+                },
+                "stream": {
+                    "type": "boolean"
+                },
+                "stream_options": {
+                    "$ref": "#/definitions/model.StreamOptions"
+                },
+                "style": {
+                    "type": "string"
+                },
+                "temperature": {
+                    "type": "number"
+                },
+                "tool_choice": {},
+                "tools": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.Tool"
+                    }
+                },
+                "top_k": {
+                    "type": "integer"
+                },
+                "top_logprobs": {
+                    "type": "integer"
+                },
+                "top_p": {
+                    "type": "number"
+                },
+                "user": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.GetGroupLogsResult": {
+            "type": "object",
+            "properties": {
+                "logs": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.Log"
+                    }
+                },
+                "models": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "token_names": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "total": {
+                    "type": "integer"
+                }
+            }
+        },
+        "model.GetLogsResult": {
+            "type": "object",
+            "properties": {
+                "logs": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.Log"
+                    }
+                },
+                "total": {
+                    "type": "integer"
+                }
+            }
+        },
+        "model.Group": {
+            "type": "object",
+            "properties": {
+                "created_at": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "request_count": {
+                    "type": "integer"
+                },
+                "rpm": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "integer"
+                    }
+                },
+                "rpm_ratio": {
+                    "type": "number"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "integer"
+                    }
+                },
+                "tpm_ratio": {
+                    "type": "number"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.GroupDashboardResponse": {
+            "type": "object",
+            "properties": {
+                "chart_data": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.ChartData"
+                    }
+                },
+                "exception_count": {
+                    "type": "integer"
+                },
+                "models": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "rpm": {
+                    "type": "integer"
+                },
+                "token_names": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "total_count": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "integer"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.ImageData": {
+            "type": "object",
+            "properties": {
+                "b64_json": {
+                    "type": "string"
+                },
+                "revised_prompt": {
+                    "type": "string"
+                },
+                "url": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.ImageRequest": {
+            "type": "object",
+            "properties": {
+                "model": {
+                    "type": "string"
+                },
+                "n": {
+                    "type": "integer"
+                },
+                "prompt": {
+                    "type": "string"
+                },
+                "quality": {
+                    "type": "string"
+                },
+                "response_format": {
+                    "type": "string"
+                },
+                "size": {
+                    "type": "string"
+                },
+                "style": {
+                    "type": "string"
+                },
+                "user": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.ImageResponse": {
+            "type": "object",
+            "properties": {
+                "created": {
+                    "type": "integer"
+                },
+                "data": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.ImageData"
+                    }
+                }
+            }
+        },
+        "model.JSONSchema": {
+            "type": "object",
+            "properties": {
+                "description": {
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                },
+                "schema": {
+                    "type": "object",
+                    "additionalProperties": true
+                },
+                "strict": {
+                    "type": "boolean"
+                }
+            }
+        },
+        "model.Log": {
+            "type": "object",
+            "properties": {
+                "cache_creation_price": {
+                    "type": "number"
+                },
+                "cache_creation_tokens": {
+                    "type": "integer"
+                },
+                "cached_price": {
+                    "type": "number"
+                },
+                "cached_tokens": {
+                    "type": "integer"
+                },
+                "channel": {
+                    "type": "integer"
+                },
+                "code": {
+                    "type": "integer"
+                },
+                "completion_price": {
+                    "type": "number"
+                },
+                "completion_tokens": {
+                    "type": "integer"
+                },
+                "content": {
+                    "type": "string"
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "downstream_result": {
+                    "type": "boolean"
+                },
+                "endpoint": {
+                    "type": "string"
+                },
+                "group": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "integer"
+                },
+                "ip": {
+                    "type": "string"
+                },
+                "mode": {
+                    "type": "integer"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "price": {
+                    "type": "number"
+                },
+                "prompt_tokens": {
+                    "type": "integer"
+                },
+                "request_at": {
+                    "type": "string"
+                },
+                "request_detail": {
+                    "$ref": "#/definitions/model.RequestDetail"
+                },
+                "request_id": {
+                    "type": "string"
+                },
+                "retry_times": {
+                    "type": "integer"
+                },
+                "timestamp_trunc_by_day": {
+                    "type": "integer"
+                },
+                "timestamp_trunc_by_hour": {
+                    "type": "integer"
+                },
+                "token_id": {
+                    "type": "integer"
+                },
+                "token_name": {
+                    "type": "string"
+                },
+                "total_tokens": {
+                    "type": "integer"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.Message": {
+            "type": "object",
+            "properties": {
+                "content": {},
+                "name": {
+                    "type": "string"
+                },
+                "reasoning_content": {
+                    "type": "string"
+                },
+                "role": {
+                    "type": "string"
+                },
+                "tool_call_id": {
+                    "type": "string"
+                },
+                "tool_calls": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.Tool"
+                    }
+                }
+            }
+        },
+        "model.ModelConfig": {
+            "type": "object",
+            "properties": {
+                "cache_creation_price": {
+                    "type": "number"
+                },
+                "cached_price": {
+                    "type": "number"
+                },
+                "config": {
+                    "type": "object",
+                    "additionalProperties": {}
+                },
+                "created_at": {
+                    "type": "string"
+                },
+                "exclude_from_tests": {
+                    "type": "boolean"
+                },
+                "image_batch_size": {
+                    "type": "integer"
+                },
+                "image_prices": {
+                    "type": "object",
+                    "additionalProperties": {
+                        "type": "number"
+                    }
+                },
+                "input_price": {
+                    "type": "number"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "output_price": {
+                    "type": "number"
+                },
+                "owner": {
+                    "$ref": "#/definitions/model.ModelOwner"
+                },
+                "rpm": {
+                    "type": "integer"
+                },
+                "tpm": {
+                    "type": "integer"
+                },
+                "type": {
+                    "$ref": "#/definitions/mode.Mode"
+                },
+                "updated_at": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.ModelCostRank": {
+            "type": "object",
+            "properties": {
+                "model": {
+                    "type": "string"
+                },
+                "total": {
+                    "type": "integer"
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.ModelOwner": {
+            "type": "string",
+            "enum": [
+                "openai",
+                "alibaba",
+                "tencent",
+                "xunfei",
+                "deepseek",
+                "moonshot",
+                "minimax",
+                "baidu",
+                "google",
+                "baai",
+                "funaudiollm",
+                "doubao",
+                "fishaudio",
+                "chatglm",
+                "stabilityai",
+                "netease",
+                "ai360",
+                "anthropic",
+                "meta",
+                "baichuan",
+                "mistral",
+                "openchat",
+                "microsoft",
+                "defog",
+                "nexusflow",
+                "cohere",
+                "huggingface",
+                "lingyiwanwu",
+                "stepfun",
+                "xai",
+                "doc2x"
+            ],
+            "x-enum-varnames": [
+                "ModelOwnerOpenAI",
+                "ModelOwnerAlibaba",
+                "ModelOwnerTencent",
+                "ModelOwnerXunfei",
+                "ModelOwnerDeepSeek",
+                "ModelOwnerMoonshot",
+                "ModelOwnerMiniMax",
+                "ModelOwnerBaidu",
+                "ModelOwnerGoogle",
+                "ModelOwnerBAAI",
+                "ModelOwnerFunAudioLLM",
+                "ModelOwnerDoubao",
+                "ModelOwnerFishAudio",
+                "ModelOwnerChatGLM",
+                "ModelOwnerStabilityAI",
+                "ModelOwnerNetease",
+                "ModelOwnerAI360",
+                "ModelOwnerAnthropic",
+                "ModelOwnerMeta",
+                "ModelOwnerBaichuan",
+                "ModelOwnerMistral",
+                "ModelOwnerOpenChat",
+                "ModelOwnerMicrosoft",
+                "ModelOwnerDefog",
+                "ModelOwnerNexusFlow",
+                "ModelOwnerCohere",
+                "ModelOwnerHuggingFace",
+                "ModelOwnerLingyiWanwu",
+                "ModelOwnerStepFun",
+                "ModelOwnerXAI",
+                "ModelOwnerDoc2x"
+            ]
+        },
+        "model.Option": {
+            "type": "object",
+            "properties": {
+                "key": {
+                    "type": "string"
+                },
+                "value": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.ParsePdfResponse": {
+            "type": "object",
+            "properties": {
+                "markdown": {
+                    "type": "string"
+                },
+                "pages": {
+                    "type": "integer"
+                }
+            }
+        },
+        "model.PromptTokensDetails": {
+            "type": "object",
+            "properties": {
+                "cache_creation_tokens": {
+                    "type": "integer"
+                },
+                "cached_tokens": {
+                    "type": "integer"
+                }
+            }
+        },
+        "model.RequestDetail": {
+            "type": "object",
+            "properties": {
+                "id": {
+                    "type": "integer"
+                },
+                "log_id": {
+                    "type": "integer"
+                },
+                "request_body": {
+                    "type": "string"
+                },
+                "request_body_truncated": {
+                    "type": "boolean"
+                },
+                "response_body": {
+                    "type": "string"
+                },
+                "response_body_truncated": {
+                    "type": "boolean"
+                }
+            }
+        },
+        "model.RerankMeta": {
+            "type": "object",
+            "properties": {
+                "model": {
+                    "type": "string"
+                },
+                "tokens": {
+                    "$ref": "#/definitions/model.RerankMetaTokens"
+                }
+            }
+        },
+        "model.RerankMetaTokens": {
+            "type": "object",
+            "properties": {
+                "input_tokens": {
+                    "type": "integer"
+                },
+                "output_tokens": {
+                    "type": "integer"
+                }
+            }
+        },
+        "model.RerankRequest": {
+            "type": "object",
+            "properties": {
+                "documents": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "max_chunks_per_doc": {
+                    "type": "integer"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "overlap_tokens": {
+                    "type": "integer"
+                },
+                "query": {
+                    "type": "string"
+                },
+                "return_documents": {
+                    "type": "boolean"
+                },
+                "top_n": {
+                    "type": "integer"
+                }
+            }
+        },
+        "model.RerankResponse": {
+            "type": "object",
+            "properties": {
+                "id": {
+                    "type": "string"
+                },
+                "meta": {
+                    "$ref": "#/definitions/model.RerankMeta"
+                },
+                "results": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.RerankResult"
+                    }
+                }
+            }
+        },
+        "model.RerankResult": {
+            "type": "object",
+            "properties": {
+                "document": {
+                    "$ref": "#/definitions/model.Document"
+                },
+                "index": {
+                    "type": "integer"
+                },
+                "relevance_score": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.ResponseFormat": {
+            "type": "object",
+            "properties": {
+                "json_schema": {
+                    "$ref": "#/definitions/model.JSONSchema"
+                },
+                "type": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.StreamOptions": {
+            "type": "object",
+            "properties": {
+                "include_usage": {
+                    "type": "boolean"
+                }
+            }
+        },
+        "model.SttJSONResponse": {
+            "type": "object",
+            "properties": {
+                "text": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.TextResponse": {
+            "type": "object",
+            "properties": {
+                "choices": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.TextResponseChoice"
+                    }
+                },
+                "created": {
+                    "type": "integer"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "object": {
+                    "type": "string"
+                },
+                "usage": {
+                    "$ref": "#/definitions/model.Usage"
+                }
+            }
+        },
+        "model.TextResponseChoice": {
+            "type": "object",
+            "properties": {
+                "finish_reason": {
+                    "type": "string"
+                },
+                "index": {
+                    "type": "integer"
+                },
+                "message": {
+                    "$ref": "#/definitions/model.Message"
+                },
+                "text": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.TextToSpeechRequest": {
+            "type": "object",
+            "required": [
+                "input",
+                "model",
+                "voice"
+            ],
+            "properties": {
+                "input": {
+                    "type": "string"
+                },
+                "model": {
+                    "type": "string"
+                },
+                "response_format": {
+                    "type": "string"
+                },
+                "speed": {
+                    "type": "number"
+                },
+                "voice": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.Token": {
+            "type": "object",
+            "properties": {
+                "created_at": {
+                    "type": "string"
+                },
+                "expired_at": {
+                    "type": "string"
+                },
+                "group": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "integer"
+                },
+                "key": {
+                    "type": "string"
+                },
+                "models": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "name": {
+                    "type": "string"
+                },
+                "quota": {
+                    "type": "number"
+                },
+                "request_count": {
+                    "type": "integer"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "subnets": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "used_amount": {
+                    "type": "number"
+                }
+            }
+        },
+        "model.Tool": {
+            "type": "object",
+            "properties": {
+                "function": {
+                    "$ref": "#/definitions/model.Function"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "type": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.Usage": {
+            "type": "object",
+            "properties": {
+                "completion_tokens": {
+                    "type": "integer"
+                },
+                "prompt_tokens": {
+                    "type": "integer"
+                },
+                "prompt_tokens_details": {
+                    "$ref": "#/definitions/model.PromptTokensDetails"
+                },
+                "total_tokens": {
+                    "type": "integer"
+                }
+            }
+        },
+        "openai.SubscriptionResponse": {
+            "type": "object",
+            "properties": {
+                "access_until": {
+                    "type": "integer"
+                },
+                "hard_limit_usd": {
+                    "type": "number"
+                },
+                "has_payment_method": {
+                    "type": "boolean"
+                },
+                "object": {
+                    "type": "string"
+                },
+                "soft_limit_usd": {
+                    "type": "number"
+                },
+                "system_hard_limit_usd": {
+                    "type": "number"
+                }
+            }
+        },
+        "openai.UsageResponse": {
+            "type": "object",
+            "properties": {
+                "object": {
+                    "type": "string"
+                },
+                "total_usage": {
+                    "description": "DailyCosts []OpenAIUsageDailyCost `json:\"daily_costs\"`",
+                    "type": "number"
+                }
+            }
+        }
+    },
+    "securityDefinitions": {
+        "ApiKeyAuth": {
+            "type": "apiKey",
+            "name": "Authorization",
+            "in": "header"
+        }
+    }
+}

+ 4242 - 0
docs/swagger.yaml

@@ -0,0 +1,4242 @@
+definitions:
+  channeltype.AdaptorMeta:
+    properties:
+      defaultBaseUrl:
+        type: string
+      keyHelp:
+        type: string
+      name:
+        type: string
+    type: object
+  controller.AddChannelRequest:
+    properties:
+      base_url:
+        type: string
+      config:
+        $ref: '#/definitions/model.ChannelConfig'
+      key:
+        type: string
+      model_mapping:
+        additionalProperties:
+          type: string
+        type: object
+      models:
+        items:
+          type: string
+        type: array
+      name:
+        type: string
+      priority:
+        type: integer
+      status:
+        type: integer
+      type:
+        type: integer
+    type: object
+  controller.BuiltinModelConfig:
+    properties:
+      cache_creation_price:
+        type: number
+      cached_price:
+        type: number
+      config:
+        additionalProperties: {}
+        type: object
+      created_at:
+        type: string
+      exclude_from_tests:
+        type: boolean
+      image_batch_size:
+        type: integer
+      image_prices:
+        additionalProperties:
+          type: number
+        type: object
+      input_price:
+        type: number
+      model:
+        type: string
+      output_price:
+        type: number
+      owner:
+        $ref: '#/definitions/model.ModelOwner'
+      rpm:
+        type: integer
+      tpm:
+        type: integer
+      type:
+        $ref: '#/definitions/mode.Mode'
+      updated_at:
+        type: string
+    type: object
+  controller.GroupResponse:
+    properties:
+      accessed_at:
+        type: string
+      created_at:
+        type: string
+      id:
+        type: string
+      request_count:
+        type: integer
+      rpm:
+        additionalProperties:
+          type: integer
+        type: object
+      rpm_ratio:
+        type: number
+      status:
+        type: integer
+      tpm:
+        additionalProperties:
+          type: integer
+        type: object
+      tpm_ratio:
+        type: number
+      used_amount:
+        type: number
+    type: object
+  controller.ImportChannelFromOneAPIRequest:
+    properties:
+      dsn:
+        type: string
+    type: object
+  controller.OpenAIModelPermission:
+    properties:
+      allow_create_engine:
+        type: boolean
+      allow_fine_tuning:
+        type: boolean
+      allow_logprobs:
+        type: boolean
+      allow_sampling:
+        type: boolean
+      allow_search_indices:
+        type: boolean
+      allow_view:
+        type: boolean
+      created:
+        type: integer
+      group:
+        type: string
+      id:
+        type: string
+      is_blocking:
+        type: boolean
+      object:
+        type: string
+      organization:
+        type: string
+    type: object
+  controller.OpenAIModels:
+    properties:
+      created:
+        type: integer
+      id:
+        type: string
+      object:
+        type: string
+      owned_by:
+        type: string
+      parent:
+        type: string
+      permission:
+        items:
+          $ref: '#/definitions/controller.OpenAIModelPermission'
+        type: array
+      root:
+        type: string
+    type: object
+  controller.SaveModelConfigsRequest:
+    properties:
+      cache_creation_price:
+        type: number
+      cached_price:
+        type: number
+      config:
+        additionalProperties: {}
+        type: object
+      created_at:
+        type: string
+      exclude_from_tests:
+        type: boolean
+      image_batch_size:
+        type: integer
+      image_prices:
+        additionalProperties:
+          type: number
+        type: object
+      input_price:
+        type: number
+      model:
+        type: string
+      output_price:
+        type: number
+      owner:
+        $ref: '#/definitions/model.ModelOwner'
+      rpm:
+        type: integer
+      tpm:
+        type: integer
+      type:
+        $ref: '#/definitions/mode.Mode'
+      updated_at:
+        type: string
+    type: object
+  controller.StatusData:
+    properties:
+      startTime:
+        type: integer
+    type: object
+  controller.TestResult:
+    properties:
+      data:
+        $ref: '#/definitions/model.ChannelTest'
+      message:
+        type: string
+      success:
+        type: boolean
+    type: object
+  controller.TokenResponse:
+    properties:
+      accessed_at:
+        type: string
+      created_at:
+        type: string
+      expired_at:
+        type: string
+      group:
+        type: string
+      id:
+        type: integer
+      key:
+        type: string
+      models:
+        items:
+          type: string
+        type: array
+      name:
+        type: string
+      quota:
+        type: number
+      request_count:
+        type: integer
+      status:
+        type: integer
+      subnets:
+        items:
+          type: string
+        type: array
+      used_amount:
+        type: number
+    type: object
+  controller.UpdateChannelStatusRequest:
+    properties:
+      status:
+        type: integer
+    type: object
+  controller.UpdateTokenNameRequest:
+    properties:
+      name:
+        type: string
+    type: object
+  controller.UpdateTokenStatusRequest:
+    properties:
+      status:
+        type: integer
+    type: object
+  middleware.APIResponse:
+    properties:
+      data: {}
+      message:
+        type: string
+      success:
+        type: boolean
+    type: object
+  mode.Mode:
+    enum:
+    - 0
+    - 1
+    - 2
+    - 3
+    - 4
+    - 5
+    - 6
+    - 7
+    - 8
+    - 9
+    - 10
+    - 11
+    type: integer
+    x-enum-varnames:
+    - Unknown
+    - ChatCompletions
+    - Completions
+    - Embeddings
+    - Moderations
+    - ImagesGenerations
+    - Edits
+    - AudioSpeech
+    - AudioTranscription
+    - AudioTranslation
+    - Rerank
+    - ParsePdf
+  model.Audio:
+    properties:
+      format:
+        type: string
+      voice:
+        type: string
+    type: object
+  model.Channel:
+    properties:
+      balance:
+        type: number
+      balance_threshold:
+        type: number
+      balance_updated_at:
+        type: string
+      base_url:
+        type: string
+      channel_tests:
+        items:
+          $ref: '#/definitions/model.ChannelTest'
+        type: array
+      config:
+        $ref: '#/definitions/model.ChannelConfig'
+      created_at:
+        type: string
+      enabled_auto_balance_check:
+        type: boolean
+      id:
+        type: integer
+      key:
+        type: string
+      last_test_error_at:
+        type: string
+      model_mapping:
+        additionalProperties:
+          type: string
+        type: object
+      models:
+        items:
+          type: string
+        type: array
+      name:
+        type: string
+      priority:
+        type: integer
+      request_count:
+        type: integer
+      status:
+        type: integer
+      type:
+        type: integer
+      used_amount:
+        type: number
+    type: object
+  model.ChannelConfig:
+    properties:
+      split_think:
+        type: boolean
+    type: object
+  model.ChannelTest:
+    properties:
+      actual_model:
+        type: string
+      channel_id:
+        type: integer
+      channel_name:
+        type: string
+      channel_type:
+        type: integer
+      code:
+        type: integer
+      mode:
+        $ref: '#/definitions/mode.Mode'
+      model:
+        type: string
+      response:
+        type: string
+      success:
+        type: boolean
+      test_at:
+        type: string
+      took:
+        type: number
+    type: object
+  model.ChartData:
+    properties:
+      exception_count:
+        type: integer
+      request_count:
+        type: integer
+      timestamp:
+        type: integer
+      used_amount:
+        type: number
+    type: object
+  model.DashboardResponse:
+    properties:
+      chart_data:
+        items:
+          $ref: '#/definitions/model.ChartData'
+        type: array
+      exception_count:
+        type: integer
+      rpm:
+        type: integer
+      total_count:
+        type: integer
+      tpm:
+        type: integer
+      used_amount:
+        type: number
+    type: object
+  model.Document:
+    properties:
+      text:
+        type: string
+    type: object
+  model.EmbeddingRequest:
+    properties:
+      dimensions:
+        type: integer
+      encoding_format:
+        type: string
+      input:
+        type: string
+      model:
+        type: string
+    type: object
+  model.EmbeddingResponse:
+    properties:
+      data:
+        items:
+          $ref: '#/definitions/model.EmbeddingResponseItem'
+        type: array
+      model:
+        type: string
+      object:
+        type: string
+      usage:
+        $ref: '#/definitions/model.Usage'
+    type: object
+  model.EmbeddingResponseItem:
+    properties:
+      embedding:
+        items:
+          type: number
+        type: array
+      index:
+        type: integer
+      object:
+        type: string
+    type: object
+  model.Function:
+    properties:
+      arguments:
+        type: string
+      description:
+        type: string
+      name:
+        type: string
+      parameters: {}
+    type: object
+  model.GeneralOpenAIRequest:
+    properties:
+      audio:
+        $ref: '#/definitions/model.Audio'
+      dimensions:
+        type: integer
+      encoding_format:
+        type: string
+      frequency_penalty:
+        type: number
+      function_call: {}
+      functions: {}
+      input: {}
+      instruction:
+        type: string
+      logit_bias: {}
+      logprobs:
+        type: boolean
+      max_completion_tokens:
+        type: integer
+      max_tokens:
+        type: integer
+      messages:
+        items:
+          $ref: '#/definitions/model.Message'
+        type: array
+      metadata: {}
+      modalities:
+        items:
+          type: string
+        type: array
+      model:
+        type: string
+      "n":
+        type: integer
+      num_ctx:
+        type: integer
+      parallel_tool_calls:
+        type: boolean
+      prediction: {}
+      presence_penalty:
+        type: number
+      prompt: {}
+      quality:
+        type: string
+      response_format:
+        $ref: '#/definitions/model.ResponseFormat'
+      seed:
+        type: number
+      service_tier:
+        type: string
+      size:
+        type: string
+      stop: {}
+      store:
+        type: boolean
+      stream:
+        type: boolean
+      stream_options:
+        $ref: '#/definitions/model.StreamOptions'
+      style:
+        type: string
+      temperature:
+        type: number
+      tool_choice: {}
+      tools:
+        items:
+          $ref: '#/definitions/model.Tool'
+        type: array
+      top_k:
+        type: integer
+      top_logprobs:
+        type: integer
+      top_p:
+        type: number
+      user:
+        type: string
+    type: object
+  model.GetGroupLogsResult:
+    properties:
+      logs:
+        items:
+          $ref: '#/definitions/model.Log'
+        type: array
+      models:
+        items:
+          type: string
+        type: array
+      token_names:
+        items:
+          type: string
+        type: array
+      total:
+        type: integer
+    type: object
+  model.GetLogsResult:
+    properties:
+      logs:
+        items:
+          $ref: '#/definitions/model.Log'
+        type: array
+      total:
+        type: integer
+    type: object
+  model.Group:
+    properties:
+      created_at:
+        type: string
+      id:
+        type: string
+      request_count:
+        type: integer
+      rpm:
+        additionalProperties:
+          type: integer
+        type: object
+      rpm_ratio:
+        type: number
+      status:
+        type: integer
+      tpm:
+        additionalProperties:
+          type: integer
+        type: object
+      tpm_ratio:
+        type: number
+      used_amount:
+        type: number
+    type: object
+  model.GroupDashboardResponse:
+    properties:
+      chart_data:
+        items:
+          $ref: '#/definitions/model.ChartData'
+        type: array
+      exception_count:
+        type: integer
+      models:
+        items:
+          type: string
+        type: array
+      rpm:
+        type: integer
+      token_names:
+        items:
+          type: string
+        type: array
+      total_count:
+        type: integer
+      tpm:
+        type: integer
+      used_amount:
+        type: number
+    type: object
+  model.ImageData:
+    properties:
+      b64_json:
+        type: string
+      revised_prompt:
+        type: string
+      url:
+        type: string
+    type: object
+  model.ImageRequest:
+    properties:
+      model:
+        type: string
+      "n":
+        type: integer
+      prompt:
+        type: string
+      quality:
+        type: string
+      response_format:
+        type: string
+      size:
+        type: string
+      style:
+        type: string
+      user:
+        type: string
+    type: object
+  model.ImageResponse:
+    properties:
+      created:
+        type: integer
+      data:
+        items:
+          $ref: '#/definitions/model.ImageData'
+        type: array
+    type: object
+  model.JSONSchema:
+    properties:
+      description:
+        type: string
+      name:
+        type: string
+      schema:
+        additionalProperties: true
+        type: object
+      strict:
+        type: boolean
+    type: object
+  model.Log:
+    properties:
+      cache_creation_price:
+        type: number
+      cache_creation_tokens:
+        type: integer
+      cached_price:
+        type: number
+      cached_tokens:
+        type: integer
+      channel:
+        type: integer
+      code:
+        type: integer
+      completion_price:
+        type: number
+      completion_tokens:
+        type: integer
+      content:
+        type: string
+      created_at:
+        type: string
+      downstream_result:
+        type: boolean
+      endpoint:
+        type: string
+      group:
+        type: string
+      id:
+        type: integer
+      ip:
+        type: string
+      mode:
+        type: integer
+      model:
+        type: string
+      price:
+        type: number
+      prompt_tokens:
+        type: integer
+      request_at:
+        type: string
+      request_detail:
+        $ref: '#/definitions/model.RequestDetail'
+      request_id:
+        type: string
+      retry_times:
+        type: integer
+      timestamp_trunc_by_day:
+        type: integer
+      timestamp_trunc_by_hour:
+        type: integer
+      token_id:
+        type: integer
+      token_name:
+        type: string
+      total_tokens:
+        type: integer
+      used_amount:
+        type: number
+    type: object
+  model.Message:
+    properties:
+      content: {}
+      name:
+        type: string
+      reasoning_content:
+        type: string
+      role:
+        type: string
+      tool_call_id:
+        type: string
+      tool_calls:
+        items:
+          $ref: '#/definitions/model.Tool'
+        type: array
+    type: object
+  model.ModelConfig:
+    properties:
+      cache_creation_price:
+        type: number
+      cached_price:
+        type: number
+      config:
+        additionalProperties: {}
+        type: object
+      created_at:
+        type: string
+      exclude_from_tests:
+        type: boolean
+      image_batch_size:
+        type: integer
+      image_prices:
+        additionalProperties:
+          type: number
+        type: object
+      input_price:
+        type: number
+      model:
+        type: string
+      output_price:
+        type: number
+      owner:
+        $ref: '#/definitions/model.ModelOwner'
+      rpm:
+        type: integer
+      tpm:
+        type: integer
+      type:
+        $ref: '#/definitions/mode.Mode'
+      updated_at:
+        type: string
+    type: object
+  model.ModelCostRank:
+    properties:
+      model:
+        type: string
+      total:
+        type: integer
+      used_amount:
+        type: number
+    type: object
+  model.ModelOwner:
+    enum:
+    - openai
+    - alibaba
+    - tencent
+    - xunfei
+    - deepseek
+    - moonshot
+    - minimax
+    - baidu
+    - google
+    - baai
+    - funaudiollm
+    - doubao
+    - fishaudio
+    - chatglm
+    - stabilityai
+    - netease
+    - ai360
+    - anthropic
+    - meta
+    - baichuan
+    - mistral
+    - openchat
+    - microsoft
+    - defog
+    - nexusflow
+    - cohere
+    - huggingface
+    - lingyiwanwu
+    - stepfun
+    - xai
+    - doc2x
+    type: string
+    x-enum-varnames:
+    - ModelOwnerOpenAI
+    - ModelOwnerAlibaba
+    - ModelOwnerTencent
+    - ModelOwnerXunfei
+    - ModelOwnerDeepSeek
+    - ModelOwnerMoonshot
+    - ModelOwnerMiniMax
+    - ModelOwnerBaidu
+    - ModelOwnerGoogle
+    - ModelOwnerBAAI
+    - ModelOwnerFunAudioLLM
+    - ModelOwnerDoubao
+    - ModelOwnerFishAudio
+    - ModelOwnerChatGLM
+    - ModelOwnerStabilityAI
+    - ModelOwnerNetease
+    - ModelOwnerAI360
+    - ModelOwnerAnthropic
+    - ModelOwnerMeta
+    - ModelOwnerBaichuan
+    - ModelOwnerMistral
+    - ModelOwnerOpenChat
+    - ModelOwnerMicrosoft
+    - ModelOwnerDefog
+    - ModelOwnerNexusFlow
+    - ModelOwnerCohere
+    - ModelOwnerHuggingFace
+    - ModelOwnerLingyiWanwu
+    - ModelOwnerStepFun
+    - ModelOwnerXAI
+    - ModelOwnerDoc2x
+  model.Option:
+    properties:
+      key:
+        type: string
+      value:
+        type: string
+    type: object
+  model.ParsePdfResponse:
+    properties:
+      markdown:
+        type: string
+      pages:
+        type: integer
+    type: object
+  model.PromptTokensDetails:
+    properties:
+      cache_creation_tokens:
+        type: integer
+      cached_tokens:
+        type: integer
+    type: object
+  model.RequestDetail:
+    properties:
+      id:
+        type: integer
+      log_id:
+        type: integer
+      request_body:
+        type: string
+      request_body_truncated:
+        type: boolean
+      response_body:
+        type: string
+      response_body_truncated:
+        type: boolean
+    type: object
+  model.RerankMeta:
+    properties:
+      model:
+        type: string
+      tokens:
+        $ref: '#/definitions/model.RerankMetaTokens'
+    type: object
+  model.RerankMetaTokens:
+    properties:
+      input_tokens:
+        type: integer
+      output_tokens:
+        type: integer
+    type: object
+  model.RerankRequest:
+    properties:
+      documents:
+        items:
+          type: string
+        type: array
+      max_chunks_per_doc:
+        type: integer
+      model:
+        type: string
+      overlap_tokens:
+        type: integer
+      query:
+        type: string
+      return_documents:
+        type: boolean
+      top_n:
+        type: integer
+    type: object
+  model.RerankResponse:
+    properties:
+      id:
+        type: string
+      meta:
+        $ref: '#/definitions/model.RerankMeta'
+      results:
+        items:
+          $ref: '#/definitions/model.RerankResult'
+        type: array
+    type: object
+  model.RerankResult:
+    properties:
+      document:
+        $ref: '#/definitions/model.Document'
+      index:
+        type: integer
+      relevance_score:
+        type: number
+    type: object
+  model.ResponseFormat:
+    properties:
+      json_schema:
+        $ref: '#/definitions/model.JSONSchema'
+      type:
+        type: string
+    type: object
+  model.StreamOptions:
+    properties:
+      include_usage:
+        type: boolean
+    type: object
+  model.SttJSONResponse:
+    properties:
+      text:
+        type: string
+    type: object
+  model.TextResponse:
+    properties:
+      choices:
+        items:
+          $ref: '#/definitions/model.TextResponseChoice'
+        type: array
+      created:
+        type: integer
+      id:
+        type: string
+      model:
+        type: string
+      object:
+        type: string
+      usage:
+        $ref: '#/definitions/model.Usage'
+    type: object
+  model.TextResponseChoice:
+    properties:
+      finish_reason:
+        type: string
+      index:
+        type: integer
+      message:
+        $ref: '#/definitions/model.Message'
+      text:
+        type: string
+    type: object
+  model.TextToSpeechRequest:
+    properties:
+      input:
+        type: string
+      model:
+        type: string
+      response_format:
+        type: string
+      speed:
+        type: number
+      voice:
+        type: string
+    required:
+    - input
+    - model
+    - voice
+    type: object
+  model.Token:
+    properties:
+      created_at:
+        type: string
+      expired_at:
+        type: string
+      group:
+        type: string
+      id:
+        type: integer
+      key:
+        type: string
+      models:
+        items:
+          type: string
+        type: array
+      name:
+        type: string
+      quota:
+        type: number
+      request_count:
+        type: integer
+      status:
+        type: integer
+      subnets:
+        items:
+          type: string
+        type: array
+      used_amount:
+        type: number
+    type: object
+  model.Tool:
+    properties:
+      function:
+        $ref: '#/definitions/model.Function'
+      id:
+        type: string
+      type:
+        type: string
+    type: object
+  model.Usage:
+    properties:
+      completion_tokens:
+        type: integer
+      prompt_tokens:
+        type: integer
+      prompt_tokens_details:
+        $ref: '#/definitions/model.PromptTokensDetails'
+      total_tokens:
+        type: integer
+    type: object
+  openai.SubscriptionResponse:
+    properties:
+      access_until:
+        type: integer
+      hard_limit_usd:
+        type: number
+      has_payment_method:
+        type: boolean
+      object:
+        type: string
+      soft_limit_usd:
+        type: number
+      system_hard_limit_usd:
+        type: number
+    type: object
+  openai.UsageResponse:
+    properties:
+      object:
+        type: string
+      total_usage:
+        description: DailyCosts []OpenAIUsageDailyCost `json:"daily_costs"`
+        type: number
+    type: object
+info:
+  contact: {}
+paths:
+  /api/channel:
+    post:
+      consumes:
+      - application/json
+      description: Adds a new channel to the system
+      parameters:
+      - description: Channel information
+        in: body
+        name: channel
+        required: true
+        schema:
+          $ref: '#/definitions/controller.AddChannelRequest'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Add a single channel
+      tags:
+      - channel
+  /api/channel/{id}:
+    delete:
+      description: Deletes a channel by its ID
+      parameters:
+      - description: Channel ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Delete a channel
+      tags:
+      - channel
+    get:
+      description: Returns detailed information about a specific channel
+      parameters:
+      - description: Channel ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.Channel'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get a channel by ID
+      tags:
+      - channel
+    put:
+      consumes:
+      - application/json
+      description: Updates an existing channel by its ID
+      parameters:
+      - description: Channel ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      - description: Updated channel information
+        in: body
+        name: channel
+        required: true
+        schema:
+          $ref: '#/definitions/controller.AddChannelRequest'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.Channel'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Update a channel
+      tags:
+      - channel
+  /api/channel/{id}/{model}:
+    get:
+      description: Tests a single model in the channel
+      parameters:
+      - description: Channel ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      - description: Model name
+        in: path
+        name: model
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.ChannelTest'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Test channel model
+      tags:
+      - channel
+  /api/channel/{id}/balance:
+    get:
+      description: Updates the balance for a single channel
+      parameters:
+      - description: Channel ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  type: number
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Update channel balance
+      tags:
+      - channel
+  /api/channel/{id}/models:
+    get:
+      description: Tests all models in the channel
+      parameters:
+      - description: Channel ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/controller.TestResult'
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Test channel models
+      tags:
+      - channel
+  /api/channel/{id}/status:
+    post:
+      consumes:
+      - application/json
+      description: Updates the status of a channel by its ID
+      parameters:
+      - description: Channel ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      - description: Status information
+        in: body
+        name: status
+        required: true
+        schema:
+          $ref: '#/definitions/controller.UpdateChannelStatusRequest'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update channel status
+      tags:
+      - channel
+  /api/channels:
+    get:
+      description: Returns a paginated list of channels with optional filters
+      parameters:
+      - description: Page number
+        in: query
+        name: page
+        type: integer
+      - description: Items per page
+        in: query
+        name: per_page
+        type: integer
+      - description: Filter by id
+        in: query
+        name: id
+        type: integer
+      - description: Filter by name
+        in: query
+        name: name
+        type: string
+      - description: Filter by key
+        in: query
+        name: key
+        type: string
+      - description: Filter by channel type
+        in: query
+        name: channel_type
+        type: integer
+      - description: Filter by base URL
+        in: query
+        name: base_url
+        type: string
+      - description: Order by field
+        in: query
+        name: order
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        channels:
+                          items:
+                            $ref: '#/definitions/model.Channel'
+                          type: array
+                        total:
+                          type: integer
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get channels with pagination
+      tags:
+      - channels
+    post:
+      consumes:
+      - application/json
+      description: Adds multiple channels in a batch operation
+      parameters:
+      - description: Channel information
+        in: body
+        name: channels
+        required: true
+        schema:
+          items:
+            $ref: '#/definitions/controller.AddChannelRequest'
+          type: array
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Add multiple channels
+      tags:
+      - channels
+  /api/channels/all:
+    get:
+      description: Returns a list of all channels without pagination
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/model.Channel'
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get all channels
+      tags:
+      - channels
+  /api/channels/balance:
+    get:
+      description: Updates the balance for all channels
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update all channels balance
+      tags:
+      - channel
+  /api/channels/batch_delete:
+    post:
+      consumes:
+      - application/json
+      description: Deletes multiple channels by their IDs
+      parameters:
+      - description: Channel IDs
+        in: body
+        name: ids
+        required: true
+        schema:
+          items:
+            type: integer
+          type: array
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Delete multiple channels
+      tags:
+      - channels
+  /api/channels/import/oneapi:
+    post:
+      description: Imports channels from OneAPI
+      parameters:
+      - description: Import channel from OneAPI request
+        in: body
+        name: request
+        required: true
+        schema:
+          $ref: '#/definitions/controller.ImportChannelFromOneAPIRequest'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items: {}
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Import channel from OneAPI
+      tags:
+      - channels
+  /api/channels/search:
+    get:
+      description: Search channels with keyword and optional filters
+      parameters:
+      - description: Search keyword
+        in: query
+        name: keyword
+        required: true
+        type: string
+      - description: Page number
+        in: query
+        name: page
+        type: integer
+      - description: Items per page
+        in: query
+        name: per_page
+        type: integer
+      - description: Filter by id
+        in: query
+        name: id
+        type: integer
+      - description: Filter by name
+        in: query
+        name: name
+        type: string
+      - description: Filter by key
+        in: query
+        name: key
+        type: string
+      - description: Filter by channel type
+        in: query
+        name: channel_type
+        type: integer
+      - description: Filter by base URL
+        in: query
+        name: base_url
+        type: string
+      - description: Order by field
+        in: query
+        name: order
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        channels:
+                          items:
+                            $ref: '#/definitions/model.Channel'
+                          type: array
+                        total:
+                          type: integer
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Search channels
+      tags:
+      - channels
+  /api/channels/test:
+    get:
+      description: Tests all channels
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/controller.TestResult'
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Test all channels
+      tags:
+      - channel
+  /api/channels/type_metas:
+    get:
+      description: Returns metadata for all channel types
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    $ref: '#/definitions/channeltype.AdaptorMeta'
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get channel type metadata
+      tags:
+      - channels
+  /api/channels/type_names:
+    get:
+      description: Returns a list of all available channel type names
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    type: string
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get all channel type names
+      tags:
+      - channels
+  /api/dashboard:
+    get:
+      description: Returns the general dashboard data including usage statistics and
+        metrics
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.DashboardResponse'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get dashboard data
+      tags:
+      - dashboard
+  /api/dashboard/{group}:
+    get:
+      description: Returns dashboard data and metrics specific to the given group
+      parameters:
+      - description: Group name or ID
+        in: path
+        name: group
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.GroupDashboardResponse'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get dashboard data for a specific group
+      tags:
+      - dashboard
+  /api/dashboard/{group}/models:
+    get:
+      description: Returns model-specific metrics and usage data for the given group
+      parameters:
+      - description: Group name or ID
+        in: path
+        name: group
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/model.ModelConfig'
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get model usage data for a specific group
+      tags:
+      - dashboard
+  /api/group/{group}:
+    delete:
+      description: Deletes a group by its name
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Delete a group
+      tags:
+      - group
+    get:
+      description: Returns detailed information about a specific group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/controller.GroupResponse'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get a group
+      tags:
+      - group
+    post:
+      consumes:
+      - application/json
+      description: Creates a new group with the given information
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Group information
+        in: body
+        name: data
+        required: true
+        schema:
+          type: object
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.Group'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Create a new group
+      tags:
+      - group
+    put:
+      consumes:
+      - application/json
+      description: Updates an existing group with the given information
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Updated group information
+        in: body
+        name: data
+        required: true
+        schema:
+          type: object
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.Group'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Update a group
+      tags:
+      - group
+  /api/group/{group}/rpm:
+    post:
+      consumes:
+      - application/json
+      description: Updates the RPM (Requests Per Minute) for a group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: RPM information
+        in: body
+        name: data
+        required: true
+        schema:
+          type: object
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update group RPM
+      tags:
+      - group
+  /api/group/{group}/rpm_ratio:
+    post:
+      consumes:
+      - application/json
+      description: Updates the RPM (Requests Per Minute) ratio for a group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: RPM ratio information
+        in: body
+        name: data
+        required: true
+        schema:
+          type: object
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update group RPM ratio
+      tags:
+      - group
+  /api/group/{group}/status:
+    post:
+      consumes:
+      - application/json
+      description: Updates the status of a group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Status information
+        in: body
+        name: status
+        required: true
+        schema:
+          type: object
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update group status
+      tags:
+      - group
+  /api/group/{group}/tpm:
+    post:
+      consumes:
+      - application/json
+      description: Updates the TPM (Tokens Per Minute) for a group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: TPM information
+        in: body
+        name: data
+        required: true
+        schema:
+          type: object
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update group TPM
+      tags:
+      - group
+  /api/group/{group}/tpm_ratio:
+    post:
+      consumes:
+      - application/json
+      description: Updates the TPM (Tokens Per Minute) ratio for a group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: TPM ratio information
+        in: body
+        name: data
+        required: true
+        schema:
+          type: object
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update group TPM ratio
+      tags:
+      - group
+  /api/groups:
+    get:
+      description: Returns a list of all groups with pagination
+      parameters:
+      - description: Page number
+        in: query
+        name: page
+        type: integer
+      - description: Items per page
+        in: query
+        name: per_page
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        groups:
+                          items:
+                            $ref: '#/definitions/controller.GroupResponse'
+                          type: array
+                        total:
+                          type: integer
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get all groups
+      tags:
+      - groups
+  /api/groups/batch_delete:
+    post:
+      consumes:
+      - application/json
+      description: Deletes multiple groups by their IDs
+      parameters:
+      - description: Group IDs
+        in: body
+        name: ids
+        required: true
+        schema:
+          items:
+            type: string
+          type: array
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Delete multiple groups
+      tags:
+      - groups
+  /api/groups/search:
+    get:
+      description: Search groups with keyword and pagination
+      parameters:
+      - description: Search keyword
+        in: query
+        name: keyword
+        required: true
+        type: string
+      - description: Page number
+        in: query
+        name: page
+        type: integer
+      - description: Items per page
+        in: query
+        name: per_page
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        groups:
+                          items:
+                            $ref: '#/definitions/controller.GroupResponse'
+                          type: array
+                        total:
+                          type: integer
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Search groups
+      tags:
+      - groups
+  /api/log/{group}:
+    get:
+      description: Get logs for a specific group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Page number
+        in: query
+        name: page
+        type: integer
+      - description: Items per page
+        in: query
+        name: per_page
+        type: integer
+      - description: Start timestamp (milliseconds)
+        in: query
+        name: start_time
+        type: integer
+      - description: End timestamp (milliseconds)
+        in: query
+        name: end_time
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.GetGroupLogsResult'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get group logs
+      tags:
+      - log
+  /api/log/{group}/detail/{log_id}:
+    get:
+      description: Get detailed information about a specific log entry in a group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Log ID
+        in: path
+        name: log_id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.RequestDetail'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get group log detail
+      tags:
+      - log
+  /api/log/{group}/search:
+    get:
+      description: Search logs for a specific group with filters
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Page number
+        in: query
+        name: page
+        type: integer
+      - description: Items per page
+        in: query
+        name: per_page
+        type: integer
+      - description: Start timestamp (milliseconds)
+        in: query
+        name: start_time
+        type: integer
+      - description: End timestamp (milliseconds)
+        in: query
+        name: end_time
+        type: integer
+      - description: Filter by token name
+        in: query
+        name: token_name
+        type: string
+      - description: Filter by model name
+        in: query
+        name: model
+        type: string
+      - description: Filter by status
+        in: query
+        name: status
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.GetGroupLogsResult'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Search group logs
+      tags:
+      - log
+  /api/log/{group}/used/models:
+    get:
+      description: Get a list of models that have been used in a specific group's
+        logs
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    type: string
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get group used models
+      tags:
+      - log
+  /api/log/{group}/used/token_names:
+    get:
+      description: Get a list of token names that have been used in a specific group's
+        logs
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    type: string
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get group used token names
+      tags:
+      - log
+  /api/logs:
+    delete:
+      description: Deletes logs older than the specified retention period
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  type: integer
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Delete historical logs
+      tags:
+      - logs
+    get:
+      description: Returns a paginated list of all logs with optional filters
+      parameters:
+      - description: Page number
+        in: query
+        name: page
+        type: integer
+      - description: Items per page
+        in: query
+        name: per_page
+        type: integer
+      - description: Start timestamp (milliseconds)
+        in: query
+        name: start_time
+        type: integer
+      - description: End timestamp (milliseconds)
+        in: query
+        name: end_time
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.GetLogsResult'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get all logs
+      tags:
+      - logs
+  /api/logs/consume_error:
+    get:
+      description: Search for logs with consumption errors
+      parameters:
+      - description: Page number
+        in: query
+        name: page
+        type: integer
+      - description: Items per page
+        in: query
+        name: per_page
+        type: integer
+      - description: Start timestamp (milliseconds)
+        in: query
+        name: start_time
+        type: integer
+      - description: End timestamp (milliseconds)
+        in: query
+        name: end_time
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        logs:
+                          items:
+                            $ref: '#/definitions/model.RequestDetail'
+                          type: array
+                        total:
+                          type: integer
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Search consumption errors
+      tags:
+      - logs
+  /api/logs/detail/{log_id}:
+    get:
+      description: Get detailed information about a specific log entry
+      parameters:
+      - description: Log ID
+        in: path
+        name: log_id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.RequestDetail'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get log detail
+      tags:
+      - logs
+  /api/logs/search:
+    get:
+      description: Search logs with various filters
+      parameters:
+      - description: Page number
+        in: query
+        name: page
+        type: integer
+      - description: Items per page
+        in: query
+        name: per_page
+        type: integer
+      - description: Start timestamp (milliseconds)
+        in: query
+        name: start_time
+        type: integer
+      - description: End timestamp (milliseconds)
+        in: query
+        name: end_time
+        type: integer
+      - description: Filter by token name
+        in: query
+        name: token_name
+        type: string
+      - description: Filter by model name
+        in: query
+        name: model
+        type: string
+      - description: Filter by status
+        in: query
+        name: status
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.GetLogsResult'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Search logs
+      tags:
+      - logs
+  /api/logs/used/models:
+    get:
+      description: Get a list of models that have been used in logs
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    type: string
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get used models
+      tags:
+      - logs
+  /api/model_config:
+    post:
+      description: Saves a model config
+      parameters:
+      - description: Model config
+        in: body
+        name: config
+        required: true
+        schema:
+          $ref: '#/definitions/controller.SaveModelConfigsRequest'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Save model config
+      tags:
+      - modelconfig
+  /api/model_config/{model}:
+    delete:
+      description: Deletes a model config
+      parameters:
+      - description: Model name
+        in: path
+        name: model
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Delete model config
+      tags:
+      - modelconfig
+    get:
+      description: Returns a model config
+      parameters:
+      - description: Model name
+        in: path
+        name: model
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.ModelConfig'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get model config
+      tags:
+      - modelconfig
+  /api/model_configs:
+    post:
+      description: Saves a list of model configs
+      parameters:
+      - description: Model configs
+        in: body
+        name: configs
+        required: true
+        schema:
+          items:
+            $ref: '#/definitions/controller.SaveModelConfigsRequest'
+          type: array
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Save model configs
+      tags:
+      - modelconfig
+  /api/model_configs/batch_delete:
+    post:
+      description: Deletes a list of model configs
+      parameters:
+      - description: Model names
+        in: body
+        name: models
+        required: true
+        schema:
+          items:
+            type: string
+          type: array
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Delete model configs
+      tags:
+      - modelconfig
+  /api/model_cost_rank:
+    get:
+      description: Returns ranking data for models based on cost
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/model.ModelCostRank'
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get model cost ranking data
+      tags:
+      - dashboard
+  /api/model_cost_rank/{group}:
+    get:
+      description: Returns model cost ranking data specific to the given group
+      parameters:
+      - description: Group name or ID
+        in: path
+        name: group
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/model.ModelCostRank'
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get model cost ranking data for a specific group
+      tags:
+      - dashboard
+  /api/modelconfigs:
+    get:
+      description: Returns a list of model configs with pagination
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        configs:
+                          items:
+                            $ref: '#/definitions/model.ModelConfig'
+                          type: array
+                        total:
+                          type: integer
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get model configs
+      tags:
+      - modelconfig
+  /api/modelconfigs/all:
+    get:
+      description: Returns a list of all model configs
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/model.ModelConfig'
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get all model configs
+      tags:
+      - modelconfig
+  /api/modelconfigs/contains:
+    post:
+      description: Returns a list of model configs by models contains
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/model.ModelConfig'
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get model configs by models contains
+      tags:
+      - modelconfig
+  /api/modelconfigs/search:
+    get:
+      description: Returns a list of model configs by keyword
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        configs:
+                          items:
+                            $ref: '#/definitions/model.ModelConfig'
+                          type: array
+                        total:
+                          type: integer
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Search model configs
+      tags:
+      - modelconfig
+  /api/models/builtin:
+    get:
+      description: Returns a list of builtin models
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/controller.BuiltinModelConfig'
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get builtin models
+      tags:
+      - model
+  /api/models/builtin/channel:
+    get:
+      description: Returns a list of channel builtin models
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    items:
+                      $ref: '#/definitions/controller.BuiltinModelConfig'
+                    type: array
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get channel builtin models
+      tags:
+      - model
+  /api/models/builtin/channel/{type}:
+    get:
+      description: Returns a list of channel builtin models by type
+      parameters:
+      - description: Channel type
+        in: path
+        name: type
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/controller.BuiltinModelConfig'
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get channel builtin models by type
+      tags:
+      - model
+  /api/models/default:
+    get:
+      description: Returns a list of channel default models and mapping
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        mapping:
+                          additionalProperties:
+                            type: string
+                          type: object
+                        models:
+                          items:
+                            type: string
+                          type: array
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get channel default models and mapping
+      tags:
+      - model
+  /api/models/default/{type}:
+    get:
+      description: Returns a list of channel default models and mapping by type
+      parameters:
+      - description: Channel type
+        in: path
+        name: type
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        mapping:
+                          additionalProperties:
+                            type: string
+                          type: object
+                        models:
+                          items:
+                            type: string
+                          type: array
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get channel default models and mapping by type
+      tags:
+      - model
+  /api/models/enabled:
+    get:
+      description: Returns a list of enabled models
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/model.ModelConfig'
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get enabled models
+      tags:
+      - model
+  /api/models/enabled/channel:
+    get:
+      description: Returns a list of channel enabled models
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    items:
+                      $ref: '#/definitions/model.ModelConfig'
+                    type: array
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get channel enabled models
+      tags:
+      - model
+  /api/models/enabled/channel/{type}:
+    get:
+      description: Returns a list of channel enabled models by type
+      parameters:
+      - description: Channel type
+        in: path
+        name: type
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/model.ModelConfig'
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get channel enabled models by type
+      tags:
+      - model
+  /api/monitor:
+    delete:
+      description: Clears all model errors
+      produces:
+      - application/json
+      responses:
+        "204":
+          description: No Content
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Clear all model errors
+      tags:
+      - monitor
+    get:
+      description: Returns a list of all channel model error rates
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    additionalProperties:
+                      type: number
+                    type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get all channel model error rates
+      tags:
+      - monitor
+  /api/monitor/{id}:
+    delete:
+      description: Clears all model errors for a specific channel
+      parameters:
+      - description: Channel ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "204":
+          description: No Content
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Clear channel all model errors
+      tags:
+      - monitor
+    get:
+      description: Returns a list of channel model error rates
+      parameters:
+      - description: Channel ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  items:
+                    additionalProperties:
+                      type: number
+                    type: object
+                  type: array
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get channel model error rates
+      tags:
+      - monitor
+  /api/monitor/{id}/{model}:
+    delete:
+      description: Clears model errors for a specific channel and model
+      parameters:
+      - description: Channel ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      - description: Model name
+        in: path
+        name: model
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "204":
+          description: No Content
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Clear channel model errors
+      tags:
+      - monitor
+  /api/monitor/banned_channels:
+    get:
+      description: Returns a list of all banned model channels
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    items:
+                      type: integer
+                    type: array
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get all banned model channels
+      tags:
+      - monitor
+  /api/monitor/models:
+    get:
+      description: Returns a list of models error rate
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    type: number
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get models error rate
+      tags:
+      - monitor
+  /api/options:
+    get:
+      description: Returns a list of options
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    type: string
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get options
+      tags:
+      - option
+    put:
+      description: Updates multiple options
+      parameters:
+      - description: Options
+        in: body
+        name: options
+        required: true
+        schema:
+          additionalProperties:
+            type: string
+          type: object
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update options
+      tags:
+      - option
+  /api/options/{key}:
+    get:
+      description: Returns a single option
+      parameters:
+      - description: Option key
+        in: path
+        name: key
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/model.Option'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get option
+      tags:
+      - option
+    put:
+      description: Updates a single option
+      parameters:
+      - description: Option key
+        in: path
+        name: key
+        required: true
+        type: string
+      - description: Option value
+        in: body
+        name: value
+        required: true
+        schema:
+          type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update option
+      tags:
+      - option
+  /api/status:
+    get:
+      description: Returns the status of the server
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/controller.StatusData'
+              type: object
+      summary: Get status
+      tags:
+      - misc
+  /api/token/{group}:
+    post:
+      consumes:
+      - application/json
+      description: Adds a new token to a specific group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Token information
+        in: body
+        name: token
+        required: true
+        schema:
+          $ref: '#/definitions/model.Token'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/controller.TokenResponse'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Add group token
+      tags:
+      - token
+  /api/token/{group}/{id}:
+    delete:
+      description: Deletes a specific token from a group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Token ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Delete group token
+      tags:
+      - token
+    get:
+      description: Returns detailed information about a specific token for a specific
+        group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Token ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/controller.TokenResponse'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get token by ID for a specific group
+      tags:
+      - tokens
+    put:
+      consumes:
+      - application/json
+      description: Updates an existing token in a specific group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Token ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      - description: Updated token information
+        in: body
+        name: token
+        required: true
+        schema:
+          $ref: '#/definitions/model.Token'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/controller.TokenResponse'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Update group token
+      tags:
+      - token
+  /api/token/{group}/{id}/name:
+    post:
+      consumes:
+      - application/json
+      description: Updates the name of a token in a specific group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Token ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      - description: Name information
+        in: body
+        name: name
+        required: true
+        schema:
+          $ref: '#/definitions/controller.UpdateTokenNameRequest'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update group token name
+      tags:
+      - token
+  /api/token/{group}/{id}/status:
+    post:
+      consumes:
+      - application/json
+      description: Updates the status of a token in a specific group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Token ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      - description: Status information
+        in: body
+        name: status
+        required: true
+        schema:
+          $ref: '#/definitions/controller.UpdateTokenStatusRequest'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update group token status
+      tags:
+      - token
+  /api/token/{group}/batch_delete:
+    post:
+      description: Deletes multiple tokens from a specific group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      - description: Token IDs
+        in: body
+        name: ids
+        required: true
+        schema:
+          items:
+            type: integer
+          type: array
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Delete group tokens
+      tags:
+      - token
+  /api/token/{group}/search:
+    get:
+      description: Returns a paginated list of tokens for a specific group based on
+        search criteria
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        tokens:
+                          items:
+                            $ref: '#/definitions/controller.TokenResponse'
+                          type: array
+                        total:
+                          type: integer
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Search tokens for a specific group
+      tags:
+      - tokens
+  /api/tokens:
+    get:
+      description: Returns a paginated list of all tokens
+      parameters:
+      - description: Page number
+        in: query
+        name: page
+        type: integer
+      - description: Items per page
+        in: query
+        name: per_page
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        tokens:
+                          items:
+                            $ref: '#/definitions/controller.TokenResponse'
+                          type: array
+                        total:
+                          type: integer
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get all tokens
+      tags:
+      - tokens
+  /api/tokens/{group}:
+    get:
+      description: Returns a paginated list of all tokens for a specific group
+      parameters:
+      - description: Group name
+        in: path
+        name: group
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        tokens:
+                          items:
+                            $ref: '#/definitions/controller.TokenResponse'
+                          type: array
+                        total:
+                          type: integer
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get all tokens for a specific group
+      tags:
+      - tokens
+  /api/tokens/{id}:
+    delete:
+      description: Deletes a specific token by ID
+      parameters:
+      - description: Token ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Delete token
+      tags:
+      - tokens
+    get:
+      description: Returns detailed information about a specific token
+      parameters:
+      - description: Token ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/controller.TokenResponse'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Get token by ID
+      tags:
+      - tokens
+    put:
+      consumes:
+      - application/json
+      description: Updates an existing token's information
+      parameters:
+      - description: Token ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      - description: Updated token information
+        in: body
+        name: token
+        required: true
+        schema:
+          $ref: '#/definitions/model.Token'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/controller.TokenResponse'
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Update token
+      tags:
+      - tokens
+  /api/tokens/{id}/name:
+    post:
+      consumes:
+      - application/json
+      description: Updates the name of a specific token
+      parameters:
+      - description: Token ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      - description: Name information
+        in: body
+        name: name
+        required: true
+        schema:
+          $ref: '#/definitions/controller.UpdateTokenNameRequest'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update token name
+      tags:
+      - tokens
+  /api/tokens/{id}/status:
+    post:
+      consumes:
+      - application/json
+      description: Updates the status of a specific token
+      parameters:
+      - description: Token ID
+        in: path
+        name: id
+        required: true
+        type: integer
+      - description: Status information
+        in: body
+        name: status
+        required: true
+        schema:
+          $ref: '#/definitions/controller.UpdateTokenStatusRequest'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Update token status
+      tags:
+      - tokens
+  /api/tokens/batch_delete:
+    post:
+      consumes:
+      - application/json
+      description: Deletes multiple tokens by their IDs
+      parameters:
+      - description: Token IDs
+        in: body
+        name: ids
+        required: true
+        schema:
+          items:
+            type: integer
+          type: array
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/middleware.APIResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Delete multiple tokens
+      tags:
+      - tokens
+  /api/tokens/search:
+    get:
+      description: Returns a paginated list of tokens based on search criteria
+      parameters:
+      - description: Keyword
+        in: query
+        name: keyword
+        type: string
+      - description: Order
+        in: query
+        name: order
+        type: string
+      - description: Name
+        in: query
+        name: name
+        type: string
+      - description: Key
+        in: query
+        name: key
+        type: string
+      - description: Status
+        in: query
+        name: status
+        type: integer
+      - description: Group
+        in: query
+        name: group
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/middleware.APIResponse'
+            - properties:
+                data:
+                  additionalProperties:
+                    allOf:
+                    - {}
+                    - properties:
+                        tokens:
+                          items:
+                            $ref: '#/definitions/controller.TokenResponse'
+                          type: array
+                        total:
+                          type: integer
+                      type: object
+                  type: object
+              type: object
+      security:
+      - ApiKeyAuth: []
+      summary: Search tokens
+      tags:
+      - tokens
+  /v1/audio/speech:
+    post:
+      description: AudioSpeech
+      parameters:
+      - description: Request
+        in: body
+        name: request
+        required: true
+        schema:
+          $ref: '#/definitions/model.TextToSpeechRequest'
+      - description: Optional Aiproxy-Channel header
+        in: header
+        name: Aiproxy-Channel
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: audio binary
+          headers:
+            X-RateLimit-Limit-Requests:
+              description: X-RateLimit-Limit-Requests
+              type: integer
+            X-RateLimit-Limit-Tokens:
+              description: X-RateLimit-Limit-Tokens
+              type: integer
+            X-RateLimit-Remaining-Requests:
+              description: X-RateLimit-Remaining-Requests
+              type: integer
+            X-RateLimit-Remaining-Tokens:
+              description: X-RateLimit-Remaining-Tokens
+              type: integer
+            X-RateLimit-Reset-Requests:
+              description: X-RateLimit-Reset-Requests
+              type: string
+            X-RateLimit-Reset-Tokens:
+              description: X-RateLimit-Reset-Tokens
+              type: string
+          schema:
+            type: file
+      security:
+      - ApiKeyAuth: []
+      summary: AudioSpeech
+      tags:
+      - relay
+  /v1/audio/transcription:
+    post:
+      description: AudioTranscription
+      parameters:
+      - description: Model
+        in: formData
+        name: model
+        required: true
+        type: string
+      - description: File
+        in: formData
+        name: file
+        required: true
+        type: file
+      - description: Optional Aiproxy-Channel header
+        in: header
+        name: Aiproxy-Channel
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          headers:
+            X-RateLimit-Limit-Requests:
+              description: X-RateLimit-Limit-Requests
+              type: integer
+            X-RateLimit-Limit-Tokens:
+              description: X-RateLimit-Limit-Tokens
+              type: integer
+            X-RateLimit-Remaining-Requests:
+              description: X-RateLimit-Remaining-Requests
+              type: integer
+            X-RateLimit-Remaining-Tokens:
+              description: X-RateLimit-Remaining-Tokens
+              type: integer
+            X-RateLimit-Reset-Requests:
+              description: X-RateLimit-Reset-Requests
+              type: string
+            X-RateLimit-Reset-Tokens:
+              description: X-RateLimit-Reset-Tokens
+              type: string
+          schema:
+            $ref: '#/definitions/model.SttJSONResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: AudioTranscription
+      tags:
+      - relay
+  /v1/audio/translation:
+    post:
+      description: AudioTranslation
+      parameters:
+      - description: Model
+        in: formData
+        name: model
+        required: true
+        type: string
+      - description: File
+        in: formData
+        name: file
+        required: true
+        type: file
+      - description: Optional Aiproxy-Channel header
+        in: header
+        name: Aiproxy-Channel
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          headers:
+            X-RateLimit-Limit-Requests:
+              description: X-RateLimit-Limit-Requests
+              type: integer
+            X-RateLimit-Limit-Tokens:
+              description: X-RateLimit-Limit-Tokens
+              type: integer
+            X-RateLimit-Remaining-Requests:
+              description: X-RateLimit-Remaining-Requests
+              type: integer
+            X-RateLimit-Remaining-Tokens:
+              description: X-RateLimit-Remaining-Tokens
+              type: integer
+            X-RateLimit-Reset-Requests:
+              description: X-RateLimit-Reset-Requests
+              type: string
+            X-RateLimit-Reset-Tokens:
+              description: X-RateLimit-Reset-Tokens
+              type: string
+          schema:
+            $ref: '#/definitions/model.SttJSONResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: AudioTranslation
+      tags:
+      - relay
+  /v1/chat/completions:
+    post:
+      description: ChatCompletions
+      parameters:
+      - description: Request
+        in: body
+        name: request
+        required: true
+        schema:
+          $ref: '#/definitions/model.GeneralOpenAIRequest'
+      - description: Optional Aiproxy-Channel header
+        in: header
+        name: Aiproxy-Channel
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          headers:
+            X-RateLimit-Limit-Requests:
+              description: X-RateLimit-Limit-Requests
+              type: integer
+            X-RateLimit-Limit-Tokens:
+              description: X-RateLimit-Limit-Tokens
+              type: integer
+            X-RateLimit-Remaining-Requests:
+              description: X-RateLimit-Remaining-Requests
+              type: integer
+            X-RateLimit-Remaining-Tokens:
+              description: X-RateLimit-Remaining-Tokens
+              type: integer
+            X-RateLimit-Reset-Requests:
+              description: X-RateLimit-Reset-Requests
+              type: string
+            X-RateLimit-Reset-Tokens:
+              description: X-RateLimit-Reset-Tokens
+              type: string
+          schema:
+            $ref: '#/definitions/model.TextResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: ChatCompletions
+      tags:
+      - relay
+  /v1/completions:
+    post:
+      description: Completions
+      parameters:
+      - description: Request
+        in: body
+        name: request
+        required: true
+        schema:
+          $ref: '#/definitions/model.GeneralOpenAIRequest'
+      - description: Optional Aiproxy-Channel header
+        in: header
+        name: Aiproxy-Channel
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          headers:
+            X-RateLimit-Limit-Requests:
+              description: X-RateLimit-Limit-Requests
+              type: integer
+            X-RateLimit-Limit-Tokens:
+              description: X-RateLimit-Limit-Tokens
+              type: integer
+            X-RateLimit-Remaining-Requests:
+              description: X-RateLimit-Remaining-Requests
+              type: integer
+            X-RateLimit-Remaining-Tokens:
+              description: X-RateLimit-Remaining-Tokens
+              type: integer
+            X-RateLimit-Reset-Requests:
+              description: X-RateLimit-Reset-Requests
+              type: string
+            X-RateLimit-Reset-Tokens:
+              description: X-RateLimit-Reset-Tokens
+              type: string
+          schema:
+            $ref: '#/definitions/model.TextResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Completions
+      tags:
+      - relay
+  /v1/dashboard/subscription:
+    get:
+      description: Get subscription
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/openai.SubscriptionResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Get subscription
+      tags:
+      - relay
+  /v1/dashboard/usage:
+    get:
+      description: Get usage
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/openai.UsageResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Get usage
+      tags:
+      - relay
+  /v1/embeddings:
+    post:
+      description: Embeddings
+      parameters:
+      - description: Request
+        in: body
+        name: request
+        required: true
+        schema:
+          $ref: '#/definitions/model.EmbeddingRequest'
+      - description: Optional Aiproxy-Channel header
+        in: header
+        name: Aiproxy-Channel
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          headers:
+            X-RateLimit-Limit-Requests:
+              description: X-RateLimit-Limit-Requests
+              type: integer
+            X-RateLimit-Limit-Tokens:
+              description: X-RateLimit-Limit-Tokens
+              type: integer
+            X-RateLimit-Remaining-Requests:
+              description: X-RateLimit-Remaining-Requests
+              type: integer
+            X-RateLimit-Remaining-Tokens:
+              description: X-RateLimit-Remaining-Tokens
+              type: integer
+            X-RateLimit-Reset-Requests:
+              description: X-RateLimit-Reset-Requests
+              type: string
+            X-RateLimit-Reset-Tokens:
+              description: X-RateLimit-Reset-Tokens
+              type: string
+          schema:
+            $ref: '#/definitions/model.EmbeddingResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Embeddings
+      tags:
+      - relay
+  /v1/images/generations:
+    post:
+      description: ImagesGenerations
+      parameters:
+      - description: Request
+        in: body
+        name: request
+        required: true
+        schema:
+          $ref: '#/definitions/model.ImageRequest'
+      - description: Optional Aiproxy-Channel header
+        in: header
+        name: Aiproxy-Channel
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          headers:
+            X-RateLimit-Limit-Requests:
+              description: X-RateLimit-Limit-Requests
+              type: integer
+            X-RateLimit-Limit-Tokens:
+              description: X-RateLimit-Limit-Tokens
+              type: integer
+            X-RateLimit-Remaining-Requests:
+              description: X-RateLimit-Remaining-Requests
+              type: integer
+            X-RateLimit-Remaining-Tokens:
+              description: X-RateLimit-Remaining-Tokens
+              type: integer
+            X-RateLimit-Reset-Requests:
+              description: X-RateLimit-Reset-Requests
+              type: string
+            X-RateLimit-Reset-Tokens:
+              description: X-RateLimit-Reset-Tokens
+              type: string
+          schema:
+            $ref: '#/definitions/model.ImageResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: ImagesGenerations
+      tags:
+      - relay
+  /v1/models:
+    get:
+      description: List all models
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            properties:
+              data:
+                items:
+                  $ref: '#/definitions/controller.OpenAIModels'
+                type: array
+              object:
+                type: string
+            type: object
+      security:
+      - ApiKeyAuth: []
+      summary: List models
+      tags:
+      - relay
+  /v1/models/{model}:
+    get:
+      description: Retrieve a model
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/controller.OpenAIModels'
+      security:
+      - ApiKeyAuth: []
+      summary: Retrieve model
+      tags:
+      - relay
+  /v1/parse-pdf:
+    post:
+      description: ParsePdf
+      parameters:
+      - description: Model
+        in: formData
+        name: model
+        required: true
+        type: string
+      - description: File
+        in: formData
+        name: file
+        required: true
+        type: file
+      - description: Optional Aiproxy-Channel header
+        in: header
+        name: Aiproxy-Channel
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          headers:
+            X-RateLimit-Limit-Requests:
+              description: X-RateLimit-Limit-Requests
+              type: integer
+            X-RateLimit-Limit-Tokens:
+              description: X-RateLimit-Limit-Tokens
+              type: integer
+            X-RateLimit-Remaining-Requests:
+              description: X-RateLimit-Remaining-Requests
+              type: integer
+            X-RateLimit-Remaining-Tokens:
+              description: X-RateLimit-Remaining-Tokens
+              type: integer
+            X-RateLimit-Reset-Requests:
+              description: X-RateLimit-Reset-Requests
+              type: string
+            X-RateLimit-Reset-Tokens:
+              description: X-RateLimit-Reset-Tokens
+              type: string
+          schema:
+            $ref: '#/definitions/model.ParsePdfResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: ParsePdf
+      tags:
+      - relay
+  /v1/rerank:
+    post:
+      description: Rerank
+      parameters:
+      - description: Request
+        in: body
+        name: request
+        required: true
+        schema:
+          $ref: '#/definitions/model.RerankRequest'
+      - description: Optional Aiproxy-Channel header
+        in: header
+        name: Aiproxy-Channel
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          headers:
+            X-RateLimit-Limit-Requests:
+              description: X-RateLimit-Limit-Requests
+              type: integer
+            X-RateLimit-Limit-Tokens:
+              description: X-RateLimit-Limit-Tokens
+              type: integer
+            X-RateLimit-Remaining-Requests:
+              description: X-RateLimit-Remaining-Requests
+              type: integer
+            X-RateLimit-Remaining-Tokens:
+              description: X-RateLimit-Remaining-Tokens
+              type: integer
+            X-RateLimit-Reset-Requests:
+              description: X-RateLimit-Reset-Requests
+              type: string
+            X-RateLimit-Reset-Tokens:
+              description: X-RateLimit-Reset-Tokens
+              type: string
+          schema:
+            $ref: '#/definitions/model.RerankResponse'
+      security:
+      - ApiKeyAuth: []
+      summary: Rerank
+      tags:
+      - relay
+securityDefinitions:
+  ApiKeyAuth:
+    in: header
+    name: Authorization
+    type: apiKey
+swagger: "2.0"

+ 11 - 0
go.mod

@@ -30,6 +30,9 @@ require (
 	github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c
 	github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
 	github.com/stretchr/testify v1.10.0
+	github.com/swaggo/files v1.0.1
+	github.com/swaggo/gin-swagger v1.6.0
+	github.com/swaggo/swag v1.16.4
 	golang.org/x/image v0.25.0
 	golang.org/x/sync v0.12.0
 	google.golang.org/api v0.226.0
@@ -43,6 +46,7 @@ require (
 	cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect
 	cloud.google.com/go/compute/metadata v0.6.0 // indirect
 	filippo.io/edwards25519 v1.1.0 // indirect
+	github.com/KyleBanks/depth v1.2.1 // indirect
 	github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect
 	github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
 	github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
@@ -60,6 +64,10 @@ require (
 	github.com/glebarez/go-sqlite v1.22.0 // indirect
 	github.com/go-logr/logr v1.4.2 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/go-openapi/jsonpointer v0.21.1 // indirect
+	github.com/go-openapi/jsonreference v0.21.0 // indirect
+	github.com/go-openapi/spec v0.21.0 // indirect
+	github.com/go-openapi/swag v0.23.1 // indirect
 	github.com/go-playground/locales v0.14.1 // indirect
 	github.com/go-playground/universal-translator v0.18.1 // indirect
 	github.com/go-playground/validator/v10 v10.25.0 // indirect
@@ -75,9 +83,11 @@ require (
 	github.com/jackc/puddle/v2 v2.2.2 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.5 // indirect
+	github.com/josharian/intern v1.0.0 // indirect
 	github.com/jtolds/gls v4.20.0+incompatible // indirect
 	github.com/klauspost/cpuid/v2 v2.2.10 // indirect
 	github.com/leodido/go-urn v1.4.0 // indirect
+	github.com/mailru/easyjson v0.9.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/ncruces/go-strftime v0.1.9 // indirect
@@ -101,6 +111,7 @@ require (
 	golang.org/x/sys v0.31.0 // indirect
 	golang.org/x/text v0.23.0 // indirect
 	golang.org/x/time v0.11.0 // indirect
+	golang.org/x/tools v0.31.0 // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
 	google.golang.org/grpc v1.71.0 // indirect

+ 47 - 0
go.sum

@@ -8,6 +8,8 @@ cloud.google.com/go/iam v1.4.2 h1:4AckGYAYsowXeHzsn/LCKWIwSWLkdb0eGjH8wWkd27Q=
 cloud.google.com/go/iam v1.4.2/go.mod h1:REGlrt8vSlh4dfCJfSEcNjLGq75wW75c5aU3FLOYq34=
 filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
 filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
+github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
 github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
 github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 h1:zAybnyUQXIZ5mok5Jqwlf58/TFE7uvd3IAsa1aF9cXs=
@@ -66,6 +68,14 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
 github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
+github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
+github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
+github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
+github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
+github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
 github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
 github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -116,6 +126,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
 github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
@@ -130,6 +142,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
 github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
+github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
+github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
 github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo=
 github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -181,10 +195,17 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
+github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
+github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
+github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
+github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A=
+github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg=
 github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
 github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
 github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
 go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
@@ -203,30 +224,56 @@ go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt
 go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
 golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw=
 golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
 golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
 golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
 golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
 golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
 golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
 golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
 golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
 golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
 golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
 golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
 golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
 golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
 golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
 golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
 golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.226.0 h1:9A29y1XUD+YRXfnHkO66KggxHBZWg9LsTGqm7TkUvtQ=
 google.golang.org/api v0.226.0/go.mod h1:WP/0Xm4LVvMOCldfvOISnWquSRWbG2kArDZcg+W2DbY=
 google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=

+ 3 - 0
main.go

@@ -184,6 +184,9 @@ func cleanLog(ctx context.Context) {
 	}
 }
 
+// @securityDefinitions.apikey	ApiKeyAuth
+// @in							header
+// @name						Authorization
 func main() {
 	flag.Parse()
 

+ 2 - 2
middleware/auth.go

@@ -10,7 +10,7 @@ import (
 	"github.com/labring/aiproxy/common/network"
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/meta"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 	"github.com/sirupsen/logrus"
 )
 
@@ -181,7 +181,7 @@ func SetLogFieldsFromMeta(m *meta.Meta, fields logrus.Fields) {
 	SetLogChannelFields(fields, m.Channel)
 }
 
-func SetLogModeField(fields logrus.Fields, mode relaymode.Mode) {
+func SetLogModeField(fields logrus.Fields, mode mode.Mode) {
 	fields["mode"] = mode.String()
 }
 

+ 8 - 8
middleware/distributor.go

@@ -20,7 +20,7 @@ import (
 	"github.com/labring/aiproxy/common/rpmlimit"
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/meta"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 func calculateGroupConsumeLevelRatio(usedAmount float64) float64 {
@@ -215,7 +215,7 @@ func checkGroupBalance(c *gin.Context, group *model.GroupCache) bool {
 	return true
 }
 
-func NewDistribute(mode relaymode.Mode) gin.HandlerFunc {
+func NewDistribute(mode mode.Mode) gin.HandlerFunc {
 	return func(c *gin.Context) {
 		distribute(c, mode)
 	}
@@ -251,7 +251,7 @@ func getChannelFromHeader(header string, mc *model.ModelCaches, model string) (*
 	return nil, fmt.Errorf("channel %d not found for model %s", channelIDInt, model)
 }
 
-func distribute(c *gin.Context, mode relaymode.Mode) {
+func distribute(c *gin.Context, mode mode.Mode) {
 	if config.GetDisableServe() {
 		abortLogWithMessage(c, http.StatusServiceUnavailable, "service is under maintenance")
 		return
@@ -358,7 +358,7 @@ func GetModelConfig(c *gin.Context) *model.ModelConfig {
 
 func NewMetaByContext(c *gin.Context,
 	channel *model.Channel,
-	mode relaymode.Mode,
+	mode mode.Mode,
 	opts ...meta.Option,
 ) *meta.Meta {
 	requestID := GetRequestID(c)
@@ -390,10 +390,10 @@ type ModelRequest struct {
 	Model string `form:"model" json:"model"`
 }
 
-func getRequestModel(c *gin.Context, mode relaymode.Mode) (string, error) {
+func getRequestModel(c *gin.Context, m mode.Mode) (string, error) {
 	path := c.Request.URL.Path
 	switch {
-	case mode == relaymode.ParsePdf:
+	case m == mode.ParsePdf:
 		query := c.Request.URL.Query()
 		model := query.Get("model")
 		if model != "" {
@@ -401,8 +401,8 @@ func getRequestModel(c *gin.Context, mode relaymode.Mode) (string, error) {
 		}
 
 		fallthrough
-	case mode == relaymode.AudioTranscription,
-		mode == relaymode.AudioTranslation:
+	case m == mode.AudioTranscription,
+		m == mode.AudioTranslation:
 		return c.Request.FormValue("model"), nil
 
 	case strings.HasPrefix(path, "/v1/engines") && strings.HasSuffix(path, "/embeddings"):

+ 2 - 2
model/channel.go

@@ -11,7 +11,7 @@ import (
 	"github.com/labring/aiproxy/common"
 	"github.com/labring/aiproxy/common/config"
 	"github.com/labring/aiproxy/monitor"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 	"gorm.io/gorm"
 	"gorm.io/gorm/clause"
 )
@@ -330,7 +330,7 @@ func ClearLastTestErrorAt(id int) error {
 	return HandleUpdateResult(result, ErrChannelNotFound)
 }
 
-func (c *Channel) UpdateModelTest(testAt time.Time, model, actualModel string, mode relaymode.Mode, took float64, success bool, response string, code int) (*ChannelTest, error) {
+func (c *Channel) UpdateModelTest(testAt time.Time, model, actualModel string, mode mode.Mode, took float64, success bool, response string, code int) (*ChannelTest, error) {
 	var ct *ChannelTest
 	err := DB.Transaction(func(tx *gorm.DB) error {
 		if !success {

+ 12 - 12
model/channeltest.go

@@ -4,21 +4,21 @@ import (
 	"time"
 
 	"github.com/bytedance/sonic"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 type ChannelTest struct {
-	TestAt      time.Time      `json:"test_at"`
-	Model       string         `gorm:"primaryKey"   json:"model"`
-	ActualModel string         `json:"actual_model"`
-	Response    string         `gorm:"type:text"    json:"response"`
-	ChannelName string         `json:"channel_name"`
-	ChannelType int            `json:"channel_type"`
-	ChannelID   int            `gorm:"primaryKey"   json:"channel_id"`
-	Took        float64        `json:"took"`
-	Success     bool           `json:"success"`
-	Mode        relaymode.Mode `json:"mode"`
-	Code        int            `json:"code"`
+	TestAt      time.Time `json:"test_at"`
+	Model       string    `gorm:"primaryKey"   json:"model"`
+	ActualModel string    `json:"actual_model"`
+	Response    string    `gorm:"type:text"    json:"response"`
+	ChannelName string    `json:"channel_name"`
+	ChannelType int       `json:"channel_type"`
+	ChannelID   int       `gorm:"primaryKey"   json:"channel_id"`
+	Took        float64   `json:"took"`
+	Success     bool      `json:"success"`
+	Mode        mode.Mode `json:"mode"`
+	Code        int       `json:"code"`
 }
 
 func (ct *ChannelTest) MarshalJSON() ([]byte, error) {

+ 2 - 2
model/modelconfig.go

@@ -7,7 +7,7 @@ import (
 
 	"github.com/bytedance/sonic"
 	"github.com/labring/aiproxy/common"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 	"gorm.io/gorm"
 )
 
@@ -25,7 +25,7 @@ type ModelConfig struct {
 	Model              string                 `gorm:"primaryKey"                     json:"model"`
 	Owner              ModelOwner             `gorm:"type:varchar(255);index"        json:"owner"`
 	ImageMaxBatchSize  int                    `json:"image_batch_size,omitempty"`
-	Type               relaymode.Mode         `json:"type"`
+	Type               mode.Mode              `json:"type"`
 	ExcludeFromTests   bool                   `json:"exclude_from_tests,omitempty"`
 	InputPrice         float64                `json:"input_price,omitempty"`
 	OutputPrice        float64                `json:"output_price,omitempty"`

+ 5 - 5
relay/adaptor/ai360/constants.go

@@ -2,28 +2,28 @@ package ai360
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 var ModelList = []*model.ModelConfig{
 	{
 		Model: "360GPT_S2_V9",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerAI360,
 	},
 	{
 		Model: "embedding-bert-512-v1",
-		Type:  relaymode.Embeddings,
+		Type:  mode.Embeddings,
 		Owner: model.ModelOwnerAI360,
 	},
 	{
 		Model: "embedding_s1_v1",
-		Type:  relaymode.Embeddings,
+		Type:  mode.Embeddings,
 		Owner: model.ModelOwnerAI360,
 	},
 	{
 		Model: "semantic_similarity_s1_v1",
-		Type:  relaymode.Embeddings,
+		Type:  mode.Embeddings,
 		Owner: model.ModelOwnerAI360,
 	},
 }

+ 20 - 20
relay/adaptor/ali/adaptor.go

@@ -9,8 +9,8 @@ import (
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -30,17 +30,17 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 		u = baseURL
 	}
 	switch meta.Mode {
-	case relaymode.ImagesGenerations:
+	case mode.ImagesGenerations:
 		return u + "/api/v1/services/aigc/text2image/image-synthesis", nil
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		return u + "/compatible-mode/v1/chat/completions", nil
-	case relaymode.Completions:
+	case mode.Completions:
 		return u + "/compatible-mode/v1/completions", nil
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		return u + "/compatible-mode/v1/embeddings", nil
-	case relaymode.AudioSpeech, relaymode.AudioTranscription:
+	case mode.AudioSpeech, mode.AudioTranscription:
 		return u + "/api-ws/v1/inference", nil
-	case relaymode.Rerank:
+	case mode.Rerank:
 		return u + "/api/v1/services/rerank/text-rerank/text-rerank", nil
 	default:
 		return "", fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -56,15 +56,15 @@ func (a *Adaptor) SetupRequestHeader(meta *meta.Meta, _ *gin.Context, req *http.
 
 func (a *Adaptor) ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io.Reader, error) {
 	switch meta.Mode {
-	case relaymode.ImagesGenerations:
+	case mode.ImagesGenerations:
 		return ConvertImageRequest(meta, req)
-	case relaymode.Rerank:
+	case mode.Rerank:
 		return ConvertRerankRequest(meta, req)
-	case relaymode.ChatCompletions, relaymode.Completions, relaymode.Embeddings:
+	case mode.ChatCompletions, mode.Completions, mode.Embeddings:
 		return openai.ConvertRequest(meta, req)
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		return ConvertTTSRequest(meta, req)
-	case relaymode.AudioTranscription:
+	case mode.AudioTranscription:
 		return ConvertSTTRequest(meta, req)
 	default:
 		return "", nil, nil, fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -73,11 +73,11 @@ func (a *Adaptor) ConvertRequest(meta *meta.Meta, req *http.Request) (string, ht
 
 func (a *Adaptor) DoRequest(meta *meta.Meta, _ *gin.Context, req *http.Request) (*http.Response, error) {
 	switch meta.Mode {
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		return TTSDoRequest(meta, req)
-	case relaymode.AudioTranscription:
+	case mode.AudioTranscription:
 		return STTDoRequest(meta, req)
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		fallthrough
 	default:
 		return utils.DoRequest(req)
@@ -86,15 +86,15 @@ func (a *Adaptor) DoRequest(meta *meta.Meta, _ *gin.Context, req *http.Request)
 
 func (a *Adaptor) DoResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (usage *relaymodel.Usage, err *relaymodel.ErrorWithStatusCode) {
 	switch meta.Mode {
-	case relaymode.ImagesGenerations:
+	case mode.ImagesGenerations:
 		usage, err = ImageHandler(meta, c, resp)
-	case relaymode.ChatCompletions, relaymode.Completions, relaymode.Embeddings:
+	case mode.ChatCompletions, mode.Completions, mode.Embeddings:
 		usage, err = openai.DoResponse(meta, c, resp)
-	case relaymode.Rerank:
+	case mode.Rerank:
 		usage, err = RerankHandler(meta, c, resp)
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		usage, err = TTSDoResponse(meta, c, resp)
-	case relaymode.AudioTranscription:
+	case mode.AudioTranscription:
 		usage, err = STTDoResponse(meta, c, resp)
 	default:
 		return nil, openai.ErrorWrapperWithMessage(fmt.Sprintf("unsupported mode: %s", meta.Mode), "unsupported_mode", http.StatusBadRequest)

+ 62 - 62
relay/adaptor/ali/constants.go

@@ -2,7 +2,7 @@ package ali
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 // https://help.aliyun.com/zh/model-studio/getting-started/models?spm=a2c4g.11186623.0.i12#ced16cb6cdfsy
@@ -11,7 +11,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问-Max
 	{
 		Model:       "qwen-max",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.02,
 		OutputPrice: 0.06,
@@ -25,7 +25,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-max-latest",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.02,
 		OutputPrice: 0.06,
@@ -41,7 +41,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问-Plus
 	{
 		Model:       "qwen-plus",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0008,
 		OutputPrice: 0.002,
@@ -55,7 +55,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-plus-latest",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0008,
 		OutputPrice: 0.002,
@@ -71,7 +71,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问-Turbo
 	{
 		Model:       "qwen-turbo",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0003,
 		OutputPrice: 0.0006,
@@ -85,7 +85,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-turbo-latest",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0003,
 		OutputPrice: 0.0006,
@@ -101,7 +101,7 @@ var ModelList = []*model.ModelConfig{
 	// Qwen-Long
 	{
 		Model:       "qwen-long",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0005,
 		OutputPrice: 0.002,
@@ -117,7 +117,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问VL
 	{
 		Model:       "qwen-vl-max",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.02,
 		OutputPrice: 0.02,
@@ -132,7 +132,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-vl-max-latest",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.02,
 		OutputPrice: 0.02,
@@ -147,7 +147,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-vl-plus",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.008,
 		OutputPrice: 0.008,
@@ -162,7 +162,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-vl-plus-latest",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.008,
 		OutputPrice: 0.008,
@@ -179,7 +179,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问OCR
 	{
 		Model:            "qwen-vl-ocr",
-		Type:             relaymode.ChatCompletions,
+		Type:             mode.ChatCompletions,
 		Owner:            model.ModelOwnerAlibaba,
 		InputPrice:       0.005,
 		OutputPrice:      0.005,
@@ -194,7 +194,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:            "qwen-vl-ocr-latest",
-		Type:             relaymode.ChatCompletions,
+		Type:             mode.ChatCompletions,
 		Owner:            model.ModelOwnerAlibaba,
 		InputPrice:       0.005,
 		OutputPrice:      0.005,
@@ -211,7 +211,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问Math
 	{
 		Model:       "qwen-math-plus",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.004,
 		OutputPrice: 0.012,
@@ -225,7 +225,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-math-plus-latest",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.004,
 		OutputPrice: 0.012,
@@ -239,7 +239,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-math-turbo",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.002,
 		OutputPrice: 0.006,
@@ -253,7 +253,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-math-turbo-latest",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.002,
 		OutputPrice: 0.006,
@@ -269,7 +269,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问Coder
 	{
 		Model:       "qwen-coder-plus",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0035,
 		OutputPrice: 0.007,
@@ -283,7 +283,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-coder-plus-latest",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0035,
 		OutputPrice: 0.007,
@@ -297,7 +297,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-coder-turbo",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.002,
 		OutputPrice: 0.006,
@@ -311,7 +311,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-coder-turbo-latest",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.002,
 		OutputPrice: 0.006,
@@ -327,7 +327,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问2.5
 	{
 		Model:       "qwen2.5-72b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.004,
 		OutputPrice: 0.012,
@@ -341,7 +341,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2.5-32b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0035,
 		OutputPrice: 0.007,
@@ -355,7 +355,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2.5-14b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.002,
 		OutputPrice: 0.006,
@@ -369,7 +369,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2.5-7b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.001,
 		OutputPrice: 0.002,
@@ -383,7 +383,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2.5-vl-72b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.016,
 		OutputPrice: 0.048,
@@ -398,7 +398,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2.5-vl-7b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.002,
 		OutputPrice: 0.005,
@@ -413,7 +413,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2.5-vl-3b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0012,
 		OutputPrice: 0.0036,
@@ -430,7 +430,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问2
 	{
 		Model:       "qwen2-72b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.004,
 		OutputPrice: 0.012,
@@ -444,7 +444,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2-57b-a14b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0035,
 		OutputPrice: 0.007,
@@ -458,7 +458,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2-7b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.001,
 		OutputPrice: 0.002,
@@ -472,7 +472,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2-vl-72b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.016,
 		OutputPrice: 0.048,
@@ -488,7 +488,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问1.5
 	{
 		Model:       "qwen1.5-110b-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.007,
 		OutputPrice: 0.014,
@@ -502,7 +502,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen1.5-72b-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.005,
 		OutputPrice: 0.01,
@@ -516,7 +516,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen1.5-32b-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0035,
 		OutputPrice: 0.007,
@@ -530,7 +530,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen1.5-14b-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.002,
 		OutputPrice: 0.004,
@@ -544,7 +544,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen1.5-7b-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.001,
 		OutputPrice: 0.002,
@@ -560,7 +560,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问
 	{
 		Model:       "qwen-72b-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.02,
 		OutputPrice: 0.02,
@@ -574,7 +574,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-14b-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.008,
 		OutputPrice: 0.008,
@@ -588,7 +588,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen-7b-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.006,
 		OutputPrice: 0.006,
@@ -604,7 +604,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问数学模型
 	{
 		Model:       "qwen2.5-math-72b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.004,
 		OutputPrice: 0.012,
@@ -618,7 +618,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2.5-math-7b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.001,
 		OutputPrice: 0.002,
@@ -632,7 +632,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2-math-72b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.004,
 		OutputPrice: 0.012,
@@ -646,7 +646,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2-math-7b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.001,
 		OutputPrice: 0.002,
@@ -662,7 +662,7 @@ var ModelList = []*model.ModelConfig{
 	// 通义千问Coder
 	{
 		Model:       "qwen2.5-coder-32b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0035,
 		OutputPrice: 0.007,
@@ -676,7 +676,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2.5-coder-14b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.002,
 		OutputPrice: 0.006,
@@ -690,7 +690,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qwen2.5-coder-7b-instruct",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.001,
 		OutputPrice: 0.002,
@@ -705,7 +705,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:       "qwq-32b-preview",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.0035,
 		OutputPrice: 0.007,
@@ -718,7 +718,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "qvq-72b-preview",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAlibaba,
 		InputPrice:  0.012,
 		OutputPrice: 0.036,
@@ -732,7 +732,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:            "qwen-mt-plus",
-		Type:             relaymode.ChatCompletions,
+		Type:             mode.ChatCompletions,
 		Owner:            model.ModelOwnerAlibaba,
 		InputPrice:       0.015,
 		OutputPrice:      0.045,
@@ -746,7 +746,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:            "qwen-mt-turbo",
-		Type:             relaymode.ChatCompletions,
+		Type:             mode.ChatCompletions,
 		Owner:            model.ModelOwnerAlibaba,
 		InputPrice:       0.001,
 		OutputPrice:      0.003,
@@ -762,32 +762,32 @@ var ModelList = []*model.ModelConfig{
 	// stable-diffusion
 	{
 		Model: "stable-diffusion-xl",
-		Type:  relaymode.ImagesGenerations,
+		Type:  mode.ImagesGenerations,
 		Owner: model.ModelOwnerStabilityAI,
 		RPM:   2,
 	},
 	{
 		Model: "stable-diffusion-v1.5",
-		Type:  relaymode.ImagesGenerations,
+		Type:  mode.ImagesGenerations,
 		Owner: model.ModelOwnerStabilityAI,
 		RPM:   2,
 	},
 	{
 		Model: "stable-diffusion-3.5-large",
-		Type:  relaymode.ImagesGenerations,
+		Type:  mode.ImagesGenerations,
 		Owner: model.ModelOwnerStabilityAI,
 		RPM:   2,
 	},
 	{
 		Model: "stable-diffusion-3.5-large-turbo",
-		Type:  relaymode.ImagesGenerations,
+		Type:  mode.ImagesGenerations,
 		Owner: model.ModelOwnerStabilityAI,
 		RPM:   2,
 	},
 
 	{
 		Model:      "sambert-v1",
-		Type:       relaymode.AudioSpeech,
+		Type:       mode.AudioSpeech,
 		Owner:      model.ModelOwnerAlibaba,
 		InputPrice: 0.1,
 		RPM:        20,
@@ -842,7 +842,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:      "paraformer-realtime-v2",
-		Type:       relaymode.AudioTranscription,
+		Type:       mode.AudioTranscription,
 		Owner:      model.ModelOwnerAlibaba,
 		RPM:        20,
 		InputPrice: 0.24,
@@ -854,7 +854,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model: "gte-rerank",
-		Type:  relaymode.Rerank,
+		Type:  mode.Rerank,
 		Owner: model.ModelOwnerAlibaba,
 		RPM:   300,
 		Config: model.NewModelConfig(
@@ -865,7 +865,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:      "text-embedding-v1",
-		Type:       relaymode.Embeddings,
+		Type:       mode.Embeddings,
 		Owner:      model.ModelOwnerAlibaba,
 		InputPrice: 0.0007,
 		RPM:        1800,
@@ -875,7 +875,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:      "text-embedding-v2",
-		Type:       relaymode.Embeddings,
+		Type:       mode.Embeddings,
 		Owner:      model.ModelOwnerAlibaba,
 		InputPrice: 0.0007,
 		RPM:        1800,
@@ -885,7 +885,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:      "text-embedding-v3",
-		Type:       relaymode.Embeddings,
+		Type:       mode.Embeddings,
 		Owner:      model.ModelOwnerAlibaba,
 		InputPrice: 0.0007,
 		RPM:        1800,

+ 6 - 6
relay/adaptor/ali/embeddings.go

@@ -12,7 +12,7 @@ import (
 	"github.com/labring/aiproxy/middleware"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 )
 
 // Deprecated: Use openai.ConvertRequest instead
@@ -55,16 +55,16 @@ func ConvertEmbeddingsRequest(meta *meta.Meta, req *http.Request) (string, http.
 	return http.MethodPost, nil, bytes.NewReader(jsonData), nil
 }
 
-func embeddingResponse2OpenAI(meta *meta.Meta, response *EmbeddingResponse) *openai.EmbeddingResponse {
-	openAIEmbeddingResponse := openai.EmbeddingResponse{
+func embeddingResponse2OpenAI(meta *meta.Meta, response *EmbeddingResponse) *model.EmbeddingResponse {
+	openAIEmbeddingResponse := model.EmbeddingResponse{
 		Object: "list",
-		Data:   make([]*openai.EmbeddingResponseItem, 0, 1),
+		Data:   make([]*model.EmbeddingResponseItem, 0, 1),
 		Model:  meta.OriginModel,
 		Usage:  response.Usage,
 	}
 
 	for i, embedding := range response.Output.Embeddings {
-		openAIEmbeddingResponse.Data = append(openAIEmbeddingResponse.Data, &openai.EmbeddingResponseItem{
+		openAIEmbeddingResponse.Data = append(openAIEmbeddingResponse.Data, &model.EmbeddingResponseItem{
 			Object:    "embedding",
 			Index:     i,
 			Embedding: embedding.Embedding,
@@ -73,7 +73,7 @@ func embeddingResponse2OpenAI(meta *meta.Meta, response *EmbeddingResponse) *ope
 	return &openAIEmbeddingResponse
 }
 
-func EmbeddingsHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
+func EmbeddingsHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*model.Usage, *model.ErrorWithStatusCode) {
 	defer resp.Body.Close()
 
 	log := middleware.GetLogger(c)

+ 3 - 3
relay/adaptor/ali/image.go

@@ -166,8 +166,8 @@ func asyncTaskWait(ctx context.Context, taskID string, key string) (*TaskRespons
 	return nil, errors.New("aliAsyncTaskWait timeout")
 }
 
-func responseAli2OpenAIImage(ctx context.Context, response *TaskResponse, responseFormat string) *openai.ImageResponse {
-	imageResponse := openai.ImageResponse{
+func responseAli2OpenAIImage(ctx context.Context, response *TaskResponse, responseFormat string) *model.ImageResponse {
+	imageResponse := model.ImageResponse{
 		Created: time.Now().Unix(),
 	}
 
@@ -189,7 +189,7 @@ func responseAli2OpenAIImage(ctx context.Context, response *TaskResponse, respon
 			b64Json = data.B64Image
 		}
 
-		imageResponse.Data = append(imageResponse.Data, &openai.ImageData{
+		imageResponse.Data = append(imageResponse.Data, &model.ImageData{
 			URL:           data.URL,
 			B64Json:       b64Json,
 			RevisedPrompt: "",

+ 4 - 4
relay/adaptor/ali/model.go

@@ -1,6 +1,6 @@
 package ali
 
-import relaymodel "github.com/labring/aiproxy/relay/model"
+import model "github.com/labring/aiproxy/relay/model"
 
 type ImageRequest struct {
 	Input struct {
@@ -38,8 +38,8 @@ type TaskResponse struct {
 			Failed    int `json:"FAILED,omitempty"`
 		} `json:"task_metrics,omitempty"`
 	} `json:"output,omitempty"`
-	Usage      relaymodel.Usage `json:"usage"`
-	StatusCode int              `json:"status_code,omitempty"`
+	Usage      model.Usage `json:"usage"`
+	StatusCode int         `json:"status_code,omitempty"`
 }
 
 type EmbeddingRequest struct {
@@ -62,7 +62,7 @@ type EmbeddingResponse struct {
 	Output struct {
 		Embeddings []Embedding `json:"embeddings"`
 	} `json:"output"`
-	Usage relaymodel.Usage `json:"usage"`
+	Usage model.Usage `json:"usage"`
 }
 
 type Error struct {

+ 9 - 9
relay/adaptor/ali/rerank.go

@@ -11,7 +11,7 @@ import (
 	"github.com/labring/aiproxy/middleware"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 )
 
 type RerankResponse struct {
@@ -20,7 +20,7 @@ type RerankResponse struct {
 	Output    RerankOutput `json:"output"`
 }
 type RerankOutput struct {
-	Results []*relaymodel.RerankResult `json:"results"`
+	Results []*model.RerankResult `json:"results"`
 }
 type RerankUsage struct {
 	TotalTokens int `json:"total_tokens"`
@@ -55,7 +55,7 @@ func ConvertRerankRequest(meta *meta.Meta, req *http.Request) (string, http.Head
 	return http.MethodPost, nil, bytes.NewReader(jsonData), nil
 }
 
-func RerankHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
+func RerankHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*model.Usage, *model.ErrorWithStatusCode) {
 	if resp.StatusCode != http.StatusOK {
 		return nil, openai.ErrorHanlder(resp)
 	}
@@ -76,9 +76,9 @@ func RerankHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relay
 
 	c.Writer.WriteHeader(resp.StatusCode)
 
-	rerankResp := relaymodel.RerankResponse{
-		Meta: relaymodel.RerankMeta{
-			Tokens: &relaymodel.RerankMetaTokens{
+	rerankResp := model.RerankResponse{
+		Meta: model.RerankMeta{
+			Tokens: &model.RerankMetaTokens{
 				InputTokens:  rerankResponse.Usage.TotalTokens,
 				OutputTokens: 0,
 			},
@@ -87,15 +87,15 @@ func RerankHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relay
 		ID:      rerankResponse.RequestID,
 	}
 
-	var usage *relaymodel.Usage
+	var usage *model.Usage
 	if rerankResponse.Usage == nil {
-		usage = &relaymodel.Usage{
+		usage = &model.Usage{
 			PromptTokens:     meta.InputTokens,
 			CompletionTokens: 0,
 			TotalTokens:      meta.InputTokens,
 		}
 	} else {
-		usage = &relaymodel.Usage{
+		usage = &model.Usage{
 			PromptTokens: rerankResponse.Usage.TotalTokens,
 			TotalTokens:  rerankResponse.Usage.TotalTokens,
 		}

+ 3 - 3
relay/adaptor/ali/stt-realtime.go

@@ -13,7 +13,7 @@ import (
 	"github.com/gorilla/websocket"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 )
 
 type STTMessage struct {
@@ -145,7 +145,7 @@ func STTDoRequest(meta *meta.Meta, req *http.Request) (*http.Response, error) {
 	}, nil
 }
 
-func STTDoResponse(meta *meta.Meta, c *gin.Context, _ *http.Response) (usage *relaymodel.Usage, err *relaymodel.ErrorWithStatusCode) {
+func STTDoResponse(meta *meta.Meta, c *gin.Context, _ *http.Response) (usage *model.Usage, err *model.ErrorWithStatusCode) {
 	audioData := meta.MustGet("audio_data").([]byte)
 	taskID := meta.MustGet("task_id").(string)
 
@@ -154,7 +154,7 @@ func STTDoResponse(meta *meta.Meta, c *gin.Context, _ *http.Response) (usage *re
 
 	output := strings.Builder{}
 
-	usage = &relaymodel.Usage{}
+	usage = &model.Usage{}
 
 	for {
 		messageType, data, err := conn.ReadMessage()

+ 3 - 3
relay/adaptor/ali/tts.go

@@ -14,7 +14,7 @@ import (
 	"github.com/labring/aiproxy/middleware"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -190,13 +190,13 @@ func TTSDoRequest(meta *meta.Meta, req *http.Request) (*http.Response, error) {
 	}, nil
 }
 
-func TTSDoResponse(meta *meta.Meta, c *gin.Context, _ *http.Response) (usage *relaymodel.Usage, err *relaymodel.ErrorWithStatusCode) {
+func TTSDoResponse(meta *meta.Meta, c *gin.Context, _ *http.Response) (usage *model.Usage, err *model.ErrorWithStatusCode) {
 	log := middleware.GetLogger(c)
 
 	conn := meta.MustGet("ws_conn").(*websocket.Conn)
 	defer conn.Close()
 
-	usage = &relaymodel.Usage{}
+	usage = &model.Usage{}
 
 	for {
 		messageType, data, err := conn.ReadMessage()

+ 7 - 7
relay/adaptor/anthropic/constants.go

@@ -2,13 +2,13 @@ package anthropic
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 var ModelList = []*model.ModelConfig{
 	{
 		Model:       "claude-3-haiku-20240307",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAnthropic,
 		InputPrice:  0.0025,
 		OutputPrice: 0.0125,
@@ -19,7 +19,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "claude-3-opus-20240229",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAnthropic,
 		InputPrice:  0.015,
 		OutputPrice: 0.075,
@@ -30,7 +30,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "claude-3-5-haiku-20241022",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAnthropic,
 		InputPrice:  0.0008,
 		OutputPrice: 0.004,
@@ -42,7 +42,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "claude-3-5-sonnet-20240620",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAnthropic,
 		InputPrice:  0.003,
 		OutputPrice: 0.015,
@@ -54,7 +54,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "claude-3-5-sonnet-20241022",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAnthropic,
 		InputPrice:  0.003,
 		OutputPrice: 0.015,
@@ -66,7 +66,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "claude-3-5-sonnet-latest",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerAnthropic,
 		InputPrice:  0.003,
 		OutputPrice: 0.015,

+ 11 - 11
relay/adaptor/anthropic/main.go

@@ -199,8 +199,8 @@ func ConvertRequest(meta *meta.Meta, req *http.Request) (*Request, error) {
 }
 
 // https://docs.anthropic.com/claude/reference/messages-streaming
-func StreamResponse2OpenAI(meta *meta.Meta, claudeResponse *StreamResponse) *openai.ChatCompletionsStreamResponse {
-	openaiResponse := openai.ChatCompletionsStreamResponse{
+func StreamResponse2OpenAI(meta *meta.Meta, claudeResponse *StreamResponse) *model.ChatCompletionsStreamResponse {
+	openaiResponse := model.ChatCompletionsStreamResponse{
 		ID:      openai.ChatCompletionID(),
 		Object:  model.ChatCompletionChunk,
 		Created: time.Now().Unix(),
@@ -261,7 +261,7 @@ func StreamResponse2OpenAI(meta *meta.Meta, claudeResponse *StreamResponse) *ope
 		}
 	}
 
-	var choice openai.ChatCompletionsStreamResponseChoice
+	var choice model.ChatCompletionsStreamResponseChoice
 	choice.Delta.Content = content
 	choice.Delta.ReasoningContent = thinking
 
@@ -274,12 +274,12 @@ func StreamResponse2OpenAI(meta *meta.Meta, claudeResponse *StreamResponse) *ope
 	if finishReason != "null" {
 		choice.FinishReason = &finishReason
 	}
-	openaiResponse.Choices = []*openai.ChatCompletionsStreamResponseChoice{&choice}
+	openaiResponse.Choices = []*model.ChatCompletionsStreamResponseChoice{&choice}
 
 	return &openaiResponse
 }
 
-func Response2OpenAI(meta *meta.Meta, claudeResponse *Response) *openai.TextResponse {
+func Response2OpenAI(meta *meta.Meta, claudeResponse *Response) *model.TextResponse {
 	var content string
 	var thinking string
 	for _, v := range claudeResponse.Content {
@@ -304,7 +304,7 @@ func Response2OpenAI(meta *meta.Meta, claudeResponse *Response) *openai.TextResp
 			})
 		}
 	}
-	choice := openai.TextResponseChoice{
+	choice := model.TextResponseChoice{
 		Index: 0,
 		Message: model.Message{
 			Role:             "assistant",
@@ -316,12 +316,12 @@ func Response2OpenAI(meta *meta.Meta, claudeResponse *Response) *openai.TextResp
 		FinishReason: stopReasonClaude2OpenAI(claudeResponse.StopReason),
 	}
 
-	fullTextResponse := openai.TextResponse{
+	fullTextResponse := model.TextResponse{
 		ID:      openai.ChatCompletionID(),
 		Model:   meta.OriginModel,
 		Object:  model.ChatCompletion,
 		Created: time.Now().Unix(),
-		Choices: []*openai.TextResponseChoice{&choice},
+		Choices: []*model.TextResponseChoice{&choice},
 		Usage: model.Usage{
 			PromptTokens:     claudeResponse.Usage.InputTokens + claudeResponse.Usage.CacheReadInputTokens + claudeResponse.Usage.CacheCreationInputTokens,
 			CompletionTokens: claudeResponse.Usage.OutputTokens,
@@ -361,7 +361,7 @@ func StreamHandler(m *meta.Meta, c *gin.Context, resp *http.Response) (*model.Us
 	common.SetEventStreamHeaders(c)
 
 	var usage model.Usage
-	var lastToolCallChoice *openai.ChatCompletionsStreamResponseChoice
+	var lastToolCallChoice *model.ChatCompletionsStreamResponseChoice
 	var usageWrited bool
 
 	for scanner.Scan() {
@@ -419,12 +419,12 @@ func StreamHandler(m *meta.Meta, c *gin.Context, resp *http.Response) (*model.Us
 	usage.TotalTokens = usage.PromptTokens + usage.CompletionTokens
 
 	if !usageWrited {
-		_ = render.ObjectData(c, &openai.ChatCompletionsStreamResponse{
+		_ = render.ObjectData(c, &model.ChatCompletionsStreamResponse{
 			ID:      openai.ChatCompletionID(),
 			Model:   m.OriginModel,
 			Object:  model.ChatCompletionChunk,
 			Created: time.Now().Unix(),
-			Choices: []*openai.ChatCompletionsStreamResponseChoice{},
+			Choices: []*model.ChatCompletionsStreamResponseChoice{},
 			Usage:   &usage,
 		})
 	}

+ 3 - 3
relay/adaptor/anthropic/model.go

@@ -1,6 +1,6 @@
 package anthropic
 
-import relaymodel "github.com/labring/aiproxy/relay/model"
+import model "github.com/labring/aiproxy/relay/model"
 
 type OpenAIRequest struct {
 	ToolChoice  any              `json:"tool_choice,omitempty"`
@@ -17,12 +17,12 @@ type OpenAIRequest struct {
 }
 
 type OpenaiMessage struct {
-	relaymodel.Message
+	model.Message
 	CacheControl *CacheControl `json:"cache_control,omitempty"`
 }
 
 type OpenaiTool struct {
-	relaymodel.Tool
+	model.Tool
 	CacheControl *CacheControl `json:"cache_control,omitempty"`
 }
 

+ 10 - 10
relay/adaptor/aws/claude/main.go

@@ -19,8 +19,8 @@ import (
 	"github.com/labring/aiproxy/relay/adaptor/aws/utils"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 	"github.com/pkg/errors"
 )
 
@@ -36,7 +36,7 @@ var AwsModelIDMap = map[string]awsModelItem{
 	"claude-instant-1.2": {
 		ModelConfig: model.ModelConfig{
 			Model: "claude-instant-1.2",
-			Type:  relaymode.ChatCompletions,
+			Type:  mode.ChatCompletions,
 			Owner: model.ModelOwnerAnthropic,
 		},
 		ID: "anthropic.claude-instant-v1",
@@ -44,7 +44,7 @@ var AwsModelIDMap = map[string]awsModelItem{
 	"claude-2.0": {
 		ModelConfig: model.ModelConfig{
 			Model: "claude-2.0",
-			Type:  relaymode.ChatCompletions,
+			Type:  mode.ChatCompletions,
 			Owner: model.ModelOwnerAnthropic,
 		},
 		ID: "anthropic.claude-v2",
@@ -52,7 +52,7 @@ var AwsModelIDMap = map[string]awsModelItem{
 	"claude-2.1": {
 		ModelConfig: model.ModelConfig{
 			Model: "claude-2.1",
-			Type:  relaymode.ChatCompletions,
+			Type:  mode.ChatCompletions,
 			Owner: model.ModelOwnerAnthropic,
 		},
 		ID: "anthropic.claude-v2:1",
@@ -60,7 +60,7 @@ var AwsModelIDMap = map[string]awsModelItem{
 	"claude-3-haiku-20240307": {
 		ModelConfig: model.ModelConfig{
 			Model: "claude-3-haiku-20240307",
-			Type:  relaymode.ChatCompletions,
+			Type:  mode.ChatCompletions,
 			Owner: model.ModelOwnerAnthropic,
 		},
 		ID: "anthropic.claude-3-haiku-20240307-v1:0",
@@ -68,7 +68,7 @@ var AwsModelIDMap = map[string]awsModelItem{
 	"claude-3-5-sonnet-latest": {
 		ModelConfig: model.ModelConfig{
 			Model: "claude-3-5-sonnet-latest",
-			Type:  relaymode.ChatCompletions,
+			Type:  mode.ChatCompletions,
 			Owner: model.ModelOwnerAnthropic,
 		},
 		ID: "anthropic.claude-3-5-sonnet-20241022-v2:0",
@@ -76,7 +76,7 @@ var AwsModelIDMap = map[string]awsModelItem{
 	"claude-3-5-haiku-20241022": {
 		ModelConfig: model.ModelConfig{
 			Model: "claude-3-5-haiku-20241022",
-			Type:  relaymode.ChatCompletions,
+			Type:  mode.ChatCompletions,
 			Owner: model.ModelOwnerAnthropic,
 		},
 		ID: "anthropic.claude-3-5-haiku-20241022-v1:0",
@@ -188,7 +188,7 @@ func StreamHandler(meta *meta.Meta, c *gin.Context) (*relaymodel.ErrorWithStatus
 
 	c.Writer.Header().Set("Content-Type", "text/event-stream")
 	var usage relaymodel.Usage
-	var lastToolCallChoice *openai.ChatCompletionsStreamResponseChoice
+	var lastToolCallChoice *relaymodel.ChatCompletionsStreamResponseChoice
 	var usageWrited bool
 
 	c.Stream(func(_ io.Writer) bool {
@@ -246,12 +246,12 @@ func StreamHandler(meta *meta.Meta, c *gin.Context) (*relaymodel.ErrorWithStatus
 	})
 
 	if !usageWrited {
-		_ = render.ObjectData(c, &openai.ChatCompletionsStreamResponse{
+		_ = render.ObjectData(c, &relaymodel.ChatCompletionsStreamResponse{
 			ID:      openai.ChatCompletionID(),
 			Model:   meta.OriginModel,
 			Object:  relaymodel.ChatCompletionChunk,
 			Created: time.Now().Unix(),
-			Choices: []*openai.ChatCompletionsStreamResponseChoice{},
+			Choices: []*relaymodel.ChatCompletionsStreamResponseChoice{},
 			Usage:   &usage,
 		})
 	}

+ 11 - 11
relay/adaptor/aws/llama3/main.go

@@ -19,8 +19,8 @@ import (
 	"github.com/labring/aiproxy/relay/adaptor/aws/utils"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 )
@@ -37,7 +37,7 @@ var AwsModelIDMap = map[string]awsModelItem{
 	"llama3-8b-8192": {
 		ModelConfig: model.ModelConfig{
 			Model: "llama3-8b-8192",
-			Type:  relaymode.ChatCompletions,
+			Type:  mode.ChatCompletions,
 			Owner: model.ModelOwnerMeta,
 		},
 		ID: "meta.llama3-8b-instruct-v1:0",
@@ -45,7 +45,7 @@ var AwsModelIDMap = map[string]awsModelItem{
 	"llama3-70b-8192": {
 		ModelConfig: model.ModelConfig{
 			Model: "llama3-70b-8192",
-			Type:  relaymode.ChatCompletions,
+			Type:  mode.ChatCompletions,
 			Owner: model.ModelOwnerMeta,
 		},
 		ID: "meta.llama3-70b-instruct-v1:0",
@@ -140,12 +140,12 @@ func Handler(meta *meta.Meta, c *gin.Context) (*relaymodel.ErrorWithStatusCode,
 	return nil, &usage
 }
 
-func ResponseLlama2OpenAI(llamaResponse *Response) *openai.TextResponse {
+func ResponseLlama2OpenAI(llamaResponse *Response) *relaymodel.TextResponse {
 	var responseText string
 	if len(llamaResponse.Generation) > 0 {
 		responseText = llamaResponse.Generation
 	}
-	choice := openai.TextResponseChoice{
+	choice := relaymodel.TextResponseChoice{
 		Index: 0,
 		Message: relaymodel.Message{
 			Role:    "assistant",
@@ -154,11 +154,11 @@ func ResponseLlama2OpenAI(llamaResponse *Response) *openai.TextResponse {
 		},
 		FinishReason: llamaResponse.StopReason,
 	}
-	fullTextResponse := openai.TextResponse{
+	fullTextResponse := relaymodel.TextResponse{
 		ID:      openai.ChatCompletionID(),
 		Object:  relaymodel.ChatCompletion,
 		Created: time.Now().Unix(),
-		Choices: []*openai.TextResponseChoice{&choice},
+		Choices: []*relaymodel.TextResponseChoice{&choice},
 	}
 	return &fullTextResponse
 }
@@ -247,16 +247,16 @@ func StreamHandler(meta *meta.Meta, c *gin.Context) (*relaymodel.ErrorWithStatus
 	return nil, &usage
 }
 
-func StreamResponseLlama2OpenAI(llamaResponse *StreamResponse) *openai.ChatCompletionsStreamResponse {
-	var choice openai.ChatCompletionsStreamResponseChoice
+func StreamResponseLlama2OpenAI(llamaResponse *StreamResponse) *relaymodel.ChatCompletionsStreamResponse {
+	var choice relaymodel.ChatCompletionsStreamResponseChoice
 	choice.Delta.Content = llamaResponse.Generation
 	choice.Delta.Role = "assistant"
 	finishReason := llamaResponse.StopReason
 	if finishReason != "null" {
 		choice.FinishReason = &finishReason
 	}
-	var openaiResponse openai.ChatCompletionsStreamResponse
+	var openaiResponse relaymodel.ChatCompletionsStreamResponse
 	openaiResponse.Object = relaymodel.ChatCompletionChunk
-	openaiResponse.Choices = []*openai.ChatCompletionsStreamResponseChoice{&choice}
+	openaiResponse.Choices = []*relaymodel.ChatCompletionsStreamResponseChoice{&choice}
 	return &openaiResponse
 }

+ 3 - 3
relay/adaptor/aws/llama3/main_test.go

@@ -4,12 +4,12 @@ import (
 	"testing"
 
 	aws "github.com/labring/aiproxy/relay/adaptor/aws/llama3"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 	"github.com/stretchr/testify/assert"
 )
 
 func TestRenderPrompt(t *testing.T) {
-	messages := []*relaymodel.Message{
+	messages := []*model.Message{
 		{
 			Role:    "user",
 			Content: "What's your name?",
@@ -20,7 +20,7 @@ func TestRenderPrompt(t *testing.T) {
 `
 	assert.Equal(t, expected, prompt)
 
-	messages = []*relaymodel.Message{
+	messages = []*model.Message{
 		{
 			Role:    "system",
 			Content: "Your name is Kat. You are a detective.",

+ 4 - 4
relay/adaptor/aws/utils/utils.go

@@ -3,13 +3,13 @@ package utils
 import (
 	"net/http"
 
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 )
 
-func WrapErr(err error) *relaymodel.ErrorWithStatusCode {
-	return &relaymodel.ErrorWithStatusCode{
+func WrapErr(err error) *model.ErrorWithStatusCode {
+	return &model.ErrorWithStatusCode{
 		StatusCode: http.StatusInternalServerError,
-		Error: relaymodel.Error{
+		Error: model.Error{
 			Message: err.Error(),
 		},
 	}

+ 7 - 7
relay/adaptor/azure/constants.go

@@ -8,7 +8,7 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 type Adaptor struct {
@@ -26,22 +26,22 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 	}
 	model := strings.ReplaceAll(meta.ActualModel, ".", "")
 	switch meta.Mode {
-	case relaymode.ImagesGenerations:
+	case mode.ImagesGenerations:
 		// https://learn.microsoft.com/en-us/azure/ai-services/openai/dall-e-quickstart?tabs=dalle3%2Ccommand-line&pivots=rest-api
 		// https://{resource_name}.openai.azure.com/openai/deployments/dall-e-3/images/generations?api-version=2024-03-01-preview
 		return fmt.Sprintf("%s/openai/deployments/%s/images/generations?api-version=%s", meta.Channel.BaseURL, model, apiVersion), nil
-	case relaymode.AudioTranscription:
+	case mode.AudioTranscription:
 		// https://learn.microsoft.com/en-us/azure/ai-services/openai/whisper-quickstart?tabs=command-line#rest-api
 		return fmt.Sprintf("%s/openai/deployments/%s/audio/transcriptions?api-version=%s", meta.Channel.BaseURL, model, apiVersion), nil
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		// https://learn.microsoft.com/en-us/azure/ai-services/openai/text-to-speech-quickstart?tabs=command-line#rest-api
 		return fmt.Sprintf("%s/openai/deployments/%s/audio/speech?api-version=%s", meta.Channel.BaseURL, model, apiVersion), nil
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		// https://learn.microsoft.com/en-us/azure/cognitive-services/openai/chatgpt-quickstart?pivots=rest-api&tabs=command-line#rest-api
 		return fmt.Sprintf("%s/openai/deployments/%s/chat/completions?api-version=%s", meta.Channel.BaseURL, model, apiVersion), nil
-	case relaymode.Completions:
+	case mode.Completions:
 		return fmt.Sprintf("%s/openai/deployments/%s/completions?api-version=%s", meta.Channel.BaseURL, model, apiVersion), nil
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		return fmt.Sprintf("%s/openai/deployments/%s/embeddings?api-version=%s", meta.Channel.BaseURL, model, apiVersion), nil
 	default:
 		return "", fmt.Errorf("unsupported mode: %s", meta.Mode)

+ 7 - 7
relay/adaptor/baichuan/constants.go

@@ -2,13 +2,13 @@ package baichuan
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 var ModelList = []*model.ModelConfig{
 	{
 		Model:       "Baichuan4-Turbo",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaichuan,
 		InputPrice:  0.015,
 		OutputPrice: 0.015,
@@ -18,7 +18,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Baichuan4-Air",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaichuan,
 		InputPrice:  0.00098,
 		OutputPrice: 0.00098,
@@ -28,7 +28,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Baichuan4",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaichuan,
 		InputPrice:  0.1,
 		OutputPrice: 0.1,
@@ -38,7 +38,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Baichuan3-Turbo",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaichuan,
 		InputPrice:  0.012,
 		OutputPrice: 0.012,
@@ -48,7 +48,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Baichuan3-Turbo-128k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaichuan,
 		InputPrice:  0.024,
 		OutputPrice: 0.024,
@@ -59,7 +59,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:      "Baichuan-Text-Embedding",
-		Type:       relaymode.Embeddings,
+		Type:       mode.Embeddings,
 		Owner:      model.ModelOwnerBaichuan,
 		InputPrice: 0.0005,
 		Config: model.NewModelConfig(

+ 13 - 13
relay/adaptor/baidu/adaptor.go

@@ -11,8 +11,8 @@ import (
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -57,13 +57,13 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 	// Get API path suffix based on mode
 	var pathSuffix string
 	switch meta.Mode {
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		pathSuffix = "chat"
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		pathSuffix = "embeddings"
-	case relaymode.Rerank:
+	case mode.Rerank:
 		pathSuffix = "reranker"
-	case relaymode.ImagesGenerations:
+	case mode.ImagesGenerations:
 		pathSuffix = "text2image"
 	}
 
@@ -91,14 +91,14 @@ func (a *Adaptor) SetupRequestHeader(meta *meta.Meta, _ *gin.Context, req *http.
 
 func (a *Adaptor) ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io.Reader, error) {
 	switch meta.Mode {
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		meta.Set(openai.MetaEmbeddingsPatchInputToSlices, true)
 		return openai.ConvertRequest(meta, req)
-	case relaymode.Rerank:
+	case mode.Rerank:
 		return openai.ConvertRequest(meta, req)
-	case relaymode.ImagesGenerations:
+	case mode.ImagesGenerations:
 		return openai.ConvertRequest(meta, req)
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		return ConvertRequest(meta, req)
 	default:
 		return "", nil, nil, fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -111,13 +111,13 @@ func (a *Adaptor) DoRequest(_ *meta.Meta, _ *gin.Context, req *http.Request) (*h
 
 func (a *Adaptor) DoResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (usage *relaymodel.Usage, err *relaymodel.ErrorWithStatusCode) {
 	switch meta.Mode {
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		usage, err = EmbeddingsHandler(meta, c, resp)
-	case relaymode.Rerank:
+	case mode.Rerank:
 		usage, err = RerankHandler(meta, c, resp)
-	case relaymode.ImagesGenerations:
+	case mode.ImagesGenerations:
 		usage, err = ImageHandler(meta, c, resp)
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		if utils.IsStreamResponse(resp) {
 			err, usage = StreamHandler(meta, c, resp)
 		} else {

+ 8 - 8
relay/adaptor/baidu/constants.go

@@ -2,13 +2,13 @@ package baidu
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 var ModelList = []*model.ModelConfig{
 	{
 		Model:       "BLOOMZ-7B",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.004,
 		OutputPrice: 0.004,
@@ -19,7 +19,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:       "Embedding-V1",
-		Type:        relaymode.Embeddings,
+		Type:        mode.Embeddings,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0005,
 		OutputPrice: 0,
@@ -27,7 +27,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "bge-large-zh",
-		Type:        relaymode.Embeddings,
+		Type:        mode.Embeddings,
 		Owner:       model.ModelOwnerBAAI,
 		InputPrice:  0.0005,
 		OutputPrice: 0,
@@ -35,7 +35,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "bge-large-en",
-		Type:        relaymode.Embeddings,
+		Type:        mode.Embeddings,
 		Owner:       model.ModelOwnerBAAI,
 		InputPrice:  0.0005,
 		OutputPrice: 0,
@@ -43,7 +43,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "tao-8k",
-		Type:        relaymode.Embeddings,
+		Type:        mode.Embeddings,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0005,
 		OutputPrice: 0,
@@ -52,7 +52,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:       "bce-reranker-base_v1",
-		Type:        relaymode.Rerank,
+		Type:        mode.Rerank,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0005,
 		OutputPrice: 0,
@@ -61,7 +61,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model: "Stable-Diffusion-XL",
-		Type:  relaymode.ImagesGenerations,
+		Type:  mode.ImagesGenerations,
 		Owner: model.ModelOwnerStabilityAI,
 		ImagePrices: map[string]float64{
 			"768x768":   0.06,

+ 3 - 3
relay/adaptor/baidu/embeddings.go

@@ -9,15 +9,15 @@ import (
 	"github.com/labring/aiproxy/middleware"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 )
 
 type EmbeddingsResponse struct {
 	*Error
-	Usage relaymodel.Usage `json:"usage"`
+	Usage model.Usage `json:"usage"`
 }
 
-func EmbeddingsHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
+func EmbeddingsHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*model.Usage, *model.ErrorWithStatusCode) {
 	defer resp.Body.Close()
 
 	log := middleware.GetLogger(c)

+ 2 - 2
relay/adaptor/baidu/error.go

@@ -5,12 +5,12 @@ import (
 	"strconv"
 
 	"github.com/labring/aiproxy/relay/adaptor/openai"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 )
 
 // https://cloud.baidu.com/doc/WENXINWORKSHOP/s/tlmyncueh
 
-func ErrorHandler(baiduError *Error) *relaymodel.ErrorWithStatusCode {
+func ErrorHandler(baiduError *Error) *model.ErrorWithStatusCode {
 	switch baiduError.ErrorCode {
 	case 13, 14, 100, 110:
 		return openai.ErrorWrapperWithMessage(

+ 3 - 3
relay/adaptor/baidu/image.go

@@ -59,12 +59,12 @@ func ImageHandler(_ *meta.Meta, c *gin.Context, resp *http.Response) (*model.Usa
 	return usage, nil
 }
 
-func ToOpenAIImageResponse(imageResponse *ImageResponse) *openai.ImageResponse {
-	response := &openai.ImageResponse{
+func ToOpenAIImageResponse(imageResponse *ImageResponse) *model.ImageResponse {
+	response := &model.ImageResponse{
 		Created: imageResponse.Created,
 	}
 	for _, data := range imageResponse.Data {
-		response.Data = append(response.Data, &openai.ImageData{
+		response.Data = append(response.Data, &model.ImageData{
 			B64Json: data.B64Image,
 		})
 	}

+ 8 - 8
relay/adaptor/baidu/main.go

@@ -83,8 +83,8 @@ func ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io
 	return http.MethodPost, nil, bytes.NewReader(data), nil
 }
 
-func response2OpenAI(meta *meta.Meta, response *ChatResponse) *openai.TextResponse {
-	choice := openai.TextResponseChoice{
+func response2OpenAI(meta *meta.Meta, response *ChatResponse) *model.TextResponse {
+	choice := model.TextResponseChoice{
 		Index: 0,
 		Message: model.Message{
 			Role:    "assistant",
@@ -92,12 +92,12 @@ func response2OpenAI(meta *meta.Meta, response *ChatResponse) *openai.TextRespon
 		},
 		FinishReason: model.StopFinishReason,
 	}
-	fullTextResponse := openai.TextResponse{
+	fullTextResponse := model.TextResponse{
 		ID:      response.ID,
 		Object:  model.ChatCompletion,
 		Created: response.Created,
 		Model:   meta.OriginModel,
-		Choices: []*openai.TextResponseChoice{&choice},
+		Choices: []*model.TextResponseChoice{&choice},
 	}
 	if response.Usage != nil {
 		fullTextResponse.Usage = *response.Usage
@@ -105,19 +105,19 @@ func response2OpenAI(meta *meta.Meta, response *ChatResponse) *openai.TextRespon
 	return &fullTextResponse
 }
 
-func streamResponse2OpenAI(meta *meta.Meta, baiduResponse *ChatStreamResponse) *openai.ChatCompletionsStreamResponse {
-	var choice openai.ChatCompletionsStreamResponseChoice
+func streamResponse2OpenAI(meta *meta.Meta, baiduResponse *ChatStreamResponse) *model.ChatCompletionsStreamResponse {
+	var choice model.ChatCompletionsStreamResponseChoice
 	choice.Delta.Content = baiduResponse.Result
 	if baiduResponse.IsEnd {
 		finishReason := model.StopFinishReason
 		choice.FinishReason = &finishReason
 	}
-	response := openai.ChatCompletionsStreamResponse{
+	response := model.ChatCompletionsStreamResponse{
 		ID:      baiduResponse.ID,
 		Object:  model.ChatCompletionChunk,
 		Created: baiduResponse.Created,
 		Model:   meta.OriginModel,
-		Choices: []*openai.ChatCompletionsStreamResponseChoice{&choice},
+		Choices: []*model.ChatCompletionsStreamResponseChoice{&choice},
 		Usage:   baiduResponse.Usage,
 	}
 	return &response

+ 5 - 7
relay/adaptor/baiduv2/adaptor.go

@@ -11,8 +11,8 @@ import (
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -41,9 +41,9 @@ func toV2ModelName(modelName string) string {
 
 func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 	switch meta.Mode {
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		return meta.Channel.BaseURL + "/chat/completions", nil
-	case relaymode.Rerank:
+	case mode.Rerank:
 		return meta.Channel.BaseURL + "/rerankers", nil
 	default:
 		return "", fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -61,8 +61,7 @@ func (a *Adaptor) SetupRequestHeader(meta *meta.Meta, _ *gin.Context, req *http.
 
 func (a *Adaptor) ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io.Reader, error) {
 	switch meta.Mode {
-	case relaymode.ChatCompletions,
-		relaymode.Rerank:
+	case mode.ChatCompletions, mode.Rerank:
 		actModel := meta.ActualModel
 		v2Model := toV2ModelName(actModel)
 		if v2Model != actModel {
@@ -81,8 +80,7 @@ func (a *Adaptor) DoRequest(_ *meta.Meta, _ *gin.Context, req *http.Request) (*h
 
 func (a *Adaptor) DoResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (usage *relaymodel.Usage, err *relaymodel.ErrorWithStatusCode) {
 	switch meta.Mode {
-	case relaymode.ChatCompletions,
-		relaymode.Rerank:
+	case mode.ChatCompletions, mode.Rerank:
 		return openai.DoResponse(meta, c, resp)
 	default:
 		return nil, openai.ErrorWrapperWithMessage(

+ 22 - 22
relay/adaptor/baiduv2/constants.go

@@ -2,7 +2,7 @@ package baiduv2
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 // https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Fm2vrveyu
@@ -10,7 +10,7 @@ import (
 var ModelList = []*model.ModelConfig{
 	{
 		Model:       "ERNIE-4.0-8K-Latest",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.03,
 		OutputPrice: 0.09,
@@ -24,7 +24,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-4.0-8K-Preview",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.03,
 		OutputPrice: 0.09,
@@ -38,7 +38,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-4.0-8K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.03,
 		OutputPrice: 0.09,
@@ -52,7 +52,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-4.0-Turbo-8K-Latest",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.02,
 		OutputPrice: 0.06,
@@ -66,7 +66,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-4.0-Turbo-8K-Preview",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.02,
 		OutputPrice: 0.06,
@@ -80,7 +80,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-4.0-Turbo-8K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.02,
 		OutputPrice: 0.06,
@@ -94,7 +94,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-4.0-Turbo-128K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.02,
 		OutputPrice: 0.06,
@@ -108,7 +108,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-3.5-8K-Preview",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0008,
 		OutputPrice: 0.002,
@@ -122,7 +122,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-3.5-8K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0008,
 		OutputPrice: 0.002,
@@ -136,7 +136,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-3.5-128K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0008,
 		OutputPrice: 0.002,
@@ -150,7 +150,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-Speed-8K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0001,
 		OutputPrice: 0.0001,
@@ -163,7 +163,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-Speed-128K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0001,
 		OutputPrice: 0.0001,
@@ -176,7 +176,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-Speed-Pro-128K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0003,
 		OutputPrice: 0.0006,
@@ -189,7 +189,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-Lite-8K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0001,
 		OutputPrice: 0.0001,
@@ -202,7 +202,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-Lite-Pro-128K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0002,
 		OutputPrice: 0.0004,
@@ -216,7 +216,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-Tiny-8K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0001,
 		OutputPrice: 0.0001,
@@ -229,7 +229,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-Character-8K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0003,
 		OutputPrice: 0.0006,
@@ -242,7 +242,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-Character-Fiction-8K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.0003,
 		OutputPrice: 0.0006,
@@ -255,7 +255,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "ERNIE-Novel-8K",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerBaidu,
 		InputPrice:  0.04,
 		OutputPrice: 0.12,
@@ -269,7 +269,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:       "DeepSeek-V3",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDeepSeek,
 		InputPrice:  0.0008,
 		OutputPrice: 0.0016,
@@ -281,7 +281,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "DeepSeek-R1",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDeepSeek,
 		InputPrice:  0.002,
 		OutputPrice: 0.008,

+ 3 - 3
relay/adaptor/cloudflare/adaptor.go

@@ -7,7 +7,7 @@ import (
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 type Adaptor struct {
@@ -38,9 +38,9 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 	}
 
 	switch meta.Mode {
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		return urlPrefix + "/v1/chat/completions", nil
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		return urlPrefix + "/v1/embeddings", nil
 	default:
 		if isAIGateWay {

+ 31 - 31
relay/adaptor/cloudflare/constant.go

@@ -2,158 +2,158 @@ package cloudflare
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 var ModelList = []*model.ModelConfig{
 	{
 		Model: "@cf/meta/llama-3.1-8b-instruct",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "@cf/meta/llama-2-7b-chat-fp16",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "@cf/meta/llama-2-7b-chat-int8",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "@cf/mistral/mistral-7b-instruct-v0.1",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "@hf/thebloke/deepseek-coder-6.7b-base-awq",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerDeepSeek,
 	},
 	{
 		Model: "@hf/thebloke/deepseek-coder-6.7b-instruct-awq",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerDeepSeek,
 	},
 	{
 		Model: "@cf/deepseek-ai/deepseek-math-7b-base",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerDeepSeek,
 	},
 	{
 		Model: "@cf/deepseek-ai/deepseek-math-7b-instruct",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerDeepSeek,
 	},
 	{
 		Model: "@cf/google/gemma-2b-it-lora",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerGoogle,
 	},
 	{
 		Model: "@hf/google/gemma-7b-it",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerGoogle,
 	},
 	{
 		Model: "@cf/google/gemma-7b-it-lora",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerGoogle,
 	},
 	{
 		Model: "@hf/thebloke/llama-2-13b-chat-awq",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "@cf/meta-llama/llama-2-7b-chat-hf-lora",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "@cf/meta/llama-3-8b-instruct",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "@hf/thebloke/llamaguard-7b-awq",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "@hf/thebloke/mistral-7b-instruct-v0.1-awq",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "@hf/mistralai/mistral-7b-instruct-v0.2",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "@cf/mistral/mistral-7b-instruct-v0.2-lora",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "@hf/thebloke/neural-chat-7b-v3-1-awq",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "@cf/openchat/openchat-3.5-0106",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerOpenChat,
 	},
 	{
 		Model: "@hf/thebloke/openhermes-2.5-mistral-7b-awq",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "@cf/microsoft/phi-2",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMicrosoft,
 	},
 	{
 		Model: "@cf/qwen/qwen1.5-0.5b-chat",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerAlibaba,
 	},
 	{
 		Model: "@cf/qwen/qwen1.5-1.8b-chat",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerAlibaba,
 	},
 	{
 		Model: "@cf/qwen/qwen1.5-14b-chat-awq",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerAlibaba,
 	},
 	{
 		Model: "@cf/qwen/qwen1.5-7b-chat-awq",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerAlibaba,
 	},
 	{
 		Model: "@cf/defog/sqlcoder-7b-2",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerDefog,
 	},
 	{
 		Model: "@hf/nexusflow/starling-lm-7b-beta",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerNexusFlow,
 	},
 	{
 		Model: "@cf/tinyllama/tinyllama-1.1b-chat-v1.0",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "@hf/thebloke/zephyr-7b-beta-awq",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 }

+ 2 - 2
relay/adaptor/cohere/adaptor.go

@@ -11,8 +11,8 @@ import (
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -56,7 +56,7 @@ func (a *Adaptor) DoRequest(_ *meta.Meta, _ *gin.Context, req *http.Request) (*h
 
 func (a *Adaptor) DoResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (usage *relaymodel.Usage, err *relaymodel.ErrorWithStatusCode) {
 	switch meta.Mode {
-	case relaymode.Rerank:
+	case mode.Rerank:
 		usage, err = openai.RerankHandler(meta, c, resp)
 	default:
 		if utils.IsStreamResponse(resp) {

+ 7 - 7
relay/adaptor/cohere/constant.go

@@ -2,38 +2,38 @@ package cohere
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 var ModelList = []*model.ModelConfig{
 	{
 		Model: "command",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerCohere,
 	},
 	{
 		Model: "command-nightly",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerCohere,
 	},
 	{
 		Model: "command-light",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerCohere,
 	},
 	{
 		Model: "command-light-nightly",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerCohere,
 	},
 	{
 		Model: "command-r",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerCohere,
 	},
 	{
 		Model: "command-r-plus",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerCohere,
 	},
 }

+ 8 - 8
relay/adaptor/cohere/main.go

@@ -73,7 +73,7 @@ func ConvertRequest(textRequest *model.GeneralOpenAIRequest) *Request {
 	return &cohereRequest
 }
 
-func StreamResponse2OpenAI(meta *meta.Meta, cohereResponse *StreamResponse) *openai.ChatCompletionsStreamResponse {
+func StreamResponse2OpenAI(meta *meta.Meta, cohereResponse *StreamResponse) *model.ChatCompletionsStreamResponse {
 	var response *Response
 	var responseText string
 	var finishReason string
@@ -98,18 +98,18 @@ func StreamResponse2OpenAI(meta *meta.Meta, cohereResponse *StreamResponse) *ope
 		return nil
 	}
 
-	var choice openai.ChatCompletionsStreamResponseChoice
+	var choice model.ChatCompletionsStreamResponseChoice
 	choice.Delta.Content = responseText
 	choice.Delta.Role = "assistant"
 	if finishReason != "" {
 		choice.FinishReason = &finishReason
 	}
-	openaiResponse := openai.ChatCompletionsStreamResponse{
+	openaiResponse := model.ChatCompletionsStreamResponse{
 		ID:      "chatcmpl-" + cohereResponse.GenerationID,
 		Model:   meta.OriginModel,
 		Created: time.Now().Unix(),
 		Object:  model.ChatCompletionChunk,
-		Choices: []*openai.ChatCompletionsStreamResponseChoice{&choice},
+		Choices: []*model.ChatCompletionsStreamResponseChoice{&choice},
 	}
 	if response != nil {
 		openaiResponse.Usage = &model.Usage{
@@ -121,8 +121,8 @@ func StreamResponse2OpenAI(meta *meta.Meta, cohereResponse *StreamResponse) *ope
 	return &openaiResponse
 }
 
-func Response2OpenAI(meta *meta.Meta, cohereResponse *Response) *openai.TextResponse {
-	choice := openai.TextResponseChoice{
+func Response2OpenAI(meta *meta.Meta, cohereResponse *Response) *model.TextResponse {
+	choice := model.TextResponseChoice{
 		Index: 0,
 		Message: model.Message{
 			Role:    "assistant",
@@ -131,12 +131,12 @@ func Response2OpenAI(meta *meta.Meta, cohereResponse *Response) *openai.TextResp
 		},
 		FinishReason: stopReasonCohere2OpenAI(cohereResponse.FinishReason),
 	}
-	fullTextResponse := openai.TextResponse{
+	fullTextResponse := model.TextResponse{
 		ID:      openai.ChatCompletionID(),
 		Model:   meta.OriginModel,
 		Object:  model.ChatCompletion,
 		Created: time.Now().Unix(),
-		Choices: []*openai.TextResponseChoice{&choice},
+		Choices: []*model.TextResponseChoice{&choice},
 		Usage: model.Usage{
 			PromptTokens:     cohereResponse.Meta.Tokens.InputTokens,
 			CompletionTokens: cohereResponse.Meta.Tokens.OutputTokens,

+ 2 - 2
relay/adaptor/coze/adaptor.go

@@ -11,8 +11,8 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -38,7 +38,7 @@ func (a *Adaptor) SetupRequestHeader(meta *meta.Meta, _ *gin.Context, req *http.
 }
 
 func (a *Adaptor) ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io.Reader, error) {
-	if meta.Mode != relaymode.ChatCompletions {
+	if meta.Mode != mode.ChatCompletions {
 		return "", nil, nil, errors.New("coze only support chat completions")
 	}
 	request, err := utils.UnmarshalGeneralOpenAIRequest(req)

+ 8 - 8
relay/adaptor/coze/main.go

@@ -35,9 +35,9 @@ func stopReasonCoze2OpenAI(reason *string) string {
 	}
 }
 
-func StreamResponse2OpenAI(meta *meta.Meta, cozeResponse *StreamResponse) *openai.ChatCompletionsStreamResponse {
+func StreamResponse2OpenAI(meta *meta.Meta, cozeResponse *StreamResponse) *model.ChatCompletionsStreamResponse {
 	var stopReason string
-	var choice openai.ChatCompletionsStreamResponseChoice
+	var choice model.ChatCompletionsStreamResponseChoice
 
 	if cozeResponse.Message != nil {
 		if cozeResponse.Message.Type != messagetype.Answer {
@@ -50,17 +50,17 @@ func StreamResponse2OpenAI(meta *meta.Meta, cozeResponse *StreamResponse) *opena
 	if finishReason != "null" {
 		choice.FinishReason = &finishReason
 	}
-	openaiResponse := openai.ChatCompletionsStreamResponse{
+	openaiResponse := model.ChatCompletionsStreamResponse{
 		ID:      cozeResponse.ConversationID,
 		Model:   meta.OriginModel,
 		Created: time.Now().Unix(),
 		Object:  model.ChatCompletionChunk,
-		Choices: []*openai.ChatCompletionsStreamResponseChoice{&choice},
+		Choices: []*model.ChatCompletionsStreamResponseChoice{&choice},
 	}
 	return &openaiResponse
 }
 
-func Response2OpenAI(meta *meta.Meta, cozeResponse *Response) *openai.TextResponse {
+func Response2OpenAI(meta *meta.Meta, cozeResponse *Response) *model.TextResponse {
 	var responseText string
 	for _, message := range cozeResponse.Messages {
 		if message.Type == messagetype.Answer {
@@ -68,7 +68,7 @@ func Response2OpenAI(meta *meta.Meta, cozeResponse *Response) *openai.TextRespon
 			break
 		}
 	}
-	choice := openai.TextResponseChoice{
+	choice := model.TextResponseChoice{
 		Index: 0,
 		Message: model.Message{
 			Role:    "assistant",
@@ -77,12 +77,12 @@ func Response2OpenAI(meta *meta.Meta, cozeResponse *Response) *openai.TextRespon
 		},
 		FinishReason: model.StopFinishReason,
 	}
-	fullTextResponse := openai.TextResponse{
+	fullTextResponse := model.TextResponse{
 		ID:      openai.ChatCompletionID(),
 		Model:   meta.OriginModel,
 		Object:  model.ChatCompletion,
 		Created: time.Now().Unix(),
-		Choices: []*openai.TextResponseChoice{&choice},
+		Choices: []*model.TextResponseChoice{&choice},
 	}
 	return &fullTextResponse
 }

+ 3 - 3
relay/adaptor/deepseek/constants.go

@@ -2,13 +2,13 @@ package deepseek
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 var ModelList = []*model.ModelConfig{
 	{
 		Model:       "deepseek-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDeepSeek,
 		InputPrice:  0.001,
 		OutputPrice: 0.002,
@@ -22,7 +22,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:       "deepseek-reasoner",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDeepSeek,
 		InputPrice:  0.004,
 		OutputPrice: 0.016,

+ 4 - 4
relay/adaptor/doc2x/adaptor.go

@@ -10,8 +10,8 @@ import (
 	"github.com/labring/aiproxy/relay/adaptor"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -27,7 +27,7 @@ func (a *Adaptor) GetBaseURL() string {
 
 func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 	switch meta.Mode {
-	case relaymode.ParsePdf:
+	case mode.ParsePdf:
 		return meta.Channel.BaseURL + "/api/v2/parse/pdf", nil
 	default:
 		return "", fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -36,7 +36,7 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 
 func (a *Adaptor) ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io.Reader, error) {
 	switch meta.Mode {
-	case relaymode.ParsePdf:
+	case mode.ParsePdf:
 		return ConvertParsePdfRequest(meta, req)
 	default:
 		return "", nil, nil, fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -49,7 +49,7 @@ func (a *Adaptor) DoRequest(_ *meta.Meta, _ *gin.Context, req *http.Request) (*h
 
 func (a *Adaptor) DoResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
 	switch meta.Mode {
-	case relaymode.ParsePdf:
+	case mode.ParsePdf:
 		return HandleParsePdfResponse(meta, c, resp)
 	default:
 		return nil, openai.ErrorWrapperWithMessage(fmt.Sprintf("unsupported mode: %s", meta.Mode), "unsupported_mode", http.StatusBadRequest)

+ 2 - 2
relay/adaptor/doc2x/constants.go

@@ -2,13 +2,13 @@ package doc2x
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 var ModelList = []*model.ModelConfig{
 	{
 		Model:      "pdf",
-		Type:       relaymode.ParsePdf,
+		Type:       mode.ParsePdf,
 		Owner:      model.ModelOwnerDoc2x,
 		InputPrice: 20,
 		RPM:        10,

+ 6 - 6
relay/adaptor/doc2x/pdf.go

@@ -18,7 +18,7 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -49,7 +49,7 @@ type ParsePdfResponseData struct {
 	UID string `json:"uid"`
 }
 
-func HandleParsePdfResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
+func HandleParsePdfResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (*model.Usage, *model.ErrorWithStatusCode) {
 	var response ParsePdfResponse
 	err := sonic.ConfigDefault.NewDecoder(resp.Body).Decode(&response)
 	if err != nil {
@@ -316,7 +316,7 @@ func handleConvertPdfToMd(ctx context.Context, str string) string {
 	return result
 }
 
-func handleParsePdfResponse(meta *meta.Meta, c *gin.Context, response *StatusResponseDataResult) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
+func handleParsePdfResponse(meta *meta.Meta, c *gin.Context, response *StatusResponseDataResult) (*model.Usage, *model.ErrorWithStatusCode) {
 	mds := make([]string, 0, len(response.Pages))
 	totalLength := 0
 	for _, page := range response.Pages {
@@ -331,7 +331,7 @@ func handleParsePdfResponse(meta *meta.Meta, c *gin.Context, response *StatusRes
 			result := handleConvertPdfToMd(c.Request.Context(), md)
 			mds[i] = result
 		}
-		c.JSON(http.StatusOK, relaymodel.ParsePdfListResponse{
+		c.JSON(http.StatusOK, model.ParsePdfListResponse{
 			Markdowns: mds,
 		})
 	default:
@@ -341,13 +341,13 @@ func handleParsePdfResponse(meta *meta.Meta, c *gin.Context, response *StatusRes
 			builder.WriteString(md)
 		}
 		result := handleConvertPdfToMd(c.Request.Context(), builder.String())
-		c.JSON(http.StatusOK, relaymodel.ParsePdfResponse{
+		c.JSON(http.StatusOK, model.ParsePdfResponse{
 			Pages:    pages,
 			Markdown: result,
 		})
 	}
 
-	return &relaymodel.Usage{
+	return &model.Usage{
 		PromptTokens: pages,
 		TotalTokens:  pages,
 	}, nil

+ 16 - 16
relay/adaptor/doubao/constants.go

@@ -2,7 +2,7 @@ package doubao
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 // https://console.volcengine.com/ark/region:ark+cn-beijing/model
@@ -10,7 +10,7 @@ import (
 var ModelList = []*model.ModelConfig{
 	{
 		Model:       "Doubao-1.5-vision-pro-32k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.003,
 		OutputPrice: 0.009,
@@ -22,7 +22,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Doubao-1.5-pro-32k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.0008,
 		OutputPrice: 0.0020,
@@ -35,7 +35,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Doubao-1.5-pro-256k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.005,
 		OutputPrice: 0.009,
@@ -48,7 +48,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Doubao-1.5-lite-32k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.0003,
 		OutputPrice: 0.0006,
@@ -62,7 +62,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:       "Doubao-vision-lite-32k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.008,
 		OutputPrice: 0.008,
@@ -74,7 +74,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Doubao-vision-pro-32k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.02,
 		OutputPrice: 0.02,
@@ -86,7 +86,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Doubao-pro-256k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.0050,
 		OutputPrice: 0.0090,
@@ -98,7 +98,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Doubao-pro-128k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.0050,
 		OutputPrice: 0.0090,
@@ -111,7 +111,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Doubao-pro-32k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.0008,
 		OutputPrice: 0.0020,
@@ -124,7 +124,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Doubao-pro-4k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.0008,
 		OutputPrice: 0.0020,
@@ -137,7 +137,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Doubao-lite-128k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.0008,
 		OutputPrice: 0.0010,
@@ -150,7 +150,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Doubao-lite-32k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.0003,
 		OutputPrice: 0.0006,
@@ -163,7 +163,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "Doubao-lite-4k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerDoubao,
 		InputPrice:  0.0003,
 		OutputPrice: 0.0006,
@@ -177,7 +177,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:      "Doubao-embedding",
-		Type:       relaymode.Embeddings,
+		Type:       mode.Embeddings,
 		Owner:      model.ModelOwnerDoubao,
 		InputPrice: 0.0005,
 		RPM:        1200,
@@ -187,7 +187,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:      "Doubao-embedding-large",
-		Type:       relaymode.Embeddings,
+		Type:       mode.Embeddings,
 		Owner:      model.ModelOwnerDoubao,
 		InputPrice: 0.0007,
 		RPM:        1000,

+ 4 - 4
relay/adaptor/doubao/main.go

@@ -13,19 +13,19 @@ import (
 	"github.com/labring/aiproxy/relay/adaptor"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 )
 
 func GetRequestURL(meta *meta.Meta) (string, error) {
 	u := meta.Channel.BaseURL
 	switch meta.Mode {
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		if strings.HasPrefix(meta.ActualModel, "bot-") {
 			return u + "/api/v3/bots/chat/completions", nil
 		}
 		return u + "/api/v3/chat/completions", nil
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		return u + "/api/v3/embeddings", nil
 	default:
 		return "", fmt.Errorf("unsupported relay mode %d for doubao", meta.Mode)
@@ -55,7 +55,7 @@ func (a *Adaptor) ConvertRequest(meta *meta.Meta, req *http.Request) (string, ht
 	if err != nil {
 		return "", nil, nil, err
 	}
-	if meta.Mode != relaymode.ChatCompletions || meta.OriginModel != "deepseek-reasoner" {
+	if meta.Mode != mode.ChatCompletions || meta.OriginModel != "deepseek-reasoner" {
 		return method, header, body, nil
 	}
 

+ 3 - 3
relay/adaptor/doubaoaudio/constants.go

@@ -2,7 +2,7 @@ package doubaoaudio
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 // https://www.volcengine.com/docs/6561/1257543
@@ -10,7 +10,7 @@ import (
 var ModelList = []*model.ModelConfig{
 	{
 		Model:      "Doubao-tts",
-		Type:       relaymode.AudioSpeech,
+		Type:       mode.AudioSpeech,
 		Owner:      model.ModelOwnerDoubao,
 		InputPrice: 0.5,
 		RPM:        60,
@@ -99,7 +99,7 @@ var ModelList = []*model.ModelConfig{
 
 	// {
 	// 	Model:      "Doubao-stt",
-	// 	Type:       relaymode.AudioTranscription,
+	// 	Type:       mode.AudioTranscription,
 	// 	Owner:      model.ModelOwnerDoubao,
 	// 	InputPrice: 2.3,
 	// },

+ 6 - 6
relay/adaptor/doubaoaudio/main.go

@@ -9,14 +9,14 @@ import (
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 )
 
 func GetRequestURL(meta *meta.Meta) (string, error) {
 	u := meta.Channel.BaseURL
 	switch meta.Mode {
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		return u + "/api/v1/tts/ws_binary", nil
 	default:
 		return "", fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -41,7 +41,7 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 
 func (a *Adaptor) ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io.Reader, error) {
 	switch meta.Mode {
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		return ConvertTTSRequest(meta, req)
 	default:
 		return "", nil, nil, fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -50,7 +50,7 @@ func (a *Adaptor) ConvertRequest(meta *meta.Meta, req *http.Request) (string, ht
 
 func (a *Adaptor) SetupRequestHeader(meta *meta.Meta, _ *gin.Context, req *http.Request) error {
 	switch meta.Mode {
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		_, token, err := getAppIDAndToken(meta.Channel.Key)
 		if err != nil {
 			return err
@@ -64,7 +64,7 @@ func (a *Adaptor) SetupRequestHeader(meta *meta.Meta, _ *gin.Context, req *http.
 
 func (a *Adaptor) DoRequest(meta *meta.Meta, _ *gin.Context, req *http.Request) (*http.Response, error) {
 	switch meta.Mode {
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		return TTSDoRequest(meta, req)
 	default:
 		return nil, fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -73,7 +73,7 @@ func (a *Adaptor) DoRequest(meta *meta.Meta, _ *gin.Context, req *http.Request)
 
 func (a *Adaptor) DoResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
 	switch meta.Mode {
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		return TTSDoResponse(meta, c, resp)
 	default:
 		return nil, openai.ErrorWrapperWithMessage(

+ 3 - 3
relay/adaptor/doubaoaudio/tts.go

@@ -17,7 +17,7 @@ import (
 	"github.com/labring/aiproxy/middleware"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -174,13 +174,13 @@ func TTSDoRequest(meta *meta.Meta, req *http.Request) (*http.Response, error) {
 	}, nil
 }
 
-func TTSDoResponse(meta *meta.Meta, c *gin.Context, _ *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
+func TTSDoResponse(meta *meta.Meta, c *gin.Context, _ *http.Response) (*model.Usage, *model.ErrorWithStatusCode) {
 	log := middleware.GetLogger(c)
 
 	conn := meta.MustGet("ws_conn").(*websocket.Conn)
 	defer conn.Close()
 
-	usage := &relaymodel.Usage{
+	usage := &model.Usage{
 		PromptTokens: meta.InputTokens,
 		TotalTokens:  meta.InputTokens,
 	}

+ 6 - 6
relay/adaptor/gemini/adaptor.go

@@ -9,8 +9,8 @@ import (
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -39,7 +39,7 @@ func getRequestURL(meta *meta.Meta, action string) string {
 func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 	var action string
 	switch meta.Mode {
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		action = "batchEmbedContents"
 	default:
 		action = "generateContent"
@@ -58,9 +58,9 @@ func (a *Adaptor) SetupRequestHeader(meta *meta.Meta, _ *gin.Context, req *http.
 
 func (a *Adaptor) ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io.Reader, error) {
 	switch meta.Mode {
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		return ConvertEmbeddingRequest(meta, req)
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		return ConvertRequest(meta, req)
 	default:
 		return "", nil, nil, fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -73,9 +73,9 @@ func (a *Adaptor) DoRequest(_ *meta.Meta, _ *gin.Context, req *http.Request) (*h
 
 func (a *Adaptor) DoResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (usage *relaymodel.Usage, err *relaymodel.ErrorWithStatusCode) {
 	switch meta.Mode {
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		usage, err = EmbeddingHandler(meta, c, resp)
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		if utils.IsStreamResponse(resp) {
 			usage, err = StreamHandler(meta, c, resp)
 		} else {

+ 9 - 9
relay/adaptor/gemini/constants.go

@@ -2,7 +2,7 @@ package gemini
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 // https://ai.google.dev/models/gemini
@@ -11,7 +11,7 @@ import (
 var ModelList = []*model.ModelConfig{
 	{
 		Model:       "gemini-1.5-pro",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerGoogle,
 		InputPrice:  0.0025,
 		OutputPrice: 0.01,
@@ -25,7 +25,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "gemini-1.5-flash",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerGoogle,
 		InputPrice:  0.00015,
 		OutputPrice: 0.0006,
@@ -39,7 +39,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "gemini-1.5-flash-8b",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerGoogle,
 		InputPrice:  0.000075,
 		OutputPrice: 0.0003,
@@ -53,7 +53,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "gemini-2.0-flash",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerGoogle,
 		InputPrice:  0.0001,
 		OutputPrice: 0.0004,
@@ -67,7 +67,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "gemini-2.0-flash-lite-preview",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerGoogle,
 		InputPrice:  0.000075,
 		OutputPrice: 0.0003,
@@ -81,7 +81,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "gemini-2.0-flash-thinking-exp",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerGoogle,
 		InputPrice:  0.0001,
 		OutputPrice: 0.0004,
@@ -94,7 +94,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "gemini-2.0-pro-exp",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerGoogle,
 		InputPrice:  0.0025,
 		OutputPrice: 0.01,
@@ -109,7 +109,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:      "text-embedding-004",
-		Type:       relaymode.Embeddings,
+		Type:       mode.Embeddings,
 		Owner:      model.ModelOwnerGoogle,
 		InputPrice: 0.0001,
 		RPM:        1500,

+ 4 - 4
relay/adaptor/gemini/embeddings.go

@@ -72,15 +72,15 @@ func EmbeddingHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*mo
 	return &fullTextResponse.Usage, nil
 }
 
-func embeddingResponse2OpenAI(meta *meta.Meta, response *EmbeddingResponse) *openai.EmbeddingResponse {
-	openAIEmbeddingResponse := openai.EmbeddingResponse{
+func embeddingResponse2OpenAI(meta *meta.Meta, response *EmbeddingResponse) *model.EmbeddingResponse {
+	openAIEmbeddingResponse := model.EmbeddingResponse{
 		Object: "list",
-		Data:   make([]*openai.EmbeddingResponseItem, 0, len(response.Embeddings)),
+		Data:   make([]*model.EmbeddingResponseItem, 0, len(response.Embeddings)),
 		Model:  meta.OriginModel,
 		Usage:  model.Usage{TotalTokens: 0},
 	}
 	for _, item := range response.Embeddings {
-		openAIEmbeddingResponse.Data = append(openAIEmbeddingResponse.Data, &openai.EmbeddingResponseItem{
+		openAIEmbeddingResponse.Data = append(openAIEmbeddingResponse.Data, &model.EmbeddingResponseItem{
 			Object:    `embedding`,
 			Index:     0,
 			Embedding: item.Values,

+ 8 - 8
relay/adaptor/gemini/main.go

@@ -338,13 +338,13 @@ func getToolCall(item *Part) (*model.Tool, error) {
 	return &toolCall, nil
 }
 
-func responseGeminiChat2OpenAI(meta *meta.Meta, response *ChatResponse) *openai.TextResponse {
-	fullTextResponse := openai.TextResponse{
+func responseGeminiChat2OpenAI(meta *meta.Meta, response *ChatResponse) *model.TextResponse {
+	fullTextResponse := model.TextResponse{
 		ID:      openai.ChatCompletionID(),
 		Model:   meta.OriginModel,
 		Object:  model.ChatCompletion,
 		Created: time.Now().Unix(),
-		Choices: make([]*openai.TextResponseChoice, 0, len(response.Candidates)),
+		Choices: make([]*model.TextResponseChoice, 0, len(response.Candidates)),
 	}
 	if response.UsageMetadata != nil {
 		fullTextResponse.Usage = model.Usage{
@@ -354,7 +354,7 @@ func responseGeminiChat2OpenAI(meta *meta.Meta, response *ChatResponse) *openai.
 		}
 	}
 	for i, candidate := range response.Candidates {
-		choice := openai.TextResponseChoice{
+		choice := model.TextResponseChoice{
 			Index: i,
 			Message: model.Message{
 				Role:    "assistant",
@@ -406,13 +406,13 @@ func responseGeminiChat2OpenAI(meta *meta.Meta, response *ChatResponse) *openai.
 	return &fullTextResponse
 }
 
-func streamResponseGeminiChat2OpenAI(meta *meta.Meta, geminiResponse *ChatResponse) *openai.ChatCompletionsStreamResponse {
-	response := &openai.ChatCompletionsStreamResponse{
+func streamResponseGeminiChat2OpenAI(meta *meta.Meta, geminiResponse *ChatResponse) *model.ChatCompletionsStreamResponse {
+	response := &model.ChatCompletionsStreamResponse{
 		ID:      openai.ChatCompletionID(),
 		Created: time.Now().Unix(),
 		Model:   meta.OriginModel,
 		Object:  model.ChatCompletionChunk,
-		Choices: make([]*openai.ChatCompletionsStreamResponseChoice, 0, len(geminiResponse.Candidates)),
+		Choices: make([]*model.ChatCompletionsStreamResponseChoice, 0, len(geminiResponse.Candidates)),
 	}
 	if geminiResponse.UsageMetadata != nil {
 		response.Usage = &model.Usage{
@@ -422,7 +422,7 @@ func streamResponseGeminiChat2OpenAI(meta *meta.Meta, geminiResponse *ChatRespon
 		}
 	}
 	for i, candidate := range geminiResponse.Candidates {
-		choice := openai.ChatCompletionsStreamResponseChoice{
+		choice := model.ChatCompletionsStreamResponseChoice{
 			Index: i,
 			Delta: model.Message{
 				Content: "",

+ 22 - 22
relay/adaptor/groq/constants.go

@@ -2,7 +2,7 @@ package groq
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 // https://console.groq.com/docs/models
@@ -10,107 +10,107 @@ import (
 var ModelList = []*model.ModelConfig{
 	{
 		Model: "gemma-7b-it",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerGoogle,
 	},
 	{
 		Model: "gemma2-9b-it",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerGoogle,
 	},
 	{
 		Model: "llama-3.1-70b-versatile",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama-3.1-8b-instant",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama-3.2-11b-text-preview",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama-3.2-11b-vision-preview",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama-3.2-1b-preview",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama-3.2-3b-preview",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama-3.2-11b-vision-preview",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama-3.2-90b-text-preview",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama-3.2-90b-vision-preview",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama-guard-3-8b",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama3-70b-8192",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama3-8b-8192",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama3-groq-70b-8192-tool-use-preview",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama3-groq-8b-8192-tool-use-preview",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llava-v1.5-7b-4096-preview",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "mixtral-8x7b-32768",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "distil-whisper-large-v3-en",
-		Type:  relaymode.AudioTranscription,
+		Type:  mode.AudioTranscription,
 		Owner: model.ModelOwnerHuggingFace,
 	},
 	{
 		Model: "whisper-large-v3",
-		Type:  relaymode.AudioTranscription,
+		Type:  mode.AudioTranscription,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "whisper-large-v3-turbo",
-		Type:  relaymode.AudioTranscription,
+		Type:  mode.AudioTranscription,
 		Owner: model.ModelOwnerOpenAI,
 	},
 }

+ 3 - 3
relay/adaptor/lingyiwanwu/constants.go

@@ -2,7 +2,7 @@ package lingyiwanwu
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 // https://platform.lingyiwanwu.com/docs
@@ -10,7 +10,7 @@ import (
 var ModelList = []*model.ModelConfig{
 	{
 		Model:       "yi-lightning",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerLingyiWanwu,
 		InputPrice:  0.00099,
 		OutputPrice: 0.00099,
@@ -22,7 +22,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "yi-vision-v2",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerLingyiWanwu,
 		InputPrice:  0.006,
 		OutputPrice: 0.006,

+ 7 - 7
relay/adaptor/minimax/adaptor.go

@@ -10,8 +10,8 @@ import (
 	"github.com/labring/aiproxy/relay/adaptor"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 )
 
 type Adaptor struct {
@@ -43,11 +43,11 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 		return "", err
 	}
 	switch meta.Mode {
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		return meta.Channel.BaseURL + "/text/chatcompletion_v2", nil
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		return fmt.Sprintf("%s/embeddings?GroupId=%s", meta.Channel.BaseURL, groupID), nil
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		return fmt.Sprintf("%s/t2a_v2?GroupId=%s", meta.Channel.BaseURL, groupID), nil
 	default:
 		return a.Adaptor.GetRequestURL(meta)
@@ -56,10 +56,10 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 
 func (a *Adaptor) ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io.Reader, error) {
 	switch meta.Mode {
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		meta.Set(openai.DoNotPatchStreamOptionsIncludeUsageMetaKey, true)
 		return a.Adaptor.ConvertRequest(meta, req)
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		return ConvertTTSRequest(meta, req)
 	default:
 		return a.Adaptor.ConvertRequest(meta, req)
@@ -68,7 +68,7 @@ func (a *Adaptor) ConvertRequest(meta *meta.Meta, req *http.Request) (string, ht
 
 func (a *Adaptor) DoResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (usage *relaymodel.Usage, err *relaymodel.ErrorWithStatusCode) {
 	switch meta.Mode {
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		return TTSHandler(meta, c, resp)
 	default:
 		return a.Adaptor.DoResponse(meta, c, resp)

+ 8 - 8
relay/adaptor/minimax/constants.go

@@ -2,7 +2,7 @@ package minimax
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 // https://www.minimaxi.com/document/guides/chat-model/V2?id=65e0736ab2845de20908e2dd
@@ -10,7 +10,7 @@ import (
 var ModelList = []*model.ModelConfig{
 	{
 		Model:       "abab7-chat-preview",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerMiniMax,
 		InputPrice:  0.01,
 		OutputPrice: 0.01,
@@ -22,7 +22,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "abab6.5s-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerMiniMax,
 		InputPrice:  0.001,
 		OutputPrice: 0.001,
@@ -34,7 +34,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "abab6.5g-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerMiniMax,
 		InputPrice:  0.005,
 		OutputPrice: 0.005,
@@ -46,7 +46,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "abab6.5t-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerMiniMax,
 		InputPrice:  0.005,
 		OutputPrice: 0.005,
@@ -58,7 +58,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "abab5.5s-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerMiniMax,
 		InputPrice:  0.005,
 		OutputPrice: 0.005,
@@ -70,7 +70,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "abab5.5-chat",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerMiniMax,
 		InputPrice:  0.015,
 		OutputPrice: 0.015,
@@ -83,7 +83,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:      "speech-01-turbo",
-		Type:       relaymode.AudioSpeech,
+		Type:       mode.AudioSpeech,
 		Owner:      model.ModelOwnerMiniMax,
 		InputPrice: 0.2,
 		RPM:        20,

+ 5 - 5
relay/adaptor/minimax/tts.go

@@ -14,7 +14,7 @@ import (
 	"github.com/labring/aiproxy/middleware"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -105,7 +105,7 @@ type TTSResponse struct {
 	Data      TTSData      `json:"data"`
 }
 
-func TTSHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
+func TTSHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*model.Usage, *model.ErrorWithStatusCode) {
 	if resp.StatusCode != http.StatusOK {
 		return nil, openai.ErrorHanlder(resp)
 	}
@@ -148,13 +148,13 @@ func TTSHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymod
 		usageCharacters = result.ExtraInfo.UsageCharacters
 	}
 
-	return &relaymodel.Usage{
+	return &model.Usage{
 		PromptTokens: usageCharacters,
 		TotalTokens:  usageCharacters,
 	}, nil
 }
 
-func ttsStreamHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
+func ttsStreamHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*model.Usage, *model.ErrorWithStatusCode) {
 	defer resp.Body.Close()
 
 	resp.Header.Set("Content-Type", "application/octet-stream")
@@ -197,7 +197,7 @@ func ttsStreamHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*re
 		}
 	}
 
-	return &relaymodel.Usage{
+	return &model.Usage{
 		PromptTokens: usageCharacters,
 		TotalTokens:  usageCharacters,
 	}, nil

+ 7 - 7
relay/adaptor/mistral/constants.go

@@ -2,38 +2,38 @@ package mistral
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 var ModelList = []*model.ModelConfig{
 	{
 		Model: "open-mistral-7b",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "open-mixtral-8x7b",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "mistral-small-latest",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "mistral-medium-latest",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "mistral-large-latest",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "mistral-embed",
-		Type:  relaymode.Embeddings,
+		Type:  mode.Embeddings,
 		Owner: model.ModelOwnerMistral,
 	},
 }

+ 7 - 7
relay/adaptor/moonshot/constants.go

@@ -2,13 +2,13 @@ package moonshot
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 var ModelList = []*model.ModelConfig{
 	{
 		Model:       "moonshot-v1-8k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerMoonshot,
 		InputPrice:  0.012,
 		OutputPrice: 0.012,
@@ -20,7 +20,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "moonshot-v1-32k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerMoonshot,
 		InputPrice:  0.024,
 		OutputPrice: 0.024,
@@ -32,7 +32,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "moonshot-v1-128k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerMoonshot,
 		InputPrice:  0.06,
 		OutputPrice: 0.06,
@@ -45,7 +45,7 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model:       "moonshot-v1-8k-vision-preview",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerMoonshot,
 		InputPrice:  0.012,
 		OutputPrice: 0.012,
@@ -58,7 +58,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "moonshot-v1-32k-vision-preview",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerMoonshot,
 		InputPrice:  0.024,
 		OutputPrice: 0.024,
@@ -71,7 +71,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "moonshot-v1-128k-vision-preview",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerMoonshot,
 		InputPrice:  0.06,
 		OutputPrice: 0.06,

+ 8 - 8
relay/adaptor/novita/constants.go

@@ -2,7 +2,7 @@ package novita
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 // https://novita.ai/llm-api
@@ -10,37 +10,37 @@ import (
 var ModelList = []*model.ModelConfig{
 	{
 		Model: "meta-llama/llama-3-8b-instruct",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "meta-llama/llama-3-70b-instruct",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "nousresearch/hermes-2-pro-llama-3-8b",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "nousresearch/nous-hermes-llama2-13b",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "mistralai/mistral-7b-instruct",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "teknium/openhermes-2.5-mistral-7b",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMistral,
 	},
 	{
 		Model: "microsoft/wizardlm-2-8x22b",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMicrosoft,
 	},
 }

+ 8 - 8
relay/adaptor/ollama/adaptor.go

@@ -10,8 +10,8 @@ import (
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -27,11 +27,11 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 	// https://github.com/ollama/ollama/blob/main/docs/api.md
 	u := meta.Channel.BaseURL
 	switch meta.Mode {
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		return u + "/api/embed", nil
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		return u + "/api/chat", nil
-	case relaymode.Completions:
+	case mode.Completions:
 		return u + "/api/generate", nil
 	default:
 		return "", fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -48,9 +48,9 @@ func (a *Adaptor) ConvertRequest(meta *meta.Meta, request *http.Request) (string
 		return "", nil, nil, errors.New("request is nil")
 	}
 	switch meta.Mode {
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		return ConvertEmbeddingRequest(meta, request)
-	case relaymode.ChatCompletions, relaymode.Completions:
+	case mode.ChatCompletions, mode.Completions:
 		return ConvertRequest(meta, request)
 	default:
 		return "", nil, nil, fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -63,9 +63,9 @@ func (a *Adaptor) DoRequest(_ *meta.Meta, _ *gin.Context, req *http.Request) (*h
 
 func (a *Adaptor) DoResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (usage *relaymodel.Usage, err *relaymodel.ErrorWithStatusCode) {
 	switch meta.Mode {
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		usage, err = EmbeddingHandler(meta, c, resp)
-	case relaymode.ChatCompletions, relaymode.Completions:
+	case mode.ChatCompletions, mode.Completions:
 		if utils.IsStreamResponse(resp) {
 			usage, err = StreamHandler(meta, c, resp)
 		} else {

+ 8 - 8
relay/adaptor/ollama/constants.go

@@ -2,43 +2,43 @@ package ollama
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 var ModelList = []*model.ModelConfig{
 	{
 		Model: "codellama:7b-instruct",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama2:7b",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama2:latest",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "llama3:latest",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMeta,
 	},
 	{
 		Model: "phi3:latest",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerMicrosoft,
 	},
 	{
 		Model: "qwen:0.5b-chat",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerAlibaba,
 	},
 	{
 		Model: "qwen:7b",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerAlibaba,
 	},
 }

+ 2 - 2
relay/adaptor/ollama/error.go

@@ -7,14 +7,14 @@ import (
 	"github.com/bytedance/sonic"
 	"github.com/labring/aiproxy/common/conv"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 )
 
 type errorResponse struct {
 	Error string `json:"error"`
 }
 
-func ErrorHandler(resp *http.Response) *relaymodel.ErrorWithStatusCode {
+func ErrorHandler(resp *http.Response) *model.ErrorWithStatusCode {
 	defer resp.Body.Close()
 
 	data, err := io.ReadAll(resp.Body)

+ 32 - 32
relay/adaptor/ollama/main.go

@@ -16,12 +16,12 @@ import (
 	"github.com/labring/aiproxy/middleware"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	"github.com/labring/aiproxy/relay/model"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
 func ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io.Reader, error) {
-	var request relaymodel.GeneralOpenAIRequest
+	var request model.GeneralOpenAIRequest
 	err := common.UnmarshalBodyReusable(req, &request)
 	if err != nil {
 		return "", nil, nil, err
@@ -58,9 +58,9 @@ func ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io
 		var contentText string
 		for _, part := range openaiContent {
 			switch part.Type {
-			case relaymodel.ContentTypeText:
+			case model.ContentTypeText:
 				contentText = part.Text
-			case relaymodel.ContentTypeImageURL:
+			case model.ContentTypeImageURL:
 				_, data, err := image.GetImageFromURL(req.Context(), part.ImageURL.URL)
 				if err != nil {
 					return "", nil, nil, err
@@ -111,20 +111,20 @@ func ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io
 	return http.MethodPost, nil, bytes.NewReader(data), nil
 }
 
-func getToolCalls(ollamaResponse *ChatResponse) []*relaymodel.Tool {
+func getToolCalls(ollamaResponse *ChatResponse) []*model.Tool {
 	if ollamaResponse.Message == nil || len(ollamaResponse.Message.ToolCalls) == 0 {
 		return nil
 	}
-	toolCalls := make([]*relaymodel.Tool, 0, len(ollamaResponse.Message.ToolCalls))
+	toolCalls := make([]*model.Tool, 0, len(ollamaResponse.Message.ToolCalls))
 	for _, tool := range ollamaResponse.Message.ToolCalls {
 		argString, err := sonic.MarshalString(tool.Function.Arguments)
 		if err != nil {
 			continue
 		}
-		toolCalls = append(toolCalls, &relaymodel.Tool{
+		toolCalls = append(toolCalls, &model.Tool{
 			ID:   openai.CallID(),
 			Type: "function",
-			Function: relaymodel.Function{
+			Function: model.Function{
 				Name:      tool.Function.Name,
 				Arguments: argString,
 			},
@@ -133,12 +133,12 @@ func getToolCalls(ollamaResponse *ChatResponse) []*relaymodel.Tool {
 	return toolCalls
 }
 
-func response2OpenAI(meta *meta.Meta, response *ChatResponse) *openai.TextResponse {
-	choice := openai.TextResponseChoice{
+func response2OpenAI(meta *meta.Meta, response *ChatResponse) *model.TextResponse {
+	choice := model.TextResponseChoice{
 		Text: response.Response,
 	}
 	if response.Message != nil {
-		choice.Message = relaymodel.Message{
+		choice.Message = model.Message{
 			Role:      response.Message.Role,
 			Content:   response.Message.Content,
 			ToolCalls: getToolCalls(response),
@@ -147,13 +147,13 @@ func response2OpenAI(meta *meta.Meta, response *ChatResponse) *openai.TextRespon
 	if response.Done {
 		choice.FinishReason = response.DoneReason
 	}
-	fullTextResponse := openai.TextResponse{
+	fullTextResponse := model.TextResponse{
 		ID:      openai.ChatCompletionID(),
 		Model:   meta.OriginModel,
-		Object:  relaymodel.ChatCompletion,
+		Object:  model.ChatCompletion,
 		Created: time.Now().Unix(),
-		Choices: []*openai.TextResponseChoice{&choice},
-		Usage: relaymodel.Usage{
+		Choices: []*model.TextResponseChoice{&choice},
+		Usage: model.Usage{
 			PromptTokens:     response.PromptEvalCount,
 			CompletionTokens: response.EvalCount,
 			TotalTokens:      response.PromptEvalCount + response.EvalCount,
@@ -162,12 +162,12 @@ func response2OpenAI(meta *meta.Meta, response *ChatResponse) *openai.TextRespon
 	return &fullTextResponse
 }
 
-func streamResponse2OpenAI(meta *meta.Meta, ollamaResponse *ChatResponse) *openai.ChatCompletionsStreamResponse {
-	choice := openai.ChatCompletionsStreamResponseChoice{
+func streamResponse2OpenAI(meta *meta.Meta, ollamaResponse *ChatResponse) *model.ChatCompletionsStreamResponse {
+	choice := model.ChatCompletionsStreamResponseChoice{
 		Text: ollamaResponse.Response,
 	}
 	if ollamaResponse.Message != nil {
-		choice.Delta = relaymodel.Message{
+		choice.Delta = model.Message{
 			Role:      ollamaResponse.Message.Role,
 			Content:   ollamaResponse.Message.Content,
 			ToolCalls: getToolCalls(ollamaResponse),
@@ -176,16 +176,16 @@ func streamResponse2OpenAI(meta *meta.Meta, ollamaResponse *ChatResponse) *opena
 	if ollamaResponse.Done {
 		choice.FinishReason = &ollamaResponse.DoneReason
 	}
-	response := openai.ChatCompletionsStreamResponse{
+	response := model.ChatCompletionsStreamResponse{
 		ID:      openai.ChatCompletionID(),
-		Object:  relaymodel.ChatCompletionChunk,
+		Object:  model.ChatCompletionChunk,
 		Created: time.Now().Unix(),
 		Model:   meta.OriginModel,
-		Choices: []*openai.ChatCompletionsStreamResponseChoice{&choice},
+		Choices: []*model.ChatCompletionsStreamResponseChoice{&choice},
 	}
 
 	if ollamaResponse.EvalCount != 0 {
-		response.Usage = &relaymodel.Usage{
+		response.Usage = &model.Usage{
 			PromptTokens:     ollamaResponse.PromptEvalCount,
 			CompletionTokens: ollamaResponse.EvalCount,
 			TotalTokens:      ollamaResponse.PromptEvalCount + ollamaResponse.EvalCount,
@@ -195,7 +195,7 @@ func streamResponse2OpenAI(meta *meta.Meta, ollamaResponse *ChatResponse) *opena
 	return &response
 }
 
-func StreamHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
+func StreamHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*model.Usage, *model.ErrorWithStatusCode) {
 	if resp.StatusCode != http.StatusOK {
 		return nil, ErrorHandler(resp)
 	}
@@ -204,7 +204,7 @@ func StreamHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relay
 
 	log := middleware.GetLogger(c)
 
-	var usage *relaymodel.Usage
+	var usage *model.Usage
 	scanner := bufio.NewScanner(resp.Body)
 
 	common.SetEventStreamHeaders(c)
@@ -230,7 +230,7 @@ func StreamHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relay
 		}
 
 		if meta.ChannelConfig.SplitThink {
-			openai.StreamSplitThinkModeld(response, thinkSplitter, func(data *openai.ChatCompletionsStreamResponse) {
+			openai.StreamSplitThinkModeld(response, thinkSplitter, func(data *model.ChatCompletionsStreamResponse) {
 				_ = render.ObjectData(c, data)
 			})
 			continue
@@ -271,7 +271,7 @@ func ConvertEmbeddingRequest(meta *meta.Meta, req *http.Request) (string, http.H
 	return http.MethodPost, nil, bytes.NewReader(data), nil
 }
 
-func EmbeddingHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
+func EmbeddingHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*model.Usage, *model.ErrorWithStatusCode) {
 	if resp.StatusCode != http.StatusOK {
 		return nil, ErrorHandler(resp)
 	}
@@ -299,18 +299,18 @@ func EmbeddingHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*re
 	return &fullTextResponse.Usage, nil
 }
 
-func embeddingResponseOllama2OpenAI(meta *meta.Meta, response *EmbeddingResponse) *openai.EmbeddingResponse {
-	openAIEmbeddingResponse := openai.EmbeddingResponse{
+func embeddingResponseOllama2OpenAI(meta *meta.Meta, response *EmbeddingResponse) *model.EmbeddingResponse {
+	openAIEmbeddingResponse := model.EmbeddingResponse{
 		Object: "list",
-		Data:   make([]*openai.EmbeddingResponseItem, 0, len(response.Embeddings)),
+		Data:   make([]*model.EmbeddingResponseItem, 0, len(response.Embeddings)),
 		Model:  meta.OriginModel,
-		Usage: relaymodel.Usage{
+		Usage: model.Usage{
 			PromptTokens: response.PromptEvalCount,
 			TotalTokens:  response.PromptEvalCount,
 		},
 	}
 	for i, embedding := range response.Embeddings {
-		openAIEmbeddingResponse.Data = append(openAIEmbeddingResponse.Data, &openai.EmbeddingResponseItem{
+		openAIEmbeddingResponse.Data = append(openAIEmbeddingResponse.Data, &model.EmbeddingResponseItem{
 			Object:    "embedding",
 			Index:     i,
 			Embedding: embedding,
@@ -319,7 +319,7 @@ func embeddingResponseOllama2OpenAI(meta *meta.Meta, response *EmbeddingResponse
 	return &openAIEmbeddingResponse
 }
 
-func Handler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
+func Handler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*model.Usage, *model.ErrorWithStatusCode) {
 	if resp.StatusCode != http.StatusOK {
 		return nil, ErrorHandler(resp)
 	}

+ 25 - 25
relay/adaptor/openai/adaptor.go

@@ -13,8 +13,8 @@ import (
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/adaptor"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -33,25 +33,25 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 
 	var path string
 	switch meta.Mode {
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		path = "/chat/completions"
-	case relaymode.Completions:
+	case mode.Completions:
 		path = "/completions"
-	case relaymode.Embeddings:
+	case mode.Embeddings:
 		path = "/embeddings"
-	case relaymode.Moderations:
+	case mode.Moderations:
 		path = "/moderations"
-	case relaymode.ImagesGenerations:
+	case mode.ImagesGenerations:
 		path = "/images/generations"
-	case relaymode.Edits:
+	case mode.Edits:
 		path = "/edits"
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		path = "/audio/speech"
-	case relaymode.AudioTranscription:
+	case mode.AudioTranscription:
 		path = "/audio/transcriptions"
-	case relaymode.AudioTranslation:
+	case mode.AudioTranslation:
 		path = "/audio/translations"
-	case relaymode.Rerank:
+	case mode.Rerank:
 		path = "/rerank"
 	default:
 		return "", fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -74,20 +74,20 @@ func ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io
 		return "", nil, nil, errors.New("request is nil")
 	}
 	switch meta.Mode {
-	case relaymode.Moderations:
+	case mode.Moderations:
 		meta.Set(MetaEmbeddingsPatchInputToSlices, true)
 		return ConvertEmbeddingsRequest(meta, req)
-	case relaymode.Embeddings, relaymode.Completions:
+	case mode.Embeddings, mode.Completions:
 		return ConvertEmbeddingsRequest(meta, req)
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		return ConvertTextRequest(meta, req, meta.GetBool(DoNotPatchStreamOptionsIncludeUsageMetaKey))
-	case relaymode.ImagesGenerations:
+	case mode.ImagesGenerations:
 		return ConvertImageRequest(meta, req)
-	case relaymode.AudioTranscription, relaymode.AudioTranslation:
+	case mode.AudioTranscription, mode.AudioTranslation:
 		return ConvertSTTRequest(meta, req)
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		return ConvertTTSRequest(meta, req, "")
-	case relaymode.Rerank:
+	case mode.Rerank:
 		return ConvertRerankRequest(meta, req)
 	default:
 		return "", nil, nil, fmt.Errorf("unsupported mode: %s", meta.Mode)
@@ -96,19 +96,19 @@ func ConvertRequest(meta *meta.Meta, req *http.Request) (string, http.Header, io
 
 func DoResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (usage *relaymodel.Usage, err *relaymodel.ErrorWithStatusCode) {
 	switch meta.Mode {
-	case relaymode.ImagesGenerations:
+	case mode.ImagesGenerations:
 		usage, err = ImageHandler(meta, c, resp)
-	case relaymode.AudioTranscription, relaymode.AudioTranslation:
+	case mode.AudioTranscription, mode.AudioTranslation:
 		usage, err = STTHandler(meta, c, resp)
-	case relaymode.AudioSpeech:
+	case mode.AudioSpeech:
 		usage, err = TTSHandler(meta, c, resp)
-	case relaymode.Rerank:
+	case mode.Rerank:
 		usage, err = RerankHandler(meta, c, resp)
-	case relaymode.Moderations:
+	case mode.Moderations:
 		usage, err = ModerationsHandler(meta, c, resp)
-	case relaymode.Embeddings, relaymode.Completions:
+	case mode.Embeddings, mode.Completions:
 		fallthrough
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		if utils.IsStreamResponse(resp) {
 			usage, err = StreamHandler(meta, c, resp, nil)
 		} else {

+ 33 - 33
relay/adaptor/openai/constants.go

@@ -2,13 +2,13 @@ package openai
 
 import (
 	"github.com/labring/aiproxy/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
 )
 
 var ModelList = []*model.ModelConfig{
 	{
 		Model:       "gpt-3.5-turbo",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerOpenAI,
 		InputPrice:  0.022,
 		OutputPrice: 0.044,
@@ -19,7 +19,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "gpt-3.5-turbo-16k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerOpenAI,
 		InputPrice:  0.022,
 		OutputPrice: 0.044,
@@ -30,12 +30,12 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model: "gpt-3.5-turbo-instruct",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model:       "gpt-4",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerOpenAI,
 		InputPrice:  0.22,
 		OutputPrice: 0.44,
@@ -46,7 +46,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "gpt-4-32k",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerOpenAI,
 		InputPrice:  0.44,
 		OutputPrice: 0.88,
@@ -57,7 +57,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "gpt-4-turbo",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerOpenAI,
 		InputPrice:  0.071,
 		OutputPrice: 0.213,
@@ -68,7 +68,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "gpt-4o",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerOpenAI,
 		InputPrice:  0.01775,
 		OutputPrice: 0.071,
@@ -80,12 +80,12 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model: "chatgpt-4o-latest",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model:       "gpt-4o-mini",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerOpenAI,
 		InputPrice:  0.001065,
 		OutputPrice: 0.00426,
@@ -96,12 +96,12 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model: "gpt-4-vision-preview",
-		Type:  relaymode.ChatCompletions,
+		Type:  mode.ChatCompletions,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model:       "o1-mini",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerOpenAI,
 		InputPrice:  0.0213,
 		OutputPrice: 0.0852,
@@ -111,7 +111,7 @@ var ModelList = []*model.ModelConfig{
 	},
 	{
 		Model:       "o1-preview",
-		Type:        relaymode.ChatCompletions,
+		Type:        mode.ChatCompletions,
 		Owner:       model.ModelOwnerOpenAI,
 		InputPrice:  0.1065,
 		OutputPrice: 0.426,
@@ -122,102 +122,102 @@ var ModelList = []*model.ModelConfig{
 
 	{
 		Model: "text-embedding-ada-002",
-		Type:  relaymode.Embeddings,
+		Type:  mode.Embeddings,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "text-embedding-3-small",
-		Type:  relaymode.Embeddings,
+		Type:  mode.Embeddings,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "text-embedding-3-large",
-		Type:  relaymode.Embeddings,
+		Type:  mode.Embeddings,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "text-curie-001",
-		Type:  relaymode.Completions,
+		Type:  mode.Completions,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "text-babbage-001",
-		Type:  relaymode.Completions,
+		Type:  mode.Completions,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "text-ada-001",
-		Type:  relaymode.Completions,
+		Type:  mode.Completions,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "text-davinci-002",
-		Type:  relaymode.Completions,
+		Type:  mode.Completions,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "text-davinci-003",
-		Type:  relaymode.Completions,
+		Type:  mode.Completions,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "text-moderation-latest",
-		Type:  relaymode.Moderations,
+		Type:  mode.Moderations,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "text-moderation-stable",
-		Type:  relaymode.Moderations,
+		Type:  mode.Moderations,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "text-davinci-edit-001",
-		Type:  relaymode.Edits,
+		Type:  mode.Edits,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "davinci-002",
-		Type:  relaymode.Completions,
+		Type:  mode.Completions,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "babbage-002",
-		Type:  relaymode.Completions,
+		Type:  mode.Completions,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "dall-e-2",
-		Type:  relaymode.ImagesGenerations,
+		Type:  mode.ImagesGenerations,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "dall-e-3",
-		Type:  relaymode.ImagesGenerations,
+		Type:  mode.ImagesGenerations,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "whisper-1",
-		Type:  relaymode.AudioTranscription,
+		Type:  mode.AudioTranscription,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "tts-1",
-		Type:  relaymode.AudioSpeech,
+		Type:  mode.AudioSpeech,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "tts-1-1106",
-		Type:  relaymode.AudioSpeech,
+		Type:  mode.AudioSpeech,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "tts-1-hd",
-		Type:  relaymode.AudioSpeech,
+		Type:  mode.AudioSpeech,
 		Owner: model.ModelOwnerOpenAI,
 	},
 	{
 		Model: "tts-1-hd-1106",
-		Type:  relaymode.AudioSpeech,
+		Type:  mode.AudioSpeech,
 		Owner: model.ModelOwnerOpenAI,
 	},
 }

+ 1 - 1
relay/adaptor/openai/image.go

@@ -55,7 +55,7 @@ func ImageHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*model.
 	if err != nil {
 		return nil, ErrorWrapper(err, "read_response_body_failed", http.StatusInternalServerError)
 	}
-	var imageResponse ImageResponse
+	var imageResponse model.ImageResponse
 	err = sonic.Unmarshal(responseBody, &imageResponse)
 	if err != nil {
 		return nil, ErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError)

+ 6 - 6
relay/adaptor/openai/main.go

@@ -54,7 +54,7 @@ func PutScannerBuffer(buf *[]byte) {
 	scannerBufferPool.Put(buf)
 }
 
-func GetUsageOrChatChoicesResponseFromNode(node *ast.Node) (*model.Usage, []*ChatCompletionsStreamResponseChoice, error) {
+func GetUsageOrChatChoicesResponseFromNode(node *ast.Node) (*model.Usage, []*model.ChatCompletionsStreamResponseChoice, error) {
 	var usage *model.Usage
 	usageNode, err := node.Get("usage").Raw()
 	if err != nil {
@@ -72,7 +72,7 @@ func GetUsageOrChatChoicesResponseFromNode(node *ast.Node) (*model.Usage, []*Cha
 		return usage, nil, nil
 	}
 
-	var choices []*ChatCompletionsStreamResponseChoice
+	var choices []*model.ChatCompletionsStreamResponseChoice
 	choicesNode, err := node.Get("choices").Raw()
 	if err != nil {
 		if !errors.Is(err, ast.ErrNotExist) {
@@ -243,7 +243,7 @@ func StreamSplitThink(data map[string]any, thinkSplitter *splitter.Splitter, ren
 	}
 }
 
-func StreamSplitThinkModeld(data *ChatCompletionsStreamResponse, thinkSplitter *splitter.Splitter, renderCallback func(data *ChatCompletionsStreamResponse)) {
+func StreamSplitThinkModeld(data *model.ChatCompletionsStreamResponse, thinkSplitter *splitter.Splitter, renderCallback func(data *model.ChatCompletionsStreamResponse)) {
 	choices := data.Choices
 	// only support one choice
 	if len(data.Choices) != 1 {
@@ -299,7 +299,7 @@ func SplitThink(data map[string]any) {
 	}
 }
 
-func SplitThinkModeld(data *TextResponse) {
+func SplitThinkModeld(data *model.TextResponse) {
 	choices := data.Choices
 	for _, choice := range choices {
 		content, ok := choice.Message.Content.(string)
@@ -312,7 +312,7 @@ func SplitThinkModeld(data *TextResponse) {
 	}
 }
 
-func GetUsageOrChoicesResponseFromNode(node *ast.Node) (*model.Usage, []*TextResponseChoice, error) {
+func GetUsageOrChoicesResponseFromNode(node *ast.Node) (*model.Usage, []*model.TextResponseChoice, error) {
 	var usage *model.Usage
 	usageNode, err := node.Get("usage").Raw()
 	if err != nil {
@@ -330,7 +330,7 @@ func GetUsageOrChoicesResponseFromNode(node *ast.Node) (*model.Usage, []*TextRes
 		return usage, nil, nil
 	}
 
-	var choices []*TextResponseChoice
+	var choices []*model.TextResponseChoice
 	choicesNode, err := node.Get("choices").Raw()
 	if err != nil {
 		if !errors.Is(err, ast.ErrNotExist) {

+ 0 - 138
relay/adaptor/openai/model.go

@@ -1,139 +1,5 @@
 package openai
 
-import (
-	"github.com/labring/aiproxy/relay/model"
-)
-
-type TextContent struct {
-	Type string `json:"type,omitempty"`
-	Text string `json:"text,omitempty"`
-}
-
-type ImageContent struct {
-	ImageURL *model.ImageURL `json:"image_url,omitempty"`
-	Type     string          `json:"type,omitempty"`
-}
-
-type ChatRequest struct {
-	Model     string           `json:"model"`
-	Messages  []*model.Message `json:"messages"`
-	MaxTokens int              `json:"max_tokens"`
-}
-
-type TextRequest struct {
-	Model     string           `json:"model"`
-	Prompt    string           `json:"prompt"`
-	Messages  []*model.Message `json:"messages"`
-	MaxTokens int              `json:"max_tokens"`
-}
-
-// ImageRequest docs: https://platform.openai.com/docs/api-reference/images/create
-type ImageRequest struct {
-	Model          string `json:"model"`
-	Prompt         string `binding:"required"               json:"prompt"`
-	Size           string `json:"size,omitempty"`
-	Quality        string `json:"quality,omitempty"`
-	ResponseFormat string `json:"response_format,omitempty"`
-	Style          string `json:"style,omitempty"`
-	User           string `json:"user,omitempty"`
-	N              int    `json:"n,omitempty"`
-}
-
-type WhisperJSONResponse struct {
-	Text string `json:"text,omitempty"`
-}
-
-type WhisperVerboseJSONResponse struct {
-	Task     string     `json:"task,omitempty"`
-	Language string     `json:"language,omitempty"`
-	Text     string     `json:"text,omitempty"`
-	Segments []*Segment `json:"segments,omitempty"`
-	Duration float64    `json:"duration,omitempty"`
-}
-
-type Segment struct {
-	Text             string  `json:"text"`
-	Tokens           []int   `json:"tokens"`
-	ID               int     `json:"id"`
-	Seek             int     `json:"seek"`
-	Start            float64 `json:"start"`
-	End              float64 `json:"end"`
-	Temperature      float64 `json:"temperature"`
-	AvgLogprob       float64 `json:"avg_logprob"`
-	CompressionRatio float64 `json:"compression_ratio"`
-	NoSpeechProb     float64 `json:"no_speech_prob"`
-}
-
-type UsageOrResponseText struct {
-	*model.Usage
-	ResponseText string
-}
-
-type SlimTextResponse struct {
-	Choices []*TextResponseChoice `json:"choices"`
-	Usage   model.Usage           `json:"usage"`
-}
-
-type SlimRerankResponse struct {
-	Meta model.RerankMeta `json:"meta"`
-}
-
-type TextResponseChoice struct {
-	FinishReason string        `json:"finish_reason"`
-	Message      model.Message `json:"message"`
-	Index        int           `json:"index"`
-	Text         string        `json:"text,omitempty"`
-}
-
-type TextResponse struct {
-	ID          string                `json:"id"`
-	Model       string                `json:"model,omitempty"`
-	Object      string                `json:"object"`
-	Choices     []*TextResponseChoice `json:"choices"`
-	model.Usage `json:"usage"`
-	Created     int64 `json:"created"`
-}
-
-type EmbeddingResponseItem struct {
-	Object    string    `json:"object"`
-	Embedding []float64 `json:"embedding"`
-	Index     int       `json:"index"`
-}
-
-type EmbeddingResponse struct {
-	Object      string                   `json:"object"`
-	Model       string                   `json:"model"`
-	Data        []*EmbeddingResponseItem `json:"data"`
-	model.Usage `json:"usage"`
-}
-
-type ImageData struct {
-	URL           string `json:"url,omitempty"`
-	B64Json       string `json:"b64_json,omitempty"`
-	RevisedPrompt string `json:"revised_prompt,omitempty"`
-}
-
-type ImageResponse struct {
-	Data    []*ImageData `json:"data"`
-	Created int64        `json:"created"`
-}
-
-type ChatCompletionsStreamResponseChoice struct {
-	FinishReason *string       `json:"finish_reason,omitempty"`
-	Delta        model.Message `json:"delta"`
-	Index        int           `json:"index"`
-	Text         string        `json:"text,omitempty"`
-}
-
-type ChatCompletionsStreamResponse struct {
-	Usage   *model.Usage                           `json:"usage,omitempty"`
-	ID      string                                 `json:"id"`
-	Object  string                                 `json:"object"`
-	Model   string                                 `json:"model"`
-	Choices []*ChatCompletionsStreamResponseChoice `json:"choices"`
-	Created int64                                  `json:"created"`
-}
-
 type SubscriptionResponse struct {
 	Object             string  `json:"object"`
 	HasPaymentMethod   bool    `json:"has_payment_method"`
@@ -148,7 +14,3 @@ type UsageResponse struct {
 	// DailyCosts []OpenAIUsageDailyCost `json:"daily_costs"`
 	TotalUsage float64 `json:"total_usage"` // unit: 0.01 dollar
 }
-
-type ErrorResp struct {
-	Error model.Error `json:"error"`
-}

+ 1 - 1
relay/adaptor/openai/rerank.go

@@ -45,7 +45,7 @@ func RerankHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*model
 	if err != nil {
 		return nil, ErrorWrapper(err, "read_response_body_failed", http.StatusInternalServerError)
 	}
-	var rerankResponse SlimRerankResponse
+	var rerankResponse model.SlimRerankResponse
 	err = sonic.Unmarshal(responseBody, &rerankResponse)
 	if err != nil {
 		return nil, ErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError)

+ 2 - 2
relay/adaptor/openai/stt.go

@@ -137,7 +137,7 @@ func getTextFromVTT(body []byte) (string, error) {
 }
 
 func getTextFromVerboseJSON(body []byte) (string, error) {
-	var whisperResponse WhisperVerboseJSONResponse
+	var whisperResponse model.SttVerboseJSONResponse
 	if err := sonic.Unmarshal(body, &whisperResponse); err != nil {
 		return "", fmt.Errorf("unmarshal_response_body_failed err :%w", err)
 	}
@@ -170,7 +170,7 @@ func getTextFromText(body []byte) string {
 }
 
 func getTextFromJSON(body []byte) (string, error) {
-	var whisperResponse WhisperJSONResponse
+	var whisperResponse model.SttJSONResponse
 	if err := sonic.Unmarshal(body, &whisperResponse); err != nil {
 		return "", fmt.Errorf("unmarshal_response_body_failed err :%w", err)
 	}

+ 3 - 3
relay/adaptor/openai/tts.go

@@ -11,7 +11,7 @@ import (
 	"github.com/labring/aiproxy/common"
 	"github.com/labring/aiproxy/middleware"
 	"github.com/labring/aiproxy/relay/meta"
-	relaymodel "github.com/labring/aiproxy/relay/model"
+	model "github.com/labring/aiproxy/relay/model"
 )
 
 func ConvertTTSRequest(meta *meta.Meta, req *http.Request, defaultVoice string) (string, http.Header, io.Reader, error) {
@@ -54,7 +54,7 @@ func ConvertTTSRequest(meta *meta.Meta, req *http.Request, defaultVoice string)
 	return http.MethodPost, nil, bytes.NewReader(jsonData), nil
 }
 
-func TTSHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymodel.Usage, *relaymodel.ErrorWithStatusCode) {
+func TTSHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*model.Usage, *model.ErrorWithStatusCode) {
 	if resp.StatusCode != http.StatusOK {
 		return nil, ErrorHanlder(resp)
 	}
@@ -71,7 +71,7 @@ func TTSHandler(meta *meta.Meta, c *gin.Context, resp *http.Response) (*relaymod
 	if err != nil {
 		log.Warnf("write response body failed: %v", err)
 	}
-	return &relaymodel.Usage{
+	return &model.Usage{
 		PromptTokens:     meta.InputTokens,
 		CompletionTokens: 0,
 		TotalTokens:      meta.InputTokens,

+ 12 - 12
relay/adaptor/openai/util.go

@@ -3,13 +3,13 @@ package openai
 import (
 	"github.com/labring/aiproxy/middleware"
 	"github.com/labring/aiproxy/relay/meta"
-	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
+	"github.com/labring/aiproxy/relay/mode"
+	model "github.com/labring/aiproxy/relay/model"
 )
 
-func ErrorWrapper(err error, code any, statusCode int) *relaymodel.ErrorWithStatusCode {
-	return &relaymodel.ErrorWithStatusCode{
-		Error: relaymodel.Error{
+func ErrorWrapper(err error, code any, statusCode int) *model.ErrorWithStatusCode {
+	return &model.ErrorWithStatusCode{
+		Error: model.Error{
 			Message: err.Error(),
 			Type:    middleware.ErrorTypeAIPROXY,
 			Code:    code,
@@ -18,9 +18,9 @@ func ErrorWrapper(err error, code any, statusCode int) *relaymodel.ErrorWithStat
 	}
 }
 
-func ErrorWrapperWithMessage(message string, code any, statusCode int) *relaymodel.ErrorWithStatusCode {
-	return &relaymodel.ErrorWithStatusCode{
-		Error: relaymodel.Error{
+func ErrorWrapperWithMessage(message string, code any, statusCode int) *model.ErrorWithStatusCode {
+	return &model.ErrorWithStatusCode{
+		Error: model.Error{
 			Message: message,
 			Type:    middleware.ErrorTypeAIPROXY,
 			Code:    code,
@@ -29,13 +29,13 @@ func ErrorWrapperWithMessage(message string, code any, statusCode int) *relaymod
 	}
 }
 
-func GetPromptTokens(meta *meta.Meta, textRequest *relaymodel.GeneralOpenAIRequest) int {
+func GetPromptTokens(meta *meta.Meta, textRequest *model.GeneralOpenAIRequest) int {
 	switch meta.Mode {
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		return CountTokenMessages(textRequest.Messages, textRequest.Model)
-	case relaymode.Completions:
+	case mode.Completions:
 		return CountTokenInput(textRequest.Prompt, textRequest.Model)
-	case relaymode.Moderations:
+	case mode.Moderations:
 		return CountTokenInput(textRequest.Input, textRequest.Model)
 	}
 	return 0

+ 2 - 2
relay/adaptor/openrouter/adaptor.go

@@ -9,8 +9,8 @@ import (
 	"github.com/labring/aiproxy/model"
 	"github.com/labring/aiproxy/relay/adaptor/openai"
 	"github.com/labring/aiproxy/relay/meta"
+	"github.com/labring/aiproxy/relay/mode"
 	relaymodel "github.com/labring/aiproxy/relay/model"
-	"github.com/labring/aiproxy/relay/relaymode"
 	"github.com/labring/aiproxy/relay/utils"
 )
 
@@ -90,7 +90,7 @@ func handlerPreHandler(_ *meta.Meta, node *ast.Node) error {
 
 func (a *Adaptor) DoResponse(meta *meta.Meta, c *gin.Context, resp *http.Response) (usage *relaymodel.Usage, err *relaymodel.ErrorWithStatusCode) {
 	switch meta.Mode {
-	case relaymode.ChatCompletions:
+	case mode.ChatCompletions:
 		if utils.IsStreamResponse(resp) {
 			usage, err = openai.StreamHandler(meta, c, resp, streamPreHandler)
 		} else {

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů