refactor(api): standardize DTOs and update swagger

Decouple API contract from internal models by introducing dedicated DTOs for requests and responses.
- Add Response DTOs for all resources (API Keys, Bindings, Models, Namespaces, etc.)
- Update Swagger annotations to use DTOs with field examples instead of internal models
- Refactor handlers to bind and return DTO structures
- Consolidate request/response definitions in the dto package
This commit is contained in:
zenfun
2026-01-10 02:05:55 +08:00
parent f52c7acbe6
commit 2098bc4abe
20 changed files with 4156 additions and 3760 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -489,8 +489,8 @@ func (h *AdminHandler) IssueChildKeyForMaster(c *gin.Context) {
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by group/scopes/namespaces/status"
// @Success 200 {object} ResponseEnvelope{data=[]TokenView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters/{id}/keys [get]
func (h *AdminHandler) ListKeysForMaster(c *gin.Context) {
masterID, ok := parseUintParam(c, "id")
@@ -523,10 +523,10 @@ func (h *AdminHandler) ListKeysForMaster(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "Master ID"
// @Param key_id path int true "Token ID"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=dto.DeleteResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters/{id}/keys/{key_id} [delete]
func (h *AdminHandler) DeleteKeyForMaster(c *gin.Context) {
masterID, ok := parseUintParam(c, "id")

View File

@@ -17,7 +17,7 @@ import (
// @Produce json
// @Security AdminAuth
// @Param key body dto.APIKeyDTO true "API key payload"
// @Success 201 {object} ResponseEnvelope{data=model.APIKey}
// @Success 201 {object} ResponseEnvelope{data=dto.APIKeyResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/api-keys [post]
@@ -100,7 +100,7 @@ func (h *Handler) CreateAPIKey(c *gin.Context) {
// @Param limit query int false "limit (default 50, max 200)"
// @Param group_id query int false "filter by group_id"
// @Param status query string false "filter by status (active, suspended, auto_disabled, manual_disabled)"
// @Success 200 {object} ResponseEnvelope{data=[]model.APIKey}
// @Success 200 {object} ResponseEnvelope{data=[]dto.APIKeyResponse}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/api-keys [get]
func (h *Handler) ListAPIKeys(c *gin.Context) {
@@ -128,7 +128,7 @@ func (h *Handler) ListAPIKeys(c *gin.Context) {
// @Produce json
// @Security AdminAuth
// @Param id path int true "APIKey ID"
// @Success 200 {object} ResponseEnvelope{data=model.APIKey}
// @Success 200 {object} ResponseEnvelope{data=dto.APIKeyResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
@@ -155,7 +155,7 @@ func (h *Handler) GetAPIKey(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "APIKey ID"
// @Param key body dto.APIKeyDTO true "API key payload"
// @Success 200 {object} ResponseEnvelope{data=model.APIKey}
// @Success 200 {object} ResponseEnvelope{data=dto.APIKeyResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}

View File

@@ -19,7 +19,7 @@ import (
// @Produce json
// @Security AdminAuth
// @Param binding body dto.BindingDTO true "Binding Info"
// @Success 201 {object} ResponseEnvelope{data=model.Binding}
// @Success 201 {object} ResponseEnvelope{data=dto.BindingResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/bindings [post]
@@ -84,7 +84,7 @@ func (h *Handler) CreateBinding(c *gin.Context) {
// @Param page query int false "page (1-based)"
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by namespace/public_model"
// @Success 200 {object} ResponseEnvelope{data=[]model.Binding}
// @Success 200 {object} ResponseEnvelope{data=[]dto.BindingResponse}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/bindings [get]
func (h *Handler) ListBindings(c *gin.Context) {
@@ -109,7 +109,7 @@ func (h *Handler) ListBindings(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "Binding ID"
// @Param binding body dto.BindingDTO true "Binding Info"
// @Success 200 {object} ResponseEnvelope{data=model.Binding}
// @Success 200 {object} ResponseEnvelope{data=dto.BindingResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
@@ -180,7 +180,7 @@ func (h *Handler) UpdateBinding(c *gin.Context) {
// @Produce json
// @Security AdminAuth
// @Param id path int true "Binding ID"
// @Success 200 {object} ResponseEnvelope{data=model.Binding}
// @Success 200 {object} ResponseEnvelope{data=dto.BindingResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}

View File

@@ -62,7 +62,7 @@ func (h *Handler) logBaseQuery() *gorm.DB {
// @Produce json
// @Security AdminAuth
// @Param model body dto.ModelDTO true "Model Info"
// @Success 201 {object} ResponseEnvelope{data=model.Model}
// @Success 201 {object} ResponseEnvelope{data=dto.ModelResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/models [post]
@@ -123,7 +123,7 @@ func (h *Handler) CreateModel(c *gin.Context) {
// @Param page query int false "page (1-based)"
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by name/kind"
// @Success 200 {object} ResponseEnvelope{data=[]model.Model}
// @Success 200 {object} ResponseEnvelope{data=[]dto.ModelResponse}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/models [get]
func (h *Handler) ListModels(c *gin.Context) {
@@ -148,7 +148,7 @@ func (h *Handler) ListModels(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "Model ID"
// @Param model body dto.ModelDTO true "Model Info"
// @Success 200 {object} ResponseEnvelope{data=model.Model}
// @Success 200 {object} ResponseEnvelope{data=dto.ModelResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
@@ -277,7 +277,7 @@ func (h *Handler) SyncSnapshot(c *gin.Context) {
// @Tags system
// @Accept json
// @Produce json
// @Param log body model.LogRecord true "Log Record"
// @Param log body dto.LogRecordRequest true "Log Record"
// @Success 202 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Router /logs [post]

View File

@@ -3,17 +3,24 @@ package api
import (
"net/http"
"github.com/ez-api/ez-api/internal/dto"
"github.com/ez-api/ez-api/internal/service"
"github.com/gin-gonic/gin"
)
// Ensure dto types are referenced for swagger generation
var (
_ dto.LogWebhookConfigResponse
_ dto.UpdateLogWebhookConfigRequest
)
// GetLogWebhookConfig godoc
// @Summary Get log webhook config
// @Description Returns current webhook notification config
// @Tags admin
// @Produce json
// @Security AdminAuth
// @Success 200 {object} ResponseEnvelope{data=service.LogWebhookConfig}
// @Success 200 {object} ResponseEnvelope{data=dto.LogWebhookConfigResponse}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/logs/webhook [get]
func (h *Handler) GetLogWebhookConfig(c *gin.Context) {
@@ -36,8 +43,8 @@ func (h *Handler) GetLogWebhookConfig(c *gin.Context) {
// @Accept json
// @Produce json
// @Security AdminAuth
// @Param request body service.LogWebhookConfig true "Webhook config"
// @Success 200 {object} ResponseEnvelope{data=service.LogWebhookConfig}
// @Param request body dto.UpdateLogWebhookConfigRequest true "Webhook config"
// @Success 200 {object} ResponseEnvelope{data=dto.LogWebhookConfigResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/logs/webhook [put]

View File

@@ -22,7 +22,7 @@ func NewModelRegistryHandler(reg *service.ModelRegistryService) *ModelRegistryHa
// @Tags admin
// @Produce json
// @Security AdminAuth
// @Success 200 {object} ResponseEnvelope{data=service.ModelRegistryStatus}
// @Success 200 {object} ResponseEnvelope{data=dto.ModelRegistryStatusResponse}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/model-registry/status [get]
func (h *ModelRegistryHandler) GetStatus(c *gin.Context) {
@@ -50,7 +50,7 @@ type refreshModelRegistryRequest struct {
// @Produce json
// @Security AdminAuth
// @Param body body refreshModelRegistryRequest false "optional override ref"
// @Success 200 {object} ResponseEnvelope{data=service.ModelRegistryCheckResult}
// @Success 200 {object} ResponseEnvelope{data=dto.ModelRegistryCheckResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/model-registry/check [post]

View File

@@ -4,16 +4,11 @@ import (
"net/http"
"strings"
"github.com/ez-api/ez-api/internal/dto"
"github.com/ez-api/ez-api/internal/model"
"github.com/gin-gonic/gin"
)
type NamespaceRequest struct {
Name string `json:"name"`
Status string `json:"status"`
Description string `json:"description"`
}
// CreateNamespace godoc
// @Summary Create namespace
// @Description Create a namespace for bindings
@@ -21,13 +16,13 @@ type NamespaceRequest struct {
// @Accept json
// @Produce json
// @Security AdminAuth
// @Param namespace body NamespaceRequest true "Namespace payload"
// @Success 201 {object} ResponseEnvelope{data=model.Namespace}
// @Param namespace body dto.NamespaceDTO true "Namespace payload"
// @Success 201 {object} ResponseEnvelope{data=dto.NamespaceResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/namespaces [post]
func (h *Handler) CreateNamespace(c *gin.Context) {
var req NamespaceRequest
var req dto.NamespaceDTO
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
@@ -64,7 +59,7 @@ func (h *Handler) CreateNamespace(c *gin.Context) {
// @Param page query int false "page (1-based)"
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by name/description"
// @Success 200 {object} ResponseEnvelope{data=[]model.Namespace}
// @Success 200 {object} ResponseEnvelope{data=[]dto.NamespaceResponse}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/namespaces [get]
func (h *Handler) ListNamespaces(c *gin.Context) {
@@ -87,7 +82,7 @@ func (h *Handler) ListNamespaces(c *gin.Context) {
// @Produce json
// @Security AdminAuth
// @Param id path int true "Namespace ID"
// @Success 200 {object} ResponseEnvelope{data=model.Namespace}
// @Success 200 {object} ResponseEnvelope{data=dto.NamespaceResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
@@ -118,9 +113,9 @@ type UpdateNamespaceRequest struct {
// @Accept json
// @Produce json
// @Security AdminAuth
// @Param id path int true "Namespace ID"
// @Param id path int true "Namespace ID"
// @Param namespace body UpdateNamespaceRequest true "Update payload"
// @Success 200 {object} ResponseEnvelope{data=model.Namespace}
// @Success 200 {object} ResponseEnvelope{data=dto.NamespaceResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}

View File

@@ -19,7 +19,7 @@ import (
// @Produce json
// @Security AdminAuth
// @Param group body dto.ProviderGroupDTO true "Provider group payload"
// @Success 201 {object} ResponseEnvelope{data=model.ProviderGroup}
// @Success 201 {object} ResponseEnvelope{data=dto.ProviderGroupResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/provider-groups [post]
@@ -78,7 +78,7 @@ func (h *Handler) CreateProviderGroup(c *gin.Context) {
// @Param page query int false "page (1-based)"
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by name/type"
// @Success 200 {object} ResponseEnvelope{data=[]model.ProviderGroup}
// @Success 200 {object} ResponseEnvelope{data=[]dto.ProviderGroupResponse}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/provider-groups [get]
func (h *Handler) ListProviderGroups(c *gin.Context) {
@@ -101,7 +101,7 @@ func (h *Handler) ListProviderGroups(c *gin.Context) {
// @Produce json
// @Security AdminAuth
// @Param id path int true "ProviderGroup ID"
// @Success 200 {object} ResponseEnvelope{data=model.ProviderGroup}
// @Success 200 {object} ResponseEnvelope{data=dto.ProviderGroupResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
@@ -128,7 +128,7 @@ func (h *Handler) GetProviderGroup(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "ProviderGroup ID"
// @Param group body dto.ProviderGroupDTO true "Provider group payload"
// @Success 200 {object} ResponseEnvelope{data=model.ProviderGroup}
// @Success 200 {object} ResponseEnvelope{data=dto.ProviderGroupResponse}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}

View File

@@ -2,18 +2,43 @@ package dto
import "time"
// APIKeyDTO defines inbound payload for API key creation/update.
type APIKeyDTO struct {
GroupID uint `json:"group_id"`
APIKey string `json:"api_key"`
AccessToken string `json:"access_token,omitempty"`
RefreshToken string `json:"refresh_token,omitempty"`
ExpiresAt time.Time `json:"expires_at,omitempty"`
AccountID string `json:"account_id,omitempty"`
ProjectID string `json:"project_id,omitempty"`
Weight int `json:"weight,omitempty"`
Status string `json:"status"`
AutoBan *bool `json:"auto_ban,omitempty"`
BanReason string `json:"ban_reason,omitempty"`
BanUntil time.Time `json:"ban_until,omitempty"`
// APIKeyResponse represents an API key in API responses.
// @Description API key response
type APIKeyResponse struct {
ID uint `json:"id" example:"1"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
GroupID uint `json:"group_id" example:"1"`
APIKey string `json:"api_key" example:"sk-xxx..."`
AccessToken string `json:"access_token,omitempty"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
AccountID string `json:"account_id,omitempty"`
ProjectID string `json:"project_id,omitempty"`
Weight int `json:"weight" example:"1"`
Status string `json:"status" example:"active"`
AutoBan bool `json:"auto_ban" example:"true"`
BanReason string `json:"ban_reason,omitempty"`
BanUntil *time.Time `json:"ban_until,omitempty"`
TotalRequests int64 `json:"total_requests" example:"1000"`
SuccessRequests int64 `json:"success_requests" example:"950"`
FailureRequests int64 `json:"failure_requests" example:"50"`
SuccessRate float64 `json:"success_rate" example:"0.95"`
FailureRate float64 `json:"failure_rate" example:"0.05"`
}
// APIKeyDTO defines inbound payload for API key creation/update.
// @Description API key create/update request
type APIKeyDTO struct {
GroupID uint `json:"group_id" example:"1"`
APIKey string `json:"api_key" example:"sk-xxx..."`
AccessToken string `json:"access_token,omitempty"`
RefreshToken string `json:"refresh_token,omitempty"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
AccountID string `json:"account_id,omitempty"`
ProjectID string `json:"project_id,omitempty"`
Weight int `json:"weight,omitempty" example:"1"`
Status string `json:"status" example:"active"`
AutoBan *bool `json:"auto_ban,omitempty" example:"true"`
BanReason string `json:"ban_reason,omitempty"`
BanUntil *time.Time `json:"ban_until,omitempty"`
}

View File

@@ -1,13 +1,31 @@
package dto
import "time"
// BindingResponse represents a binding in API responses.
// @Description Binding response
type BindingResponse struct {
ID uint `json:"id" example:"1"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Namespace string `json:"namespace" example:"default"`
PublicModel string `json:"public_model" example:"gpt-4"`
GroupID uint `json:"group_id" example:"1"`
Weight int `json:"weight" example:"1"`
SelectorType string `json:"selector_type" example:"exact"`
SelectorValue string `json:"selector_value" example:"gpt-4-turbo"`
Status string `json:"status" example:"active"`
}
// BindingDTO defines inbound payload for binding creation/update.
// It maps "(namespace, public_model)" to a ProviderGroup and an upstream selector.
// @Description Binding create/update request
type BindingDTO struct {
Namespace string `json:"namespace"`
PublicModel string `json:"public_model"`
GroupID uint `json:"group_id"`
Weight int `json:"weight"`
SelectorType string `json:"selector_type"`
SelectorValue string `json:"selector_value"`
Status string `json:"status"`
Namespace string `json:"namespace" example:"default"`
PublicModel string `json:"public_model" example:"gpt-4"`
GroupID uint `json:"group_id" example:"1"`
Weight int `json:"weight" example:"1"`
SelectorType string `json:"selector_type" example:"exact"`
SelectorValue string `json:"selector_value" example:"gpt-4-turbo"`
Status string `json:"status" example:"active"`
}

7
internal/dto/common.go Normal file
View File

@@ -0,0 +1,7 @@
package dto
// DeleteResponse represents a successful delete operation response.
// @Description Delete operation response
type DeleteResponse struct {
Status string `json:"status" example:"deleted"`
}

View File

@@ -0,0 +1,24 @@
package dto
// LogRecordRequest defines the request body for log ingestion.
// @Description Log record ingest request
type LogRecordRequest struct {
Group string `json:"group" example:"default"`
MasterID uint `json:"master_id" example:"1"`
KeyID uint `json:"key_id" example:"1"`
ModelName string `json:"model" example:"gpt-4"`
ProviderID uint `json:"provider_id" example:"1"`
ProviderType string `json:"provider_type" example:"openai"`
ProviderName string `json:"provider_name" example:"openai-prod"`
StatusCode int `json:"status_code" example:"200"`
LatencyMs int64 `json:"latency_ms" example:"150"`
TokensIn int64 `json:"tokens_in" example:"100"`
TokensOut int64 `json:"tokens_out" example:"50"`
ErrorMessage string `json:"error_message,omitempty"`
ClientIP string `json:"client_ip" example:"192.168.1.1"`
RequestSize int64 `json:"request_size" example:"1024"`
ResponseSize int64 `json:"response_size" example:"2048"`
AuditReason string `json:"audit_reason,omitempty"`
RequestBody string `json:"request_body,omitempty"`
ResponseBody string `json:"response_body,omitempty"`
}

View File

@@ -0,0 +1,25 @@
package dto
// LogWebhookConfigResponse represents the log webhook configuration in API responses.
// @Description Log webhook configuration response
type LogWebhookConfigResponse struct {
Enabled bool `json:"enabled" example:"true"`
URL string `json:"url" example:"https://webhook.example.com/alerts"`
Secret string `json:"secret" example:"webhook-secret-key"`
Threshold int `json:"threshold" example:"10"`
WindowSeconds int `json:"window_seconds" example:"60"`
CooldownSeconds int `json:"cooldown_seconds" example:"300"`
StatusCodeThreshold int `json:"status_code_threshold" example:"500"`
}
// UpdateLogWebhookConfigRequest defines the request body for updating log webhook config.
// @Description Update log webhook configuration request
type UpdateLogWebhookConfigRequest struct {
Enabled bool `json:"enabled" example:"true"`
URL string `json:"url" example:"https://webhook.example.com/alerts"`
Secret string `json:"secret" example:"webhook-secret-key"`
Threshold int `json:"threshold" example:"10"`
WindowSeconds int `json:"window_seconds" example:"60"`
CooldownSeconds int `json:"cooldown_seconds" example:"300"`
StatusCodeThreshold int `json:"status_code_threshold" example:"500"`
}

View File

@@ -1,14 +1,34 @@
package dto
// ModelDTO is used for create/update of model capabilities.
type ModelDTO struct {
Name string `json:"name"`
Kind string `json:"kind"`
ContextWindow int `json:"context_window"`
CostPerToken float64 `json:"cost_per_token"`
SupportsVision bool `json:"supports_vision"`
SupportsFunctions bool `json:"supports_functions"`
SupportsToolChoice bool `json:"supports_tool_choice"`
SupportsFIM bool `json:"supports_fim"`
MaxOutputTokens int `json:"max_output_tokens"`
import "time"
// ModelResponse represents a model in API responses.
// @Description Model response
type ModelResponse struct {
ID uint `json:"id" example:"1"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Name string `json:"name" example:"gpt-4"`
Kind string `json:"kind" example:"chat"`
ContextWindow int `json:"context_window" example:"128000"`
CostPerToken float64 `json:"cost_per_token" example:"0.00003"`
SupportsVision bool `json:"supports_vision" example:"true"`
SupportsFunctions bool `json:"supports_functions" example:"true"`
SupportsToolChoice bool `json:"supports_tool_choice" example:"true"`
SupportsFIM bool `json:"supports_fim" example:"false"`
MaxOutputTokens int `json:"max_output_tokens" example:"4096"`
}
// ModelDTO is used for create/update of model capabilities.
// @Description Model create/update request
type ModelDTO struct {
Name string `json:"name" example:"gpt-4"`
Kind string `json:"kind" example:"chat"`
ContextWindow int `json:"context_window" example:"128000"`
CostPerToken float64 `json:"cost_per_token" example:"0.00003"`
SupportsVision bool `json:"supports_vision" example:"true"`
SupportsFunctions bool `json:"supports_functions" example:"true"`
SupportsToolChoice bool `json:"supports_tool_choice" example:"true"`
SupportsFIM bool `json:"supports_fim" example:"false"`
MaxOutputTokens int `json:"max_output_tokens" example:"4096"`
}

View File

@@ -0,0 +1,32 @@
package dto
// ModelRegistryStatusResponse represents the model registry status in API responses.
// @Description Model registry status response
type ModelRegistryStatusResponse struct {
Enabled bool `json:"enabled" example:"true"`
ModelsDevRef string `json:"models_dev_ref" example:"main"`
ModelsDevURL string `json:"models_dev_url" example:"https://models.dev/v1/models.json"`
LastRefreshAt int64 `json:"last_refresh_at,omitempty" example:"1704067200"`
LastError string `json:"last_error,omitempty"`
RedisMeta map[string]string `json:"redis_meta,omitempty"`
CacheCurrent *ModelCacheFile `json:"cache_current,omitempty"`
CachePrev *ModelCacheFile `json:"cache_prev,omitempty"`
}
// ModelCacheFile represents a cached model registry file.
// @Description Cached model registry file
type ModelCacheFile struct {
Version string `json:"version,omitempty"`
Timestamp int64 `json:"timestamp,omitempty"`
}
// ModelRegistryCheckResponse represents the result of checking model registry upstream.
// @Description Model registry check result
type ModelRegistryCheckResponse struct {
Enabled bool `json:"enabled" example:"true"`
UpstreamRef string `json:"upstream_ref" example:"main"`
CurrentVersion string `json:"current_version,omitempty" example:"abc123"`
LatestVersion string `json:"latest_version,omitempty" example:"def456"`
NeedsRefresh bool `json:"needs_refresh" example:"true"`
CurrentUpstreamRef string `json:"current_upstream_ref,omitempty" example:"main"`
}

22
internal/dto/namespace.go Normal file
View File

@@ -0,0 +1,22 @@
package dto
import "time"
// NamespaceResponse represents a namespace in API responses.
// @Description Namespace response
type NamespaceResponse struct {
ID uint `json:"id" example:"1"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Name string `json:"name" example:"default"`
Status string `json:"status" example:"active"`
Description string `json:"description,omitempty" example:"Default namespace"`
}
// NamespaceDTO defines inbound payload for namespace creation/update.
// @Description Namespace create/update request
type NamespaceDTO struct {
Name string `json:"name" example:"default"`
Status string `json:"status" example:"active"`
Description string `json:"description,omitempty" example:"Default namespace"`
}

View File

@@ -1,14 +1,39 @@
package dto
import "time"
// ProviderGroupResponse represents a provider group in API responses.
// @Description Provider group response
type ProviderGroupResponse struct {
ID uint `json:"id" example:"1"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Name string `json:"name" example:"openai-prod"`
Type string `json:"type" example:"openai"`
BaseURL string `json:"base_url" example:"https://api.openai.com"`
GoogleProject string `json:"google_project,omitempty"`
GoogleLocation string `json:"google_location,omitempty"`
StaticHeaders string `json:"static_headers,omitempty"`
HeadersProfile string `json:"headers_profile,omitempty"`
Models string `json:"models" example:"gpt-4,gpt-3.5-turbo"`
Status string `json:"status" example:"active"`
TotalRequests int64 `json:"total_requests" example:"1000"`
SuccessRequests int64 `json:"success_requests" example:"950"`
FailureRequests int64 `json:"failure_requests" example:"50"`
SuccessRate float64 `json:"success_rate" example:"0.95"`
FailureRate float64 `json:"failure_rate" example:"0.05"`
}
// ProviderGroupDTO defines inbound payload for provider group creation/update.
// @Description Provider group create/update request
type ProviderGroupDTO struct {
Name string `json:"name"`
Type string `json:"type"`
BaseURL string `json:"base_url"`
Name string `json:"name" example:"openai-prod"`
Type string `json:"type" example:"openai"`
BaseURL string `json:"base_url" example:"https://api.openai.com"`
GoogleProject string `json:"google_project,omitempty"`
GoogleLocation string `json:"google_location,omitempty"`
StaticHeaders string `json:"static_headers,omitempty"`
HeadersProfile string `json:"headers_profile,omitempty"`
Models []string `json:"models"`
Status string `json:"status"`
Models []string `json:"models" example:"gpt-4,gpt-3.5-turbo"`
Status string `json:"status" example:"active"`
}