docs(api): 补全 OpenAPI 注释与生成文档
为接口、模型与脚本补齐 Swagger/OpenAPI 注释,生成最新文档,并增加一键生成与查看入口。
This commit is contained in:
@@ -16,6 +16,13 @@ import (
|
||||
"github.com/easyai/easyai-ai-gateway/apps/api/internal/store"
|
||||
)
|
||||
|
||||
// health godoc
|
||||
// @Summary 健康检查
|
||||
// @Description 返回服务进程、运行环境和身份模式,供负载均衡或人工排障使用。
|
||||
// @Tags system
|
||||
// @Produce json
|
||||
// @Success 200 {object} HealthResponse
|
||||
// @Router /healthz [get]
|
||||
func (s *Server) health(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"ok": true,
|
||||
@@ -25,6 +32,14 @@ func (s *Server) health(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
// ready godoc
|
||||
// @Summary 就绪检查
|
||||
// @Description 检查 Postgres 是否可用;数据库不可用时返回 503。
|
||||
// @Tags system
|
||||
// @Produce json
|
||||
// @Success 200 {object} ReadyResponse
|
||||
// @Failure 503 {object} ErrorEnvelope
|
||||
// @Router /readyz [get]
|
||||
func (s *Server) ready(w http.ResponseWriter, r *http.Request) {
|
||||
if err := s.store.Ping(r.Context()); err != nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "postgres unavailable")
|
||||
@@ -33,11 +48,33 @@ func (s *Server) ready(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"ok": true})
|
||||
}
|
||||
|
||||
// me godoc
|
||||
// @Summary 获取当前用户
|
||||
// @Description 返回鉴权中解析出的用户、租户、用户组和 API Key 上下文。
|
||||
// @Tags auth
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} auth.User
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Router /api/v1/me [get]
|
||||
func (s *Server) me(w http.ResponseWriter, r *http.Request) {
|
||||
user, _ := auth.UserFromContext(r.Context())
|
||||
writeJSON(w, http.StatusOK, user)
|
||||
}
|
||||
|
||||
// register godoc
|
||||
// @Summary 本地注册
|
||||
// @Description 在 standalone 或 hybrid 身份模式下创建本地用户,并返回 24 小时 JWT。
|
||||
// @Tags auth
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param input body store.LocalRegisterInput true "注册请求,password 至少 8 位,invitationCode 取决于部署策略"
|
||||
// @Success 201 {object} AuthResponse
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 409 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/v1/auth/register [post]
|
||||
func (s *Server) register(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.localIdentityEnabled() {
|
||||
writeError(w, http.StatusForbidden, "local registration is disabled")
|
||||
@@ -69,6 +106,19 @@ func (s *Server) register(w http.ResponseWriter, r *http.Request) {
|
||||
s.writeAuthResponse(w, http.StatusCreated, user)
|
||||
}
|
||||
|
||||
// login godoc
|
||||
// @Summary 本地登录
|
||||
// @Description 使用用户名或邮箱登录本地账号,并返回 24 小时 JWT。
|
||||
// @Tags auth
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param input body store.LocalLoginInput true "登录请求,account 可为用户名或邮箱"
|
||||
// @Success 200 {object} AuthResponse
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/v1/auth/login [post]
|
||||
func (s *Server) login(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.localIdentityEnabled() {
|
||||
writeError(w, http.StatusForbidden, "local login is disabled")
|
||||
@@ -136,6 +186,17 @@ func authUserFromGatewayUser(user store.GatewayUser) *auth.User {
|
||||
}
|
||||
}
|
||||
|
||||
// listPlatforms godoc
|
||||
// @Summary 列出平台
|
||||
// @Description 管理端返回所有接入平台及其优先级、定价和运行策略摘要。
|
||||
// @Tags platforms
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} PlatformListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/platforms [get]
|
||||
func (s *Server) listPlatforms(w http.ResponseWriter, r *http.Request) {
|
||||
platforms, err := s.store.ListPlatforms(r.Context())
|
||||
if err != nil {
|
||||
@@ -146,6 +207,16 @@ func (s *Server) listPlatforms(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": platforms})
|
||||
}
|
||||
|
||||
// listPlayablePlatforms godoc
|
||||
// @Summary 列出可用平台
|
||||
// @Description 按当前用户可访问模型过滤平台,仅返回启用且存在可访问模型的平台。
|
||||
// @Tags playground
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} PlatformListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/v1/platforms [get]
|
||||
func (s *Server) listPlayablePlatforms(w http.ResponseWriter, r *http.Request) {
|
||||
user, _ := auth.UserFromContext(r.Context())
|
||||
models, err := s.store.ListAccessiblePlatformModels(r.Context(), user)
|
||||
@@ -173,6 +244,20 @@ func (s *Server) listPlayablePlatforms(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": filtered})
|
||||
}
|
||||
|
||||
// createPlatform godoc
|
||||
// @Summary 创建平台
|
||||
// @Description 新增模型供应商平台配置;credentials 会被服务端保存并在返回值中脱敏。
|
||||
// @Tags platforms
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param input body store.CreatePlatformInput true "平台配置请求"
|
||||
// @Success 201 {object} store.Platform
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/platforms [post]
|
||||
func (s *Server) createPlatform(w http.ResponseWriter, r *http.Request) {
|
||||
var input store.CreatePlatformInput
|
||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
||||
@@ -209,6 +294,23 @@ func (s *Server) createPlatform(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusCreated, platform)
|
||||
}
|
||||
|
||||
// updatePlatform godoc
|
||||
// @Summary 更新平台
|
||||
// @Description 覆盖指定平台的基础配置、凭证、优先级、定价和运行策略。
|
||||
// @Tags platforms
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param platformID path string true "平台 ID"
|
||||
// @Param input body store.CreatePlatformInput true "平台配置请求"
|
||||
// @Success 200 {object} store.Platform
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 404 {object} ErrorEnvelope
|
||||
// @Failure 409 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/platforms/{platformID} [patch]
|
||||
func (s *Server) updatePlatform(w http.ResponseWriter, r *http.Request) {
|
||||
var input store.CreatePlatformInput
|
||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
||||
@@ -253,6 +355,19 @@ func (s *Server) updatePlatform(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, platform)
|
||||
}
|
||||
|
||||
// deletePlatform godoc
|
||||
// @Summary 删除平台
|
||||
// @Description 删除指定平台及关联配置;不存在时返回 404。
|
||||
// @Tags platforms
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param platformID path string true "平台 ID"
|
||||
// @Success 204 "No Content"
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 404 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/platforms/{platformID} [delete]
|
||||
func (s *Server) deletePlatform(w http.ResponseWriter, r *http.Request) {
|
||||
if err := s.store.DeletePlatform(r.Context(), r.PathValue("platformID")); err != nil {
|
||||
if store.IsNotFound(err) {
|
||||
@@ -266,6 +381,23 @@ func (s *Server) deletePlatform(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// createPlatformModel godoc
|
||||
// @Summary 创建平台模型
|
||||
// @Description 为平台新增一个可路由模型;路径中的 platformID 会覆盖请求体 platformId。
|
||||
// @Tags platform-models
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param platformID path string true "平台 ID,使用 /api/admin/platforms/{platformID}/models 时由路径提供"
|
||||
// @Param input body store.CreatePlatformModelInput true "平台模型配置请求"
|
||||
// @Success 201 {object} store.PlatformModel
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 404 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/platforms/{platformID}/models [post]
|
||||
// @Router /api/admin/platform-models [post]
|
||||
func (s *Server) createPlatformModel(w http.ResponseWriter, r *http.Request) {
|
||||
var input store.CreatePlatformModelInput
|
||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
||||
@@ -292,6 +424,22 @@ func (s *Server) createPlatformModel(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusCreated, s.platformModelResponse(r.Context(), model))
|
||||
}
|
||||
|
||||
// replacePlatformModels godoc
|
||||
// @Summary 替换平台模型
|
||||
// @Description 用请求体中的 models 列表整体替换指定平台下的模型配置。
|
||||
// @Tags platform-models
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param platformID path string true "平台 ID"
|
||||
// @Param input body ReplacePlatformModelsRequest true "模型列表请求"
|
||||
// @Success 200 {object} PlatformModelListResponse
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 404 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/platforms/{platformID}/models [put]
|
||||
func (s *Server) replacePlatformModels(w http.ResponseWriter, r *http.Request) {
|
||||
platformID := r.PathValue("platformID")
|
||||
if platformID == "" {
|
||||
@@ -320,6 +468,19 @@ func (s *Server) replacePlatformModels(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": s.platformModelResponses(r.Context(), models)})
|
||||
}
|
||||
|
||||
// deletePlatformModel godoc
|
||||
// @Summary 删除平台模型
|
||||
// @Description 删除指定平台模型路由配置。
|
||||
// @Tags platform-models
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param modelID path string true "平台模型 ID"
|
||||
// @Success 204 "No Content"
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 404 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/platform-models/{modelID} [delete]
|
||||
func (s *Server) deletePlatformModel(w http.ResponseWriter, r *http.Request) {
|
||||
if err := s.store.DeletePlatformModel(r.Context(), r.PathValue("modelID")); err != nil {
|
||||
if store.IsNotFound(err) {
|
||||
@@ -333,6 +494,17 @@ func (s *Server) deletePlatformModel(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// listModels godoc
|
||||
// @Summary 列出平台模型
|
||||
// @Description 管理端返回所有平台模型,并补齐有效计费配置。
|
||||
// @Tags platform-models
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} PlatformModelListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/models [get]
|
||||
func (s *Server) listModels(w http.ResponseWriter, r *http.Request) {
|
||||
models, err := s.store.ListModels(r.Context())
|
||||
if err != nil {
|
||||
@@ -343,6 +515,17 @@ func (s *Server) listModels(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": s.platformModelResponses(r.Context(), models)})
|
||||
}
|
||||
|
||||
// listPlayableModels godoc
|
||||
// @Summary 列出可调用模型
|
||||
// @Description 按当前用户权限返回可用于 Playground 或 API 调用的模型列表。
|
||||
// @Tags playground
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} PlatformModelListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/v1/models [get]
|
||||
// @Router /api/v1/playground/models [get]
|
||||
func (s *Server) listPlayableModels(w http.ResponseWriter, r *http.Request) {
|
||||
user, _ := auth.UserFromContext(r.Context())
|
||||
models, err := s.store.ListAccessiblePlatformModels(r.Context(), user)
|
||||
@@ -354,6 +537,17 @@ func (s *Server) listPlayableModels(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": s.platformModelResponses(r.Context(), models)})
|
||||
}
|
||||
|
||||
// listPricingRules godoc
|
||||
// @Summary 列出定价规则
|
||||
// @Description 返回所有定价规则明细,便于管理端排查有效价格。
|
||||
// @Tags pricing
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} PricingRuleListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/pricing/rules [get]
|
||||
func (s *Server) listPricingRules(w http.ResponseWriter, r *http.Request) {
|
||||
items, err := s.store.ListPricingRules(r.Context())
|
||||
if err != nil {
|
||||
@@ -364,6 +558,17 @@ func (s *Server) listPricingRules(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": items})
|
||||
}
|
||||
|
||||
// listTenants godoc
|
||||
// @Summary 列出租户
|
||||
// @Description 管理端返回网关租户列表。
|
||||
// @Tags identity
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} TenantListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/tenants [get]
|
||||
func (s *Server) listTenants(w http.ResponseWriter, r *http.Request) {
|
||||
items, err := s.store.ListTenants(r.Context())
|
||||
if err != nil {
|
||||
@@ -374,6 +579,17 @@ func (s *Server) listTenants(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": items})
|
||||
}
|
||||
|
||||
// listUsers godoc
|
||||
// @Summary 列出用户
|
||||
// @Description 管理端返回网关用户列表及钱包摘要。
|
||||
// @Tags identity
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} UserListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/users [get]
|
||||
func (s *Server) listUsers(w http.ResponseWriter, r *http.Request) {
|
||||
items, err := s.store.ListUsers(r.Context())
|
||||
if err != nil {
|
||||
@@ -384,6 +600,17 @@ func (s *Server) listUsers(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": items})
|
||||
}
|
||||
|
||||
// listUserGroups godoc
|
||||
// @Summary 列出用户组
|
||||
// @Description 管理端返回用户组及其计费、限流和配额策略。
|
||||
// @Tags identity
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} UserGroupListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/user-groups [get]
|
||||
func (s *Server) listUserGroups(w http.ResponseWriter, r *http.Request) {
|
||||
items, err := s.store.ListUserGroups(r.Context())
|
||||
if err != nil {
|
||||
@@ -394,6 +621,16 @@ func (s *Server) listUserGroups(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": items})
|
||||
}
|
||||
|
||||
// listAPIKeys godoc
|
||||
// @Summary 列出 API Key
|
||||
// @Description 返回当前用户创建的 API Key 元数据,secret 只在创建时返回。
|
||||
// @Tags api-keys
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} APIKeyListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/v1/api-keys [get]
|
||||
func (s *Server) listAPIKeys(w http.ResponseWriter, r *http.Request) {
|
||||
user, _ := auth.UserFromContext(r.Context())
|
||||
items, err := s.store.ListAPIKeys(r.Context(), user)
|
||||
@@ -405,6 +642,17 @@ func (s *Server) listAPIKeys(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": items})
|
||||
}
|
||||
|
||||
// listPlayableAPIKeys godoc
|
||||
// @Summary 列出 Playground API Key
|
||||
// @Description 返回当前本地用户可在 Playground 中直接使用的 API Key 和 secret。
|
||||
// @Tags playground
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} PlayableAPIKeyListResponse
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/playground/api-keys [get]
|
||||
func (s *Server) listPlayableAPIKeys(w http.ResponseWriter, r *http.Request) {
|
||||
user, _ := auth.UserFromContext(r.Context())
|
||||
items, err := s.store.ListPlayableAPIKeys(r.Context(), user)
|
||||
@@ -420,6 +668,19 @@ func (s *Server) listPlayableAPIKeys(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": items})
|
||||
}
|
||||
|
||||
// createAPIKey godoc
|
||||
// @Summary 创建 API Key
|
||||
// @Description 为当前本地用户创建 API Key;secret 仅在本次响应中返回。
|
||||
// @Tags api-keys
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param input body store.CreateAPIKeyInput true "API Key 创建请求"
|
||||
// @Success 201 {object} store.CreatedAPIKey
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/v1/api-keys [post]
|
||||
func (s *Server) createAPIKey(w http.ResponseWriter, r *http.Request) {
|
||||
user, _ := auth.UserFromContext(r.Context())
|
||||
var input store.CreateAPIKeyInput
|
||||
@@ -440,6 +701,19 @@ func (s *Server) createAPIKey(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusCreated, created)
|
||||
}
|
||||
|
||||
// disableAPIKey godoc
|
||||
// @Summary 禁用 API Key
|
||||
// @Description 禁用当前用户拥有的 API Key,保留记录但不再允许调用。
|
||||
// @Tags api-keys
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param apiKeyID path string true "API Key ID"
|
||||
// @Success 200 {object} store.APIKey
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 404 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/v1/api-keys/{apiKeyID}/disable [patch]
|
||||
func (s *Server) disableAPIKey(w http.ResponseWriter, r *http.Request) {
|
||||
user, _ := auth.UserFromContext(r.Context())
|
||||
item, err := s.store.DisableAPIKey(r.Context(), r.PathValue("apiKeyID"), user)
|
||||
@@ -459,6 +733,19 @@ func (s *Server) disableAPIKey(w http.ResponseWriter, r *http.Request) {
|
||||
writeError(w, http.StatusInternalServerError, "disable api key failed")
|
||||
}
|
||||
|
||||
// deleteAPIKey godoc
|
||||
// @Summary 删除 API Key
|
||||
// @Description 删除当前用户拥有的 API Key。
|
||||
// @Tags api-keys
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param apiKeyID path string true "API Key ID"
|
||||
// @Success 204 "No Content"
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 404 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/v1/api-keys/{apiKeyID} [delete]
|
||||
func (s *Server) deleteAPIKey(w http.ResponseWriter, r *http.Request) {
|
||||
user, _ := auth.UserFromContext(r.Context())
|
||||
err := s.store.DeleteAPIKey(r.Context(), r.PathValue("apiKeyID"), user)
|
||||
@@ -478,6 +765,22 @@ func (s *Server) deleteAPIKey(w http.ResponseWriter, r *http.Request) {
|
||||
writeError(w, http.StatusInternalServerError, "delete api key failed")
|
||||
}
|
||||
|
||||
// estimatePricing godoc
|
||||
// @Summary 估算请求价格
|
||||
// @Description 按当前用户、模型候选、任务类型和请求参数估算计费条目。
|
||||
// @Tags pricing
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param input body PricingEstimateRequest true "计费估算请求,kind 默认为 chat.completions"
|
||||
// @Success 200 {object} PricingEstimateResponse
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 404 {object} ErrorEnvelope
|
||||
// @Failure 429 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/v1/pricing/estimate [post]
|
||||
func (s *Server) estimatePricing(w http.ResponseWriter, r *http.Request) {
|
||||
user, _ := auth.UserFromContext(r.Context())
|
||||
var body map[string]any
|
||||
@@ -511,6 +814,17 @@ func (s *Server) estimatePricing(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, estimate)
|
||||
}
|
||||
|
||||
// listRateLimitWindows godoc
|
||||
// @Summary 列出限流窗口
|
||||
// @Description 管理端查看当前运行时限流窗口状态。
|
||||
// @Tags runtime
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} RateLimitWindowListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/runtime/rate-limit-windows [get]
|
||||
func (s *Server) listRateLimitWindows(w http.ResponseWriter, r *http.Request) {
|
||||
items, err := s.store.ListRateLimitWindows(r.Context())
|
||||
if err != nil {
|
||||
@@ -521,6 +835,17 @@ func (s *Server) listRateLimitWindows(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": items})
|
||||
}
|
||||
|
||||
// listModelRateLimitStatuses godoc
|
||||
// @Summary 列出模型限流状态
|
||||
// @Description 管理端查看平台模型维度的限流和冷却状态。
|
||||
// @Tags runtime
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} ModelRateLimitStatusListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/admin/runtime/model-rate-limits [get]
|
||||
func (s *Server) listModelRateLimitStatuses(w http.ResponseWriter, r *http.Request) {
|
||||
items, err := s.store.ListModelRateLimitStatuses(r.Context())
|
||||
if err != nil {
|
||||
@@ -531,6 +856,37 @@ func (s *Server) listModelRateLimitStatuses(w http.ResponseWriter, r *http.Reque
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": items})
|
||||
}
|
||||
|
||||
// createTask godoc
|
||||
// @Summary 创建或执行 AI 任务
|
||||
// @Description 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。
|
||||
// @Tags tasks
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param X-Async header bool false "true 时异步创建任务并返回 202"
|
||||
// @Param input body TaskRequest true "AI 任务请求,字段随任务类型变化"
|
||||
// @Success 200 {object} CompatibleResponse
|
||||
// @Success 202 {object} TaskAcceptedResponse
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 402 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope
|
||||
// @Failure 404 {object} ErrorEnvelope
|
||||
// @Failure 429 {object} ErrorEnvelope
|
||||
// @Failure 502 {object} ErrorEnvelope
|
||||
// @Router /api/v1/chat/completions [post]
|
||||
// @Router /api/v1/responses [post]
|
||||
// @Router /api/v1/images/generations [post]
|
||||
// @Router /api/v1/images/edits [post]
|
||||
// @Router /api/v1/videos/generations [post]
|
||||
// @Router /chat/completions [post]
|
||||
// @Router /v1/chat/completions [post]
|
||||
// @Router /responses [post]
|
||||
// @Router /v1/responses [post]
|
||||
// @Router /images/generations [post]
|
||||
// @Router /v1/images/generations [post]
|
||||
// @Router /images/edits [post]
|
||||
// @Router /v1/images/edits [post]
|
||||
func (s *Server) createTask(kind string, compatible bool) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := auth.UserFromContext(r.Context())
|
||||
@@ -742,6 +1098,24 @@ func runErrorCode(err error) string {
|
||||
return clients.ErrorCode(err)
|
||||
}
|
||||
|
||||
// listTasks godoc
|
||||
// @Summary 列出任务
|
||||
// @Description 按当前用户列出任务,支持关键字、模型类型、时间范围和分页过滤。
|
||||
// @Tags tasks
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param q query string false "搜索关键字,别名 query"
|
||||
// @Param modelType query string false "模型类型,别名 type"
|
||||
// @Param createdFrom query string false "创建时间起点,支持 RFC3339 或日期格式,别名 from"
|
||||
// @Param createdTo query string false "创建时间终点,支持 RFC3339 或日期格式,别名 to"
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param pageSize query int false "每页数量,别名 limit" default(50)
|
||||
// @Success 200 {object} TaskListResponse
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/workspace/tasks [get]
|
||||
// @Router /api/v1/tasks [get]
|
||||
func (s *Server) listTasks(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := auth.UserFromContext(r.Context())
|
||||
if !ok {
|
||||
@@ -837,6 +1211,19 @@ func boolValue(body map[string]any, key string) bool {
|
||||
return value
|
||||
}
|
||||
|
||||
// getTask godoc
|
||||
// @Summary 获取任务详情
|
||||
// @Description 返回指定任务的请求、状态、输出和执行摘要。
|
||||
// @Tags tasks
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param taskID path string true "任务 ID"
|
||||
// @Success 200 {object} store.GatewayTask
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 404 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/workspace/tasks/{taskID} [get]
|
||||
// @Router /api/v1/tasks/{taskID} [get]
|
||||
func (s *Server) getTask(w http.ResponseWriter, r *http.Request) {
|
||||
task, err := s.store.GetTask(r.Context(), r.PathValue("taskID"))
|
||||
if err == nil {
|
||||
@@ -851,6 +1238,19 @@ func (s *Server) getTask(w http.ResponseWriter, r *http.Request) {
|
||||
writeError(w, http.StatusInternalServerError, "get task failed")
|
||||
}
|
||||
|
||||
// taskParamPreprocessing godoc
|
||||
// @Summary 获取任务参数预处理日志
|
||||
// @Description 返回指定任务在执行前的参数改写、校验或模板处理日志。
|
||||
// @Tags tasks
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param taskID path string true "任务 ID"
|
||||
// @Success 200 {object} TaskParamPreprocessingLogListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 404 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/workspace/tasks/{taskID}/param-preprocessing [get]
|
||||
// @Router /api/v1/tasks/{taskID}/param-preprocessing [get]
|
||||
func (s *Server) taskParamPreprocessing(w http.ResponseWriter, r *http.Request) {
|
||||
task, err := s.store.GetTask(r.Context(), r.PathValue("taskID"))
|
||||
if err != nil {
|
||||
@@ -871,6 +1271,19 @@ func (s *Server) taskParamPreprocessing(w http.ResponseWriter, r *http.Request)
|
||||
writeJSON(w, http.StatusOK, map[string]any{"items": logs})
|
||||
}
|
||||
|
||||
// taskEvents godoc
|
||||
// @Summary 订阅任务事件
|
||||
// @Description 以 text/event-stream 返回指定任务的历史事件;无事件时返回 task.accepted 占位事件。
|
||||
// @Tags tasks
|
||||
// @Produce text/event-stream
|
||||
// @Security BearerAuth
|
||||
// @Param taskID path string true "任务 ID"
|
||||
// @Success 200 {string} string "Server-Sent Events,data 为 store.TaskEvent 或 TaskAcceptedEvent"
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 404 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/workspace/tasks/{taskID}/events [get]
|
||||
// @Router /api/v1/tasks/{taskID}/events [get]
|
||||
func (s *Server) taskEvents(w http.ResponseWriter, r *http.Request) {
|
||||
task, err := s.store.GetTask(r.Context(), r.PathValue("taskID"))
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user