diff --git a/README.md b/README.md index 88e5b40..b70bfab 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,15 @@ pnpm dev 后端热更新可通过 `GO_WATCH_SHUTDOWN_GRACE_MS` 和 `GO_WATCH_RESTART_DELAY_MS` 调整旧进程退出等待时间与重启间隔。 +## OpenAPI 文档 + +修改 `apps/api/internal/httpapi` 下的接口、请求或响应类型后,请重新执行: + +```bash +pnpm openapi +``` + + 默认 EasyAI 部署里,`easyai-pgvector` 在容器网络内的连接串是: ```dotenv diff --git a/apps/api/cmd/gateway/main.go b/apps/api/cmd/gateway/main.go index 9bb935b..ca2c6b2 100644 --- a/apps/api/cmd/gateway/main.go +++ b/apps/api/cmd/gateway/main.go @@ -15,6 +15,16 @@ import ( "github.com/easyai/easyai-ai-gateway/apps/api/internal/store" ) +// @title EasyAI AI Gateway API +// @version 0.1.0 +// @description EasyAI AI Gateway 的本地鉴权、平台模型管理、定价、运行策略、钱包和 AI 任务接口。 +// @description 受保护接口使用 Authorization: Bearer ,管理接口只接受 JWT 用户凭证。 +// @BasePath / +// @schemes http https +// @securityDefinitions.apikey BearerAuth +// @in header +// @name Authorization +// @description Bearer JWT 或 API Key。 func main() { cfg := config.Load() logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ diff --git a/apps/api/docs/swagger.json b/apps/api/docs/swagger.json new file mode 100644 index 0000000..d132c95 --- /dev/null +++ b/apps/api/docs/swagger.json @@ -0,0 +1,9027 @@ +{ + "schemes": [ + "http", + "https" + ], + "swagger": "2.0", + "info": { + "description": "EasyAI AI Gateway 的本地鉴权、平台模型管理、定价、运行策略、钱包和 AI 任务接口。\n受保护接口使用 Authorization: Bearer \u003cJWT 或 API Key\u003e,管理接口只接受 JWT 用户凭证。", + "title": "EasyAI AI Gateway API", + "contact": {}, + "version": "0.1.0" + }, + "basePath": "/", + "paths": { + "/api/admin/access-rules": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端返回用户组、租户、用户或 API Key 到平台、平台模型、基础模型的访问规则。", + "produces": [ + "application/json" + ], + "tags": [ + "access-rules" + ], + "summary": "列出访问规则", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.AccessRuleListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端创建一条访问控制规则。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "access-rules" + ], + "summary": "创建访问规则", + "parameters": [ + { + "description": "访问规则请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.AccessRuleInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/store.AccessRule" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/access-rules/batch": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端为同一主体批量新增、更新或删除资源访问规则。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "access-rules" + ], + "summary": "批量写入访问规则", + "parameters": [ + { + "description": "访问规则批量请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.AccessRuleBatchInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.AccessRuleListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/access-rules/{ruleID}": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端删除一条访问控制规则。", + "produces": [ + "application/json" + ], + "tags": [ + "access-rules" + ], + "summary": "删除访问规则", + "parameters": [ + { + "type": "string", + "description": "访问规则 ID", + "name": "ruleID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端更新一条访问控制规则。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "access-rules" + ], + "summary": "更新访问规则", + "parameters": [ + { + "type": "string", + "description": "访问规则 ID", + "name": "ruleID", + "in": "path", + "required": true + }, + { + "description": "访问规则请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.AccessRuleInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.AccessRule" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/audit-logs": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端按分类、动作、目标类型和目标 ID 查询审计日志。", + "produces": [ + "application/json" + ], + "tags": [ + "billing" + ], + "summary": "列出审计日志", + "parameters": [ + { + "type": "string", + "description": "审计分类", + "name": "category", + "in": "query" + }, + { + "type": "string", + "description": "审计动作", + "name": "action", + "in": "query" + }, + { + "type": "string", + "description": "目标类型", + "name": "targetType", + "in": "query" + }, + { + "type": "string", + "description": "目标 ID", + "name": "targetId", + "in": "query" + }, + { + "type": "integer", + "default": 100, + "description": "返回数量", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.AuditLogListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/catalog/base-models": { + "get": { + "description": "返回基础模型目录;公共路径和管理路径返回同一结构。", + "produces": [ + "application/json" + ], + "tags": [ + "catalog" + ], + "summary": "列出基础模型", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.BaseModelListResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端新增基础模型目录项,providerKey、providerModelName 和 modelType 必填。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "catalog" + ], + "summary": "创建基础模型", + "parameters": [ + { + "description": "基础模型请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.BaseModelInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/store.BaseModel" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/catalog/base-models/reset-all": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "将所有具备系统默认快照的基础模型恢复为默认配置。", + "produces": [ + "application/json" + ], + "tags": [ + "catalog" + ], + "summary": "重置全部基础模型", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.BaseModelListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/catalog/base-models/{baseModelID}": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端删除基础模型目录项。", + "produces": [ + "application/json" + ], + "tags": [ + "catalog" + ], + "summary": "删除基础模型", + "parameters": [ + { + "type": "string", + "description": "基础模型 ID", + "name": "baseModelID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端更新基础模型目录项及能力、图标、默认快照等元数据。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "catalog" + ], + "summary": "更新基础模型", + "parameters": [ + { + "type": "string", + "description": "基础模型 ID", + "name": "baseModelID", + "in": "path", + "required": true + }, + { + "description": "基础模型请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.BaseModelInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.BaseModel" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/catalog/base-models/{baseModelID}/reset": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "将指定基础模型恢复为系统默认快照;无默认快照时返回 409。", + "produces": [ + "application/json" + ], + "tags": [ + "catalog" + ], + "summary": "重置基础模型", + "parameters": [ + { + "type": "string", + "description": "基础模型 ID", + "name": "baseModelID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.BaseModel" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/catalog/providers": { + "get": { + "description": "返回模型目录使用的供应商元数据;公共路径和管理路径返回同一结构。", + "produces": [ + "application/json" + ], + "tags": [ + "catalog" + ], + "summary": "列出目录供应商", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CatalogProviderListResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端新增模型目录供应商,providerKey 和 displayName 必填。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "catalog" + ], + "summary": "创建目录供应商", + "parameters": [ + { + "description": "目录供应商请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.CatalogProviderInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/store.CatalogProvider" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/catalog/providers/{providerID}": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端删除目录供应商。", + "produces": [ + "application/json" + ], + "tags": [ + "catalog" + ], + "summary": "删除目录供应商", + "parameters": [ + { + "type": "string", + "description": "目录供应商 ID", + "name": "providerID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端更新目录供应商展示信息、图标和元数据。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "catalog" + ], + "summary": "更新目录供应商", + "parameters": [ + { + "type": "string", + "description": "目录供应商 ID", + "name": "providerID", + "in": "path", + "required": true + }, + { + "description": "目录供应商请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.CatalogProviderInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.CatalogProvider" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/config/network-proxy": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端查看服务当前使用的全局 HTTP 代理配置及来源。", + "produces": [ + "application/json" + ], + "tags": [ + "config" + ], + "summary": "获取网络代理配置", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.NetworkProxyConfigResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/models": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端返回所有平台模型,并补齐有效计费配置。", + "produces": [ + "application/json" + ], + "tags": [ + "platform-models" + ], + "summary": "列出平台模型", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.PlatformModelListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/platform-models": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "为平台新增一个可路由模型;路径中的 platformID 会覆盖请求体 platformId。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "platform-models" + ], + "summary": "创建平台模型", + "parameters": [ + { + "description": "平台模型配置请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.CreatePlatformModelInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/store.PlatformModel" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/platform-models/{modelID}": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "删除指定平台模型路由配置。", + "produces": [ + "application/json" + ], + "tags": [ + "platform-models" + ], + "summary": "删除平台模型", + "parameters": [ + { + "type": "string", + "description": "平台模型 ID", + "name": "modelID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/platforms": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端返回所有接入平台及其优先级、定价和运行策略摘要。", + "produces": [ + "application/json" + ], + "tags": [ + "platforms" + ], + "summary": "列出平台", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.PlatformListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "新增模型供应商平台配置;credentials 会被服务端保存并在返回值中脱敏。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "platforms" + ], + "summary": "创建平台", + "parameters": [ + { + "description": "平台配置请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.CreatePlatformInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/store.Platform" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/platforms/{platformID}": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "删除指定平台及关联配置;不存在时返回 404。", + "produces": [ + "application/json" + ], + "tags": [ + "platforms" + ], + "summary": "删除平台", + "parameters": [ + { + "type": "string", + "description": "平台 ID", + "name": "platformID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "覆盖指定平台的基础配置、凭证、优先级、定价和运行策略。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "platforms" + ], + "summary": "更新平台", + "parameters": [ + { + "type": "string", + "description": "平台 ID", + "name": "platformID", + "in": "path", + "required": true + }, + { + "description": "平台配置请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.CreatePlatformInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.Platform" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/platforms/{platformID}/dynamic-priority": { + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端调整平台运行时动态优先级;reset 为 true 时清空动态值。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "runtime" + ], + "summary": "更新平台动态优先级", + "parameters": [ + { + "type": "string", + "description": "平台 ID", + "name": "platformID", + "in": "path", + "required": true + }, + { + "description": "动态优先级请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.updatePlatformDynamicPriorityRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.Platform" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/platforms/{platformID}/models": { + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "用请求体中的 models 列表整体替换指定平台下的模型配置。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "platform-models" + ], + "summary": "替换平台模型", + "parameters": [ + { + "type": "string", + "description": "平台 ID", + "name": "platformID", + "in": "path", + "required": true + }, + { + "description": "模型列表请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.ReplacePlatformModelsRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.PlatformModelListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "为平台新增一个可路由模型;路径中的 platformID 会覆盖请求体 platformId。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "platform-models" + ], + "summary": "创建平台模型", + "parameters": [ + { + "type": "string", + "description": "平台 ID,使用 /api/admin/platforms/{platformID}/models 时由路径提供", + "name": "platformID", + "in": "path", + "required": true + }, + { + "description": "平台模型配置请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.CreatePlatformModelInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/store.PlatformModel" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/pricing/rule-sets": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端返回可分配给平台、模型、租户或用户组的定价规则集。", + "produces": [ + "application/json" + ], + "tags": [ + "pricing" + ], + "summary": "列出定价规则集", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.PricingRuleSetListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端创建定价规则集,ruleSetKey、name 和至少一条 rule 必填。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pricing" + ], + "summary": "创建定价规则集", + "parameters": [ + { + "description": "定价规则集请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.PricingRuleSetInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/store.PricingRuleSet" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/pricing/rule-sets/{ruleSetID}": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端删除非默认定价规则集;默认规则集受保护。", + "produces": [ + "application/json" + ], + "tags": [ + "pricing" + ], + "summary": "删除定价规则集", + "parameters": [ + { + "type": "string", + "description": "定价规则集 ID", + "name": "ruleSetID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端更新定价规则集及其规则列表。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pricing" + ], + "summary": "更新定价规则集", + "parameters": [ + { + "type": "string", + "description": "定价规则集 ID", + "name": "ruleSetID", + "in": "path", + "required": true + }, + { + "description": "定价规则集请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.PricingRuleSetInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.PricingRuleSet" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/pricing/rules": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "返回所有定价规则明细,便于管理端排查有效价格。", + "produces": [ + "application/json" + ], + "tags": [ + "pricing" + ], + "summary": "列出定价规则", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.PricingRuleListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/runtime/model-rate-limits": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端查看平台模型维度的限流和冷却状态。", + "produces": [ + "application/json" + ], + "tags": [ + "runtime" + ], + "summary": "列出模型限流状态", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.ModelRateLimitStatusListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/runtime/policy-sets": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端返回可分配给平台、模型或用户组的运行策略集。", + "produces": [ + "application/json" + ], + "tags": [ + "runtime" + ], + "summary": "列出运行策略集", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.RuntimePolicySetListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端创建运行策略集,policyKey 和 name 必填。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "runtime" + ], + "summary": "创建运行策略集", + "parameters": [ + { + "description": "运行策略集请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.RuntimePolicySetInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/store.RuntimePolicySet" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/runtime/policy-sets/{policySetID}": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端删除非默认运行策略集;默认策略集受保护。", + "produces": [ + "application/json" + ], + "tags": [ + "runtime" + ], + "summary": "删除运行策略集", + "parameters": [ + { + "type": "string", + "description": "运行策略集 ID", + "name": "policySetID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端更新运行策略集及其限流、重试、超时等策略配置。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "runtime" + ], + "summary": "更新运行策略集", + "parameters": [ + { + "type": "string", + "description": "运行策略集 ID", + "name": "policySetID", + "in": "path", + "required": true + }, + { + "description": "运行策略集请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.RuntimePolicySetInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.RuntimePolicySet" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/runtime/rate-limit-windows": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端查看当前运行时限流窗口状态。", + "produces": [ + "application/json" + ], + "tags": [ + "runtime" + ], + "summary": "列出限流窗口", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.RateLimitWindowListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/runtime/runner-policy": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端获取当前生效的默认 Runner 调度策略。", + "produces": [ + "application/json" + ], + "tags": [ + "runtime" + ], + "summary": "获取 Runner 策略", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.RunnerPolicy" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端写入默认 Runner 调度策略。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "runtime" + ], + "summary": "更新 Runner 策略", + "parameters": [ + { + "description": "Runner 策略请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.RunnerPolicyInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.RunnerPolicy" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/tenants": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端返回网关租户列表。", + "produces": [ + "application/json" + ], + "tags": [ + "identity" + ], + "summary": "列出租户", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.TenantListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端创建网关租户,tenantKey 和 name 必填。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "identity" + ], + "summary": "创建租户", + "parameters": [ + { + "description": "租户请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.GatewayTenantInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/store.GatewayTenant" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/tenants/{tenantID}": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端删除网关租户。", + "produces": [ + "application/json" + ], + "tags": [ + "identity" + ], + "summary": "删除租户", + "parameters": [ + { + "type": "string", + "description": "租户 ID", + "name": "tenantID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端更新网关租户信息。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "identity" + ], + "summary": "更新租户", + "parameters": [ + { + "type": "string", + "description": "租户 ID", + "name": "tenantID", + "in": "path", + "required": true + }, + { + "description": "租户请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.GatewayTenantInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.GatewayTenant" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/user-groups": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端返回用户组及其计费、限流和配额策略。", + "produces": [ + "application/json" + ], + "tags": [ + "identity" + ], + "summary": "列出用户组", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.UserGroupListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端创建用户组,可配置默认定价、运行策略、限流和配额策略。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "identity" + ], + "summary": "创建用户组", + "parameters": [ + { + "description": "用户组请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.UserGroupInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/store.UserGroup" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/user-groups/{groupID}": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端删除用户组。", + "produces": [ + "application/json" + ], + "tags": [ + "identity" + ], + "summary": "删除用户组", + "parameters": [ + { + "type": "string", + "description": "用户组 ID", + "name": "groupID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端更新用户组基础信息和策略配置。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "identity" + ], + "summary": "更新用户组", + "parameters": [ + { + "type": "string", + "description": "用户组 ID", + "name": "groupID", + "in": "path", + "required": true + }, + { + "description": "用户组请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.UserGroupInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.UserGroup" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/users": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端返回网关用户列表及钱包摘要。", + "produces": [ + "application/json" + ], + "tags": [ + "identity" + ], + "summary": "列出用户", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.UserListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端创建网关用户;password 为空时不设置本地密码,非空时至少 8 位。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "identity" + ], + "summary": "创建用户", + "parameters": [ + { + "description": "用户请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.GatewayUserInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/store.GatewayUser" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/users/{userID}": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端删除网关用户。", + "produces": [ + "application/json" + ], + "tags": [ + "identity" + ], + "summary": "删除用户", + "parameters": [ + { + "type": "string", + "description": "用户 ID", + "name": "userID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端更新网关用户资料、角色、默认用户组和可选本地密码。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "identity" + ], + "summary": "更新用户", + "parameters": [ + { + "type": "string", + "description": "用户 ID", + "name": "userID", + "in": "path", + "required": true + }, + { + "description": "用户请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.GatewayUserInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.GatewayUser" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/admin/users/{userID}/wallet": { + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "管理端把指定用户钱包余额调整到目标值,并记录审计日志;balance 不允许为负数。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "billing" + ], + "summary": "设置用户钱包余额", + "parameters": [ + { + "type": "string", + "description": "用户 ID", + "name": "userID", + "in": "path", + "required": true + }, + { + "description": "钱包余额设置请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.walletBalanceRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.WalletAdjustmentResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/playground/api-keys": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "返回当前本地用户可在 Playground 中直接使用的 API Key 和 secret。", + "produces": [ + "application/json" + ], + "tags": [ + "playground" + ], + "summary": "列出 Playground API Key", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.PlayableAPIKeyListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/api-keys": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "返回当前用户创建的 API Key 元数据,secret 只在创建时返回。", + "produces": [ + "application/json" + ], + "tags": [ + "api-keys" + ], + "summary": "列出 API Key", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.APIKeyListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "为当前本地用户创建 API Key;secret 仅在本次响应中返回。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "api-keys" + ], + "summary": "创建 API Key", + "parameters": [ + { + "description": "API Key 创建请求", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.CreateAPIKeyInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/store.CreatedAPIKey" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/api-keys/access-rules": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "返回当前本地用户可管理的 API Key 访问规则。", + "produces": [ + "application/json" + ], + "tags": [ + "api-keys" + ], + "summary": "列出 API Key 访问规则", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.AccessRuleListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/api-keys/access-rules/batch": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "当前本地用户为自己的 API Key 批量新增、更新或删除可访问资源。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "api-keys" + ], + "summary": "批量写入 API Key 访问规则", + "parameters": [ + { + "description": "API Key 访问规则批量请求,subjectType 必须为 api_key", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.AccessRuleBatchInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.AccessRuleListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/api-keys/{apiKeyID}": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "删除当前用户拥有的 API Key。", + "produces": [ + "application/json" + ], + "tags": [ + "api-keys" + ], + "summary": "删除 API Key", + "parameters": [ + { + "type": "string", + "description": "API Key ID", + "name": "apiKeyID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/api-keys/{apiKeyID}/disable": { + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "禁用当前用户拥有的 API Key,保留记录但不再允许调用。", + "produces": [ + "application/json" + ], + "tags": [ + "api-keys" + ], + "summary": "禁用 API Key", + "parameters": [ + { + "type": "string", + "description": "API Key ID", + "name": "apiKeyID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.APIKey" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/auth/login": { + "post": { + "description": "使用用户名或邮箱登录本地账号,并返回 24 小时 JWT。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "本地登录", + "parameters": [ + { + "description": "登录请求,account 可为用户名或邮箱", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.LocalLoginInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.AuthResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/auth/register": { + "post": { + "description": "在 standalone 或 hybrid 身份模式下创建本地用户,并返回 24 小时 JWT。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "本地注册", + "parameters": [ + { + "description": "注册请求,password 至少 8 位,invitationCode 取决于部署策略", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/store.LocalRegisterInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/httpapi.AuthResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/chat/completions": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/images/edits": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/images/generations": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/me": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "返回鉴权中解析出的用户、租户、用户组和 API Key 上下文。", + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "获取当前用户", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/auth.User" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/model-catalog": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "聚合平台模型、基础模型、供应商、运行策略和访问规则,返回前端模型目录所需的过滤器、摘要和展示字段。", + "produces": [ + "application/json" + ], + "tags": [ + "model-catalog" + ], + "summary": "列出模型目录", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.ModelCatalogResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/models": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "按当前用户权限返回可用于 Playground 或 API 调用的模型列表。", + "produces": [ + "application/json" + ], + "tags": [ + "playground" + ], + "summary": "列出可调用模型", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.PlatformModelListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/platforms": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "按当前用户可访问模型过滤平台,仅返回启用且存在可访问模型的平台。", + "produces": [ + "application/json" + ], + "tags": [ + "playground" + ], + "summary": "列出可用平台", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.PlatformListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/playground/models": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "按当前用户权限返回可用于 Playground 或 API 调用的模型列表。", + "produces": [ + "application/json" + ], + "tags": [ + "playground" + ], + "summary": "列出可调用模型", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.PlatformModelListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/pricing/estimate": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "按当前用户、模型候选、任务类型和请求参数估算计费条目。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pricing" + ], + "summary": "估算请求价格", + "parameters": [ + { + "description": "计费估算请求,kind 默认为 chat.completions", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.PricingEstimateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.PricingEstimateResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/public/catalog/base-models": { + "get": { + "description": "返回基础模型目录;公共路径和管理路径返回同一结构。", + "produces": [ + "application/json" + ], + "tags": [ + "catalog" + ], + "summary": "列出基础模型", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.BaseModelListResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/public/catalog/providers": { + "get": { + "description": "返回模型目录使用的供应商元数据;公共路径和管理路径返回同一结构。", + "produces": [ + "application/json" + ], + "tags": [ + "catalog" + ], + "summary": "列出目录供应商", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CatalogProviderListResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/responses": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/tasks": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "按当前用户列出任务,支持关键字、模型类型、时间范围和分页过滤。", + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "列出任务", + "parameters": [ + { + "type": "string", + "description": "搜索关键字,别名 query", + "name": "q", + "in": "query" + }, + { + "type": "string", + "description": "模型类型,别名 type", + "name": "modelType", + "in": "query" + }, + { + "type": "string", + "description": "创建时间起点,支持 RFC3339 或日期格式,别名 from", + "name": "createdFrom", + "in": "query" + }, + { + "type": "string", + "description": "创建时间终点,支持 RFC3339 或日期格式,别名 to", + "name": "createdTo", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "default": 50, + "description": "每页数量,别名 limit", + "name": "pageSize", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.TaskListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/tasks/{taskID}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "返回指定任务的请求、状态、输出和执行摘要。", + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "获取任务详情", + "parameters": [ + { + "type": "string", + "description": "任务 ID", + "name": "taskID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.GatewayTask" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/tasks/{taskID}/events": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "以 text/event-stream 返回指定任务的历史事件;无事件时返回 task.accepted 占位事件。", + "produces": [ + "text/event-stream" + ], + "tags": [ + "tasks" + ], + "summary": "订阅任务事件", + "parameters": [ + { + "type": "string", + "description": "任务 ID", + "name": "taskID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Server-Sent Events,data 为 store.TaskEvent 或 TaskAcceptedEvent", + "schema": { + "type": "string" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/tasks/{taskID}/param-preprocessing": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "返回指定任务在执行前的参数改写、校验或模板处理日志。", + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "获取任务参数预处理日志", + "parameters": [ + { + "type": "string", + "description": "任务 ID", + "name": "taskID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.TaskParamPreprocessingLogListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/v1/videos/generations": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/workspace/tasks": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "按当前用户列出任务,支持关键字、模型类型、时间范围和分页过滤。", + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "列出任务", + "parameters": [ + { + "type": "string", + "description": "搜索关键字,别名 query", + "name": "q", + "in": "query" + }, + { + "type": "string", + "description": "模型类型,别名 type", + "name": "modelType", + "in": "query" + }, + { + "type": "string", + "description": "创建时间起点,支持 RFC3339 或日期格式,别名 from", + "name": "createdFrom", + "in": "query" + }, + { + "type": "string", + "description": "创建时间终点,支持 RFC3339 或日期格式,别名 to", + "name": "createdTo", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "default": 50, + "description": "每页数量,别名 limit", + "name": "pageSize", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.TaskListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/workspace/tasks/{taskID}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "返回指定任务的请求、状态、输出和执行摘要。", + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "获取任务详情", + "parameters": [ + { + "type": "string", + "description": "任务 ID", + "name": "taskID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.GatewayTask" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/workspace/tasks/{taskID}/events": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "以 text/event-stream 返回指定任务的历史事件;无事件时返回 task.accepted 占位事件。", + "produces": [ + "text/event-stream" + ], + "tags": [ + "tasks" + ], + "summary": "订阅任务事件", + "parameters": [ + { + "type": "string", + "description": "任务 ID", + "name": "taskID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Server-Sent Events,data 为 store.TaskEvent 或 TaskAcceptedEvent", + "schema": { + "type": "string" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/workspace/tasks/{taskID}/param-preprocessing": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "返回指定任务在执行前的参数改写、校验或模板处理日志。", + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "获取任务参数预处理日志", + "parameters": [ + { + "type": "string", + "description": "任务 ID", + "name": "taskID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.TaskParamPreprocessingLogListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/workspace/wallet": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "返回当前用户的钱包账户、余额和最近消费摘要,可按 currency 过滤。", + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "获取钱包摘要", + "parameters": [ + { + "type": "string", + "default": "USD", + "description": "币种", + "name": "currency", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.WalletSummary" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/api/workspace/wallet/transactions": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "返回当前用户的钱包交易流水,支持关键字、方向、交易类型、时间范围和分页过滤。", + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "列出钱包交易", + "parameters": [ + { + "type": "string", + "description": "搜索关键字,别名 query", + "name": "q", + "in": "query" + }, + { + "type": "string", + "description": "交易方向", + "name": "direction", + "in": "query" + }, + { + "type": "string", + "description": "交易类型", + "name": "transactionType", + "in": "query" + }, + { + "type": "string", + "description": "创建时间起点,别名 from", + "name": "createdFrom", + "in": "query" + }, + { + "type": "string", + "description": "创建时间终点,别名 to", + "name": "createdTo", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "default": 50, + "description": "每页数量,别名 limit", + "name": "pageSize", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.WalletTransactionListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/chat/completions": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/healthz": { + "get": { + "description": "返回服务进程、运行环境和身份模式,供负载均衡或人工排障使用。", + "produces": [ + "application/json" + ], + "tags": [ + "system" + ], + "summary": "健康检查", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.HealthResponse" + } + } + } + } + }, + "/images/edits": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/images/generations": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/readyz": { + "get": { + "description": "检查 Postgres 是否可用;数据库不可用时返回 503。", + "produces": [ + "application/json" + ], + "tags": [ + "system" + ], + "summary": "就绪检查", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.ReadyResponse" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/responses": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/static/simulation/{asset}": { + "get": { + "description": "返回本地模拟模式使用的图片、视频封面或短视频资源。", + "produces": [ + "image/svg+xml", + "video/mp4" + ], + "tags": [ + "simulation" + ], + "summary": "获取模拟资源", + "parameters": [ + { + "type": "string", + "description": "资源文件名,可选 image.svg、image.png、image-edit.svg、image-edit.png、video-poster.svg、video.mp4", + "name": "asset", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "file" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "string" + } + } + } + } + }, + "/v1/chat/completions": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/v1/images/edits": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/v1/images/generations": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + }, + "/v1/responses": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 SSE 流。", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "tasks" + ], + "summary": "创建或执行 AI 任务", + "parameters": [ + { + "type": "boolean", + "description": "true 时异步创建任务并返回 202", + "name": "X-Async", + "in": "header" + }, + { + "description": "AI 任务请求,字段随任务类型变化", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/httpapi.TaskRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/httpapi.CompatibleResponse" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/httpapi.TaskAcceptedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/httpapi.ErrorEnvelope" + } + } + } + } + } + }, + "definitions": { + "auth.User": { + "type": "object", + "properties": { + "apiKeyId": { + "type": "string" + }, + "apiKeyName": { + "type": "string" + }, + "apiKeyPrefix": { + "type": "string" + }, + "apiKeyScopes": { + "type": "array", + "items": { + "type": "string" + } + }, + "apiKeySecret": { + "type": "string" + }, + "gatewayTenantId": { + "type": "string" + }, + "gatewayUserId": { + "type": "string" + }, + "role": { + "type": "array", + "items": { + "type": "string" + } + }, + "source": { + "type": "string" + }, + "sso_id": { + "type": "string" + }, + "sub": { + "type": "string" + }, + "tenantId": { + "type": "string" + }, + "tenantKey": { + "type": "string" + }, + "userGroupId": { + "type": "string" + }, + "userGroupKey": { + "type": "string" + }, + "userGroupKeys": { + "type": "array", + "items": { + "type": "string" + } + }, + "username": { + "type": "string" + } + } + }, + "httpapi.APIKeyListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.APIKey" + } + } + } + }, + "httpapi.AccessRuleListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.AccessRule" + } + } + } + }, + "httpapi.AuditLogListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.AuditLog" + } + } + } + }, + "httpapi.AuthResponse": { + "type": "object", + "properties": { + "accessToken": { + "type": "string", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + }, + "expiresIn": { + "type": "integer", + "example": 86400 + }, + "tokenType": { + "type": "string", + "example": "Bearer" + }, + "user": { + "$ref": "#/definitions/auth.User" + } + } + }, + "httpapi.BaseModelListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.BaseModel" + } + } + } + }, + "httpapi.CatalogProviderListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.CatalogProvider" + } + } + } + }, + "httpapi.ChatMessage": { + "type": "object", + "properties": { + "content": { + "type": "string", + "example": "Hello" + }, + "role": { + "type": "string", + "example": "user" + } + } + }, + "httpapi.CompatibleResponse": { + "type": "object", + "properties": { + "choices": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true + } + }, + "id": { + "type": "string", + "example": "chatcmpl-123" + }, + "model": { + "type": "string", + "example": "gpt-4o-mini" + }, + "object": { + "type": "string", + "example": "chat.completion" + }, + "usage": { + "type": "object", + "additionalProperties": true + } + } + }, + "httpapi.ErrorEnvelope": { + "type": "object", + "properties": { + "error": { + "$ref": "#/definitions/httpapi.ErrorPayload" + } + } + }, + "httpapi.ErrorPayload": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "rate_limit" + }, + "message": { + "type": "string", + "example": "invalid json body" + }, + "status": { + "type": "integer", + "example": 400 + } + } + }, + "httpapi.HealthResponse": { + "type": "object", + "properties": { + "env": { + "type": "string", + "example": "development" + }, + "identityMode": { + "type": "string", + "example": "standalone" + }, + "ok": { + "type": "boolean", + "example": true + }, + "service": { + "type": "string", + "example": "easyai-ai-gateway" + } + } + }, + "httpapi.ModelCatalogFilterOption": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "iconPath": { + "type": "string" + }, + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "httpapi.ModelCatalogFilters": { + "type": "object", + "properties": { + "capabilities": { + "type": "array", + "items": { + "$ref": "#/definitions/httpapi.ModelCatalogFilterOption" + } + }, + "providers": { + "type": "array", + "items": { + "$ref": "#/definitions/httpapi.ModelCatalogFilterOption" + } + } + } + }, + "httpapi.ModelCatalogItem": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "capabilityTags": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "discount": { + "$ref": "#/definitions/httpapi.ModelCatalogText" + }, + "displayName": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "iconPath": { + "type": "string" + }, + "id": { + "type": "string" + }, + "modelName": { + "type": "string" + }, + "modelType": { + "type": "array", + "items": { + "type": "string" + } + }, + "permission": { + "$ref": "#/definitions/httpapi.ModelCatalogPermission" + }, + "pricing": { + "$ref": "#/definitions/httpapi.ModelCatalogPricing" + }, + "providerKeys": { + "type": "array", + "items": { + "type": "string" + } + }, + "providers": { + "type": "array", + "items": { + "$ref": "#/definitions/httpapi.ModelCatalogProviderSummary" + } + }, + "rateLimits": { + "$ref": "#/definitions/httpapi.ModelCatalogRateLimits" + }, + "source": { + "$ref": "#/definitions/httpapi.ModelCatalogText" + }, + "sourceCount": { + "type": "integer" + }, + "sources": { + "type": "array", + "items": { + "$ref": "#/definitions/httpapi.ModelCatalogSource" + } + }, + "statusLabel": { + "type": "string" + } + } + }, + "httpapi.ModelCatalogPermission": { + "type": "object", + "properties": { + "allowGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "denyGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "label": { + "type": "string" + }, + "title": { + "type": "string" + } + } + }, + "httpapi.ModelCatalogPricing": { + "type": "object", + "properties": { + "lines": { + "type": "array", + "items": { + "type": "string" + } + }, + "title": { + "type": "string" + } + } + }, + "httpapi.ModelCatalogProviderSummary": { + "type": "object", + "properties": { + "iconPath": { + "type": "string" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "sourceCount": { + "type": "integer" + } + } + }, + "httpapi.ModelCatalogRateLimits": { + "type": "object", + "properties": { + "concurrent": { + "type": "number" + }, + "label": { + "type": "string" + }, + "rpm": { + "type": "number" + }, + "title": { + "type": "string" + }, + "tpm": { + "type": "number" + } + } + }, + "httpapi.ModelCatalogResponse": { + "type": "object", + "properties": { + "filters": { + "$ref": "#/definitions/httpapi.ModelCatalogFilters" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/httpapi.ModelCatalogItem" + } + }, + "summary": { + "$ref": "#/definitions/httpapi.ModelCatalogSummary" + } + } + }, + "httpapi.ModelCatalogSource": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "modelAlias": { + "type": "string" + }, + "modelName": { + "type": "string" + }, + "modelType": { + "type": "array", + "items": { + "type": "string" + } + }, + "platformId": { + "type": "string" + }, + "platformName": { + "type": "string" + }, + "providerKey": { + "type": "string" + }, + "providerName": { + "type": "string" + }, + "rateLimits": { + "$ref": "#/definitions/httpapi.ModelCatalogRateLimits" + } + } + }, + "httpapi.ModelCatalogSummary": { + "type": "object", + "properties": { + "modelCount": { + "type": "integer" + }, + "sourceCount": { + "type": "integer" + } + } + }, + "httpapi.ModelCatalogText": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "title": { + "type": "string" + } + } + }, + "httpapi.ModelRateLimitStatusListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.ModelRateLimitStatus" + } + } + } + }, + "httpapi.NetworkProxyConfigResponse": { + "type": "object", + "properties": { + "globalHttpProxy": { + "type": "string", + "example": "http://127.0.0.1:7890" + }, + "globalHttpProxySet": { + "type": "boolean", + "example": true + }, + "globalHttpProxySource": { + "type": "string", + "example": "env" + } + } + }, + "httpapi.PlatformListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.Platform" + } + } + } + }, + "httpapi.PlatformModelListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.PlatformModel" + } + } + } + }, + "httpapi.PlayableAPIKeyListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.PlayableAPIKey" + } + } + } + }, + "httpapi.PricingEstimateRequest": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "example": "chat.completions" + }, + "max_tokens": { + "type": "integer", + "example": 512 + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/httpapi.ChatMessage" + } + }, + "model": { + "type": "string", + "example": "gpt-4o-mini" + }, + "n": { + "type": "integer", + "example": 1 + }, + "prompt": { + "type": "string", + "example": "A small orange cat" + }, + "runMode": { + "type": "string", + "example": "simulation" + } + } + }, + "httpapi.PricingEstimateResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true + } + }, + "resolver": { + "type": "string", + "example": "effective-pricing-v1" + } + } + }, + "httpapi.PricingRuleListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.PricingRule" + } + } + } + }, + "httpapi.PricingRuleSetListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.PricingRuleSet" + } + } + } + }, + "httpapi.RateLimitWindowListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.RateLimitWindow" + } + } + } + }, + "httpapi.ReadyResponse": { + "type": "object", + "properties": { + "ok": { + "type": "boolean", + "example": true + } + } + }, + "httpapi.ReplacePlatformModelsRequest": { + "type": "object", + "properties": { + "models": { + "type": "array", + "items": { + "$ref": "#/definitions/store.CreatePlatformModelInput" + } + } + } + }, + "httpapi.RuntimePolicySetListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.RuntimePolicySet" + } + } + } + }, + "httpapi.TaskAcceptedResponse": { + "type": "object", + "properties": { + "next": { + "$ref": "#/definitions/httpapi.TaskNextLinks" + }, + "task": { + "$ref": "#/definitions/store.GatewayTask" + }, + "taskId": { + "type": "string", + "example": "9f4d8f3d-5f5f-4bb7-a4be-344a9f930e25" + } + } + }, + "httpapi.TaskListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.GatewayTask" + } + }, + "page": { + "type": "integer", + "example": 1 + }, + "pageSize": { + "type": "integer", + "example": 50 + }, + "total": { + "type": "integer", + "example": 42 + } + } + }, + "httpapi.TaskNextLinks": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "example": "/api/v1/tasks/9f4d8f3d-5f5f-4bb7-a4be-344a9f930e25" + }, + "events": { + "type": "string", + "example": "/api/v1/tasks/9f4d8f3d-5f5f-4bb7-a4be-344a9f930e25/events" + } + } + }, + "httpapi.TaskParamPreprocessingLogListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.TaskParamPreprocessingLog" + } + } + } + }, + "httpapi.TaskRequest": { + "type": "object", + "properties": { + "duration": { + "type": "integer", + "example": 5 + }, + "input": { + "type": "string", + "example": "Tell me a short story" + }, + "max_tokens": { + "type": "integer", + "example": 512 + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/httpapi.ChatMessage" + } + }, + "model": { + "type": "string", + "example": "gpt-4o-mini" + }, + "prompt": { + "type": "string", + "example": "A watercolor robot reading a book" + }, + "resolution": { + "type": "string", + "example": "720p" + }, + "runMode": { + "type": "string", + "example": "simulation" + }, + "size": { + "type": "string", + "example": "1024x1024" + }, + "stream": { + "type": "boolean", + "example": false + } + } + }, + "httpapi.TenantListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.GatewayTenant" + } + } + } + }, + "httpapi.UserGroupListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.UserGroup" + } + } + } + }, + "httpapi.UserListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.GatewayUser" + } + } + } + }, + "httpapi.WalletAdjustmentResponse": { + "type": "object", + "properties": { + "account": { + "$ref": "#/definitions/store.GatewayWalletAccount" + }, + "auditLog": { + "$ref": "#/definitions/store.AuditLog" + }, + "before": { + "$ref": "#/definitions/store.GatewayWalletAccount" + }, + "transaction": { + "$ref": "#/definitions/store.GatewayWalletTransaction" + } + } + }, + "httpapi.WalletTransactionListResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/store.GatewayWalletTransaction" + } + }, + "page": { + "type": "integer", + "example": 1 + }, + "pageSize": { + "type": "integer", + "example": 50 + }, + "total": { + "type": "integer", + "example": 42 + } + } + }, + "httpapi.updatePlatformDynamicPriorityRequest": { + "type": "object", + "properties": { + "dynamicPriority": { + "type": "integer", + "example": 10 + }, + "reset": { + "type": "boolean", + "example": false + } + } + }, + "httpapi.walletBalanceRequest": { + "type": "object", + "properties": { + "balance": { + "type": "number", + "example": 100 + }, + "currency": { + "type": "string", + "example": "USD" + }, + "idempotencyKey": { + "type": "string", + "example": "wallet-set-20260514-001" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "reason": { + "type": "string", + "example": "manual recharge" + } + } + }, + "store.APIKey": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "expiresAt": { + "type": "string" + }, + "gatewayTenantId": { + "type": "string" + }, + "gatewayUserId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "keyPrefix": { + "type": "string" + }, + "lastUsedAt": { + "type": "string" + }, + "name": { + "type": "string" + }, + "quotaPolicy": { + "type": "object", + "additionalProperties": {} + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "scopes": { + "type": "array", + "items": { + "type": "string" + } + }, + "secret": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tenantId": { + "type": "string" + }, + "tenantKey": { + "type": "string" + }, + "updatedAt": { + "type": "string" + }, + "userGroupId": { + "type": "string" + }, + "userId": { + "type": "string" + } + } + }, + "store.AccessRule": { + "type": "object", + "properties": { + "conditions": { + "type": "object", + "additionalProperties": {} + }, + "createdAt": { + "type": "string" + }, + "effect": { + "type": "string" + }, + "id": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "minPermissionLevel": { + "type": "integer" + }, + "priority": { + "type": "integer" + }, + "resourceId": { + "type": "string" + }, + "resourceType": { + "type": "string" + }, + "status": { + "type": "string" + }, + "subjectId": { + "type": "string" + }, + "subjectType": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "store.AccessRuleBatchInput": { + "type": "object", + "properties": { + "deleteResources": { + "type": "array", + "items": { + "$ref": "#/definitions/store.AccessRuleResourceInput" + } + }, + "effect": { + "type": "string" + }, + "subjectId": { + "type": "string" + }, + "subjectType": { + "type": "string" + }, + "upsertResources": { + "type": "array", + "items": { + "$ref": "#/definitions/store.AccessRuleResourceInput" + } + } + } + }, + "store.AccessRuleInput": { + "type": "object", + "properties": { + "conditions": { + "type": "object", + "additionalProperties": {} + }, + "effect": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "minPermissionLevel": { + "type": "integer" + }, + "priority": { + "type": "integer" + }, + "resourceId": { + "type": "string" + }, + "resourceType": { + "type": "string" + }, + "status": { + "type": "string" + }, + "subjectId": { + "type": "string" + }, + "subjectType": { + "type": "string" + } + } + }, + "store.AccessRuleResourceInput": { + "type": "object", + "properties": { + "conditions": { + "type": "object", + "additionalProperties": {} + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "minPermissionLevel": { + "type": "integer" + }, + "priority": { + "type": "integer" + }, + "resourceId": { + "type": "string" + }, + "resourceType": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "store.AuditLog": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "actorGatewayUserId": { + "type": "string" + }, + "actorRoles": { + "type": "array", + "items": { + "type": "string" + } + }, + "actorSource": { + "type": "string" + }, + "actorUserId": { + "type": "string" + }, + "actorUsername": { + "type": "string" + }, + "afterState": { + "type": "object", + "additionalProperties": {} + }, + "beforeState": { + "type": "object", + "additionalProperties": {} + }, + "category": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "id": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "requestIp": { + "type": "string" + }, + "targetGatewayTenantId": { + "type": "string" + }, + "targetGatewayUserId": { + "type": "string" + }, + "targetId": { + "type": "string" + }, + "targetType": { + "type": "string" + }, + "userAgent": { + "type": "string" + } + } + }, + "store.BaseModel": { + "type": "object", + "properties": { + "baseBillingConfig": { + "type": "object", + "additionalProperties": {} + }, + "canonicalModelKey": { + "type": "string" + }, + "capabilities": { + "type": "object", + "additionalProperties": {} + }, + "catalogType": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "customizedAt": { + "type": "string" + }, + "defaultRateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "defaultSnapshot": { + "type": "object", + "additionalProperties": {} + }, + "id": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "modelAlias": { + "type": "string" + }, + "modelType": { + "type": "array", + "items": { + "type": "string" + } + }, + "pricingRuleSetId": { + "type": "string" + }, + "pricingVersion": { + "type": "integer" + }, + "providerKey": { + "type": "string" + }, + "providerModelName": { + "type": "string" + }, + "runtimePolicyOverride": { + "type": "object", + "additionalProperties": {} + }, + "runtimePolicySetId": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "store.BaseModelInput": { + "type": "object", + "properties": { + "baseBillingConfig": { + "type": "object", + "additionalProperties": {} + }, + "canonicalModelKey": { + "type": "string" + }, + "capabilities": { + "type": "object", + "additionalProperties": {} + }, + "catalogType": { + "type": "string" + }, + "defaultRateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "defaultSnapshot": { + "type": "object", + "additionalProperties": {} + }, + "displayName": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "modelAlias": { + "type": "string" + }, + "modelType": { + "type": "array", + "items": { + "type": "string" + } + }, + "pricingRuleSetId": { + "type": "string" + }, + "pricingVersion": { + "type": "integer" + }, + "providerKey": { + "type": "string" + }, + "providerModelName": { + "type": "string" + }, + "runtimePolicyOverride": { + "type": "object", + "additionalProperties": {} + }, + "runtimePolicySetId": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "store.CatalogProvider": { + "type": "object", + "properties": { + "capabilitySchema": { + "type": "object", + "additionalProperties": {} + }, + "code": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "defaultAuthType": { + "type": "string" + }, + "defaultBaseUrl": { + "type": "string" + }, + "defaultRateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "displayName": { + "type": "string" + }, + "iconPath": { + "type": "string" + }, + "id": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "providerKey": { + "type": "string" + }, + "providerType": { + "type": "string" + }, + "source": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "store.CatalogProviderInput": { + "type": "object", + "properties": { + "capabilitySchema": { + "type": "object", + "additionalProperties": {} + }, + "code": { + "type": "string" + }, + "defaultAuthType": { + "type": "string" + }, + "defaultBaseUrl": { + "type": "string" + }, + "defaultRateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "displayName": { + "type": "string" + }, + "iconPath": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "providerKey": { + "type": "string" + }, + "providerType": { + "type": "string" + }, + "source": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "store.CreateAPIKeyInput": { + "type": "object", + "properties": { + "expiresAt": { + "type": "string" + }, + "name": { + "type": "string" + }, + "scopes": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "store.CreatePlatformInput": { + "type": "object", + "properties": { + "authType": { + "type": "string" + }, + "baseUrl": { + "type": "string" + }, + "config": { + "type": "object", + "additionalProperties": {} + }, + "credentials": { + "type": "object", + "additionalProperties": {} + }, + "defaultDiscountFactor": { + "type": "number" + }, + "defaultPricingMode": { + "type": "string" + }, + "internalName": { + "type": "string" + }, + "name": { + "type": "string" + }, + "platformKey": { + "type": "string" + }, + "pricingRuleSetId": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "provider": { + "type": "string" + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "retryPolicy": { + "type": "object", + "additionalProperties": {} + }, + "status": { + "type": "string" + } + } + }, + "store.CreatePlatformModelInput": { + "type": "object", + "properties": { + "baseModelId": { + "type": "string" + }, + "billingConfig": { + "type": "object", + "additionalProperties": {} + }, + "billingConfigOverride": { + "type": "object", + "additionalProperties": {} + }, + "canonicalModelKey": { + "type": "string" + }, + "capabilities": { + "type": "object", + "additionalProperties": {} + }, + "capabilityOverride": { + "type": "object", + "additionalProperties": {} + }, + "discountFactor": { + "type": "number" + }, + "displayName": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "modelAlias": { + "type": "string" + }, + "modelName": { + "type": "string" + }, + "modelType": { + "type": "array", + "items": { + "type": "string" + } + }, + "permissionConfig": { + "type": "object", + "additionalProperties": {} + }, + "platformId": { + "type": "string" + }, + "pricingMode": { + "type": "string" + }, + "pricingRuleSetId": { + "type": "string" + }, + "providerModelName": { + "type": "string" + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "retryPolicy": { + "type": "object", + "additionalProperties": {} + }, + "runtimePolicyOverride": { + "type": "object", + "additionalProperties": {} + }, + "runtimePolicySetId": { + "type": "string" + } + } + }, + "store.CreatedAPIKey": { + "type": "object", + "properties": { + "apiKey": { + "$ref": "#/definitions/store.APIKey" + }, + "secret": { + "type": "string" + } + } + }, + "store.GatewayTask": { + "type": "object", + "properties": { + "apiKeyId": { + "type": "string" + }, + "apiKeyName": { + "type": "string" + }, + "apiKeyPrefix": { + "type": "string" + }, + "asyncMode": { + "type": "boolean" + }, + "attemptCount": { + "type": "integer" + }, + "attempts": { + "type": "array", + "items": { + "$ref": "#/definitions/store.TaskAttempt" + } + }, + "billingSummary": { + "type": "object", + "additionalProperties": {} + }, + "billings": { + "type": "array", + "items": {} + }, + "createdAt": { + "type": "string" + }, + "error": { + "type": "string" + }, + "errorCode": { + "type": "string" + }, + "errorMessage": { + "type": "string" + }, + "finalChargeAmount": { + "type": "number" + }, + "finishedAt": { + "type": "string" + }, + "gatewayTenantId": { + "type": "string" + }, + "gatewayUserId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metrics": { + "type": "object", + "additionalProperties": {} + }, + "model": { + "type": "string" + }, + "modelType": { + "type": "string" + }, + "remoteTaskId": { + "type": "string" + }, + "remoteTaskPayload": { + "type": "object", + "additionalProperties": {} + }, + "request": { + "type": "object", + "additionalProperties": {} + }, + "requestId": { + "type": "string" + }, + "requestedModel": { + "type": "string" + }, + "resolvedModel": { + "type": "string" + }, + "responseDurationMs": { + "type": "integer" + }, + "responseFinishedAt": { + "type": "string" + }, + "responseStartedAt": { + "type": "string" + }, + "result": { + "type": "object", + "additionalProperties": {} + }, + "riverJobId": { + "type": "integer" + }, + "runMode": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tenantId": { + "type": "string" + }, + "tenantKey": { + "type": "string" + }, + "updatedAt": { + "type": "string" + }, + "usage": { + "type": "object", + "additionalProperties": {} + }, + "userGroupId": { + "type": "string" + }, + "userGroupKey": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "userSource": { + "type": "string" + } + } + }, + "store.GatewayTenant": { + "type": "object", + "properties": { + "authPolicy": { + "type": "object", + "additionalProperties": {} + }, + "billingProfile": { + "type": "object", + "additionalProperties": {} + }, + "createdAt": { + "type": "string" + }, + "defaultUserGroupId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalTenantId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "name": { + "type": "string" + }, + "planKey": { + "type": "string" + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "source": { + "type": "string" + }, + "sourceUpdatedAt": { + "type": "string" + }, + "status": { + "type": "string" + }, + "syncedAt": { + "type": "string" + }, + "tenantKey": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "store.GatewayTenantInput": { + "type": "object", + "properties": { + "authPolicy": { + "type": "object", + "additionalProperties": {} + }, + "billingProfile": { + "type": "object", + "additionalProperties": {} + }, + "defaultUserGroupId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalTenantId": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "name": { + "type": "string" + }, + "planKey": { + "type": "string" + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "source": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tenantKey": { + "type": "string" + } + } + }, + "store.GatewayUser": { + "type": "object", + "properties": { + "authProfile": { + "type": "object", + "additionalProperties": {} + }, + "avatarUrl": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "defaultUserGroupId": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "externalUserId": { + "type": "string" + }, + "gatewayTenantId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "lastLoginAt": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "phone": { + "type": "string" + }, + "roles": { + "type": "array", + "items": { + "type": "string" + } + }, + "source": { + "type": "string" + }, + "sourceUpdatedAt": { + "type": "string" + }, + "status": { + "type": "string" + }, + "syncedAt": { + "type": "string" + }, + "tenantId": { + "type": "string" + }, + "tenantKey": { + "type": "string" + }, + "updatedAt": { + "type": "string" + }, + "userKey": { + "type": "string" + }, + "username": { + "type": "string" + }, + "walletAccounts": { + "type": "array", + "items": { + "$ref": "#/definitions/store.GatewayWalletAccount" + } + } + } + }, + "store.GatewayUserInput": { + "type": "object", + "properties": { + "authProfile": { + "type": "object", + "additionalProperties": {} + }, + "avatarUrl": { + "type": "string" + }, + "defaultUserGroupId": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "externalUserId": { + "type": "string" + }, + "gatewayTenantId": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "password": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "roles": { + "type": "array", + "items": { + "type": "string" + } + }, + "source": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tenantId": { + "type": "string" + }, + "tenantKey": { + "type": "string" + }, + "userKey": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "store.GatewayWalletAccount": { + "type": "object", + "properties": { + "balance": { + "type": "number" + }, + "createdAt": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "frozenBalance": { + "type": "number" + }, + "gatewayTenantId": { + "type": "string" + }, + "gatewayUserId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "status": { + "type": "string" + }, + "tenantId": { + "type": "string" + }, + "tenantKey": { + "type": "string" + }, + "totalRecharged": { + "type": "number" + }, + "totalSpent": { + "type": "number" + }, + "updatedAt": { + "type": "string" + }, + "userId": { + "type": "string" + } + } + }, + "store.GatewayWalletTransaction": { + "type": "object", + "properties": { + "accountId": { + "type": "string" + }, + "amount": { + "type": "number" + }, + "balanceAfter": { + "type": "number" + }, + "balanceBefore": { + "type": "number" + }, + "createdAt": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "direction": { + "type": "string" + }, + "gatewayTenantId": { + "type": "string" + }, + "gatewayUserId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "idempotencyKey": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "referenceId": { + "type": "string" + }, + "referenceType": { + "type": "string" + }, + "transactionType": { + "type": "string" + } + } + }, + "store.LocalLoginInput": { + "type": "object", + "properties": { + "account": { + "type": "string" + }, + "password": { + "type": "string" + } + } + }, + "store.LocalRegisterInput": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "invitationCode": { + "type": "string" + }, + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "store.ModelRateLimitStatus": { + "type": "object", + "properties": { + "concurrent": { + "$ref": "#/definitions/store.RateLimitMetricStatus" + }, + "displayName": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "loadRatio": { + "type": "number" + }, + "modelAlias": { + "type": "string" + }, + "modelCooldownUntil": { + "type": "string" + }, + "modelName": { + "type": "string" + }, + "modelType": { + "type": "array", + "items": { + "type": "string" + } + }, + "platformCooldownUntil": { + "type": "string" + }, + "platformDisabledReason": { + "$ref": "#/definitions/store.PlatformPolicyEvent" + }, + "platformDynamicPriority": { + "type": "integer" + }, + "platformEffectivePriority": { + "type": "integer" + }, + "platformId": { + "type": "string" + }, + "platformModelId": { + "type": "string" + }, + "platformName": { + "type": "string" + }, + "platformPriority": { + "type": "integer" + }, + "platformStatus": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "providerModelName": { + "type": "string" + }, + "queuedTasks": { + "type": "number" + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "recentPriorityDemotions": { + "type": "array", + "items": { + "$ref": "#/definitions/store.PriorityDemotionRecord" + } + }, + "rpm": { + "$ref": "#/definitions/store.RateLimitMetricStatus" + }, + "tpm": { + "$ref": "#/definitions/store.RateLimitMetricStatus" + } + } + }, + "store.Platform": { + "type": "object", + "properties": { + "authType": { + "type": "string" + }, + "baseUrl": { + "type": "string" + }, + "config": { + "type": "object", + "additionalProperties": {} + }, + "cooldownUntil": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "credentialsPreview": { + "type": "object", + "additionalProperties": {} + }, + "defaultDiscountFactor": { + "type": "number" + }, + "defaultPricingMode": { + "type": "string" + }, + "dynamicPriority": { + "type": "integer" + }, + "effectivePriority": { + "type": "integer" + }, + "id": { + "type": "string" + }, + "internalName": { + "type": "string" + }, + "name": { + "type": "string" + }, + "platformKey": { + "type": "string" + }, + "pricingRuleSetId": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "provider": { + "type": "string" + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "retryPolicy": { + "type": "object", + "additionalProperties": {} + }, + "status": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "store.PlatformModel": { + "type": "object", + "properties": { + "baseModelId": { + "type": "string" + }, + "billingConfig": { + "type": "object", + "additionalProperties": {} + }, + "billingConfigOverride": { + "type": "object", + "additionalProperties": {} + }, + "capabilities": { + "type": "object", + "additionalProperties": {} + }, + "capabilityOverride": { + "type": "object", + "additionalProperties": {} + }, + "cooldownUntil": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "discountFactor": { + "type": "number" + }, + "displayName": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "modelAlias": { + "type": "string" + }, + "modelName": { + "type": "string" + }, + "modelType": { + "type": "array", + "items": { + "type": "string" + } + }, + "permissionConfig": { + "type": "object", + "additionalProperties": {} + }, + "platformId": { + "type": "string" + }, + "platformName": { + "type": "string" + }, + "pricingMode": { + "type": "string" + }, + "pricingRuleSetId": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "providerModelName": { + "type": "string" + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "retryPolicy": { + "type": "object", + "additionalProperties": {} + }, + "runtimePolicyOverride": { + "type": "object", + "additionalProperties": {} + }, + "runtimePolicySetId": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "store.PlatformPolicyEvent": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "errorCode": { + "type": "string" + }, + "errorMessage": { + "type": "string" + }, + "eventType": { + "type": "string" + }, + "id": { + "type": "string" + }, + "matchedValue": { + "type": "string" + }, + "platformId": { + "type": "string" + }, + "platformModelId": { + "type": "string" + }, + "policy": { + "type": "string" + }, + "policyRule": { + "type": "string" + }, + "policySource": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "statusCode": { + "type": "integer" + }, + "taskId": { + "type": "string" + } + } + }, + "store.PlayableAPIKey": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "expiresAt": { + "type": "string" + }, + "gatewayTenantId": { + "type": "string" + }, + "gatewayUserId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "keyPrefix": { + "type": "string" + }, + "lastUsedAt": { + "type": "string" + }, + "name": { + "type": "string" + }, + "quotaPolicy": { + "type": "object", + "additionalProperties": {} + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "scopes": { + "type": "array", + "items": { + "type": "string" + } + }, + "secret": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tenantId": { + "type": "string" + }, + "tenantKey": { + "type": "string" + }, + "updatedAt": { + "type": "string" + }, + "userGroupId": { + "type": "string" + }, + "userId": { + "type": "string" + } + } + }, + "store.PricingRule": { + "type": "object", + "properties": { + "basePrice": { + "type": "number" + }, + "baseWeight": { + "type": "object", + "additionalProperties": {} + }, + "calculatorType": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "dimensionSchema": { + "type": "object", + "additionalProperties": {} + }, + "displayName": { + "type": "string" + }, + "dynamicWeight": { + "type": "object", + "additionalProperties": {} + }, + "formulaConfig": { + "type": "object", + "additionalProperties": {} + }, + "id": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "priority": { + "type": "integer" + }, + "resourceType": { + "type": "string" + }, + "ruleKey": { + "type": "string" + }, + "ruleSetId": { + "type": "string" + }, + "scopeId": { + "type": "string" + }, + "scopeType": { + "type": "string" + }, + "status": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "store.PricingRuleInput": { + "type": "object", + "properties": { + "basePrice": { + "type": "number" + }, + "baseWeight": { + "type": "object", + "additionalProperties": {} + }, + "calculatorType": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "dimensionSchema": { + "type": "object", + "additionalProperties": {} + }, + "displayName": { + "type": "string" + }, + "dynamicWeight": { + "type": "object", + "additionalProperties": {} + }, + "formulaConfig": { + "type": "object", + "additionalProperties": {} + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "priority": { + "type": "integer" + }, + "resourceType": { + "type": "string" + }, + "ruleKey": { + "type": "string" + }, + "status": { + "type": "string" + }, + "unit": { + "type": "string" + } + } + }, + "store.PricingRuleSet": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "name": { + "type": "string" + }, + "ruleSetKey": { + "type": "string" + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/store.PricingRule" + } + }, + "status": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "store.PricingRuleSetInput": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "description": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "name": { + "type": "string" + }, + "ruleSetKey": { + "type": "string" + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/store.PricingRuleInput" + } + }, + "status": { + "type": "string" + } + } + }, + "store.PriorityDemotionRecord": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "dynamicPriority": { + "type": "integer" + }, + "errorCode": { + "type": "string" + }, + "errorMessage": { + "type": "string" + }, + "id": { + "type": "string" + }, + "matchedValue": { + "type": "string" + }, + "platformId": { + "type": "string" + }, + "platformModelId": { + "type": "string" + }, + "policy": { + "type": "string" + }, + "policyRule": { + "type": "string" + }, + "policySource": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "statusCode": { + "type": "integer" + }, + "taskId": { + "type": "string" + } + } + }, + "store.RateLimitMetricStatus": { + "type": "object", + "properties": { + "currentValue": { + "type": "number" + }, + "limitValue": { + "type": "number" + }, + "limited": { + "type": "boolean" + }, + "ratio": { + "type": "number" + }, + "reservedValue": { + "type": "number" + }, + "resetAt": { + "type": "string" + }, + "usedValue": { + "type": "number" + } + } + }, + "store.RateLimitWindow": { + "type": "object", + "properties": { + "limitValue": { + "type": "number" + }, + "metric": { + "type": "string" + }, + "reservedValue": { + "type": "number" + }, + "resetAt": { + "type": "string" + }, + "scopeKey": { + "type": "string" + }, + "scopeType": { + "type": "string" + }, + "updatedAt": { + "type": "string" + }, + "usedValue": { + "type": "number" + }, + "windowStart": { + "type": "string" + } + } + }, + "store.RunnerPolicy": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "description": { + "type": "string" + }, + "failoverPolicy": { + "type": "object", + "additionalProperties": {} + }, + "hardStopPolicy": { + "type": "object", + "additionalProperties": {} + }, + "id": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "name": { + "type": "string" + }, + "policyKey": { + "type": "string" + }, + "priorityDemotePolicy": { + "type": "object", + "additionalProperties": {} + }, + "status": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "store.RunnerPolicyInput": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "failoverPolicy": { + "type": "object", + "additionalProperties": {} + }, + "hardStopPolicy": { + "type": "object", + "additionalProperties": {} + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "name": { + "type": "string" + }, + "policyKey": { + "type": "string" + }, + "priorityDemotePolicy": { + "type": "object", + "additionalProperties": {} + }, + "status": { + "type": "string" + } + } + }, + "store.RuntimePolicySet": { + "type": "object", + "properties": { + "autoDisablePolicy": { + "type": "object", + "additionalProperties": {} + }, + "createdAt": { + "type": "string" + }, + "degradePolicy": { + "type": "object", + "additionalProperties": {} + }, + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "name": { + "type": "string" + }, + "policyKey": { + "type": "string" + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "retryPolicy": { + "type": "object", + "additionalProperties": {} + }, + "status": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "store.RuntimePolicySetInput": { + "type": "object", + "properties": { + "autoDisablePolicy": { + "type": "object", + "additionalProperties": {} + }, + "degradePolicy": { + "type": "object", + "additionalProperties": {} + }, + "description": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "name": { + "type": "string" + }, + "policyKey": { + "type": "string" + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "retryPolicy": { + "type": "object", + "additionalProperties": {} + }, + "status": { + "type": "string" + } + } + }, + "store.TaskAttempt": { + "type": "object", + "properties": { + "attemptNo": { + "type": "integer" + }, + "clientId": { + "type": "string" + }, + "errorCode": { + "type": "string" + }, + "errorMessage": { + "type": "string" + }, + "finishedAt": { + "type": "string" + }, + "id": { + "type": "string" + }, + "metrics": { + "type": "object", + "additionalProperties": {} + }, + "modelAlias": { + "type": "string" + }, + "modelName": { + "type": "string" + }, + "modelType": { + "type": "string" + }, + "platformId": { + "type": "string" + }, + "platformModelId": { + "type": "string" + }, + "platformName": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "providerModelName": { + "type": "string" + }, + "queueKey": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "requestSnapshot": { + "type": "object", + "additionalProperties": {} + }, + "responseDurationMs": { + "type": "integer" + }, + "responseFinishedAt": { + "type": "string" + }, + "responseSnapshot": { + "type": "object", + "additionalProperties": {} + }, + "responseStartedAt": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "simulated": { + "type": "boolean" + }, + "startedAt": { + "type": "string" + }, + "status": { + "type": "string" + }, + "statusCode": { + "type": "integer" + }, + "taskId": { + "type": "string" + }, + "usage": { + "type": "object", + "additionalProperties": {} + } + } + }, + "store.TaskParamPreprocessingLog": { + "type": "object", + "properties": { + "actualInput": { + "type": "object", + "additionalProperties": {} + }, + "attemptId": { + "type": "string" + }, + "attemptNo": { + "type": "integer" + }, + "changeCount": { + "type": "integer" + }, + "changed": { + "type": "boolean" + }, + "changes": { + "type": "array", + "items": {} + }, + "clientId": { + "type": "string" + }, + "convertedOutput": { + "type": "object", + "additionalProperties": {} + }, + "createdAt": { + "type": "string" + }, + "id": { + "type": "string" + }, + "model": { + "type": "object", + "additionalProperties": {} + }, + "modelType": { + "type": "string" + }, + "platformId": { + "type": "string" + }, + "platformModelId": { + "type": "string" + }, + "taskId": { + "type": "string" + } + } + }, + "store.UserGroup": { + "type": "object", + "properties": { + "billingDiscountPolicy": { + "type": "object", + "additionalProperties": {} + }, + "createdAt": { + "type": "string" + }, + "description": { + "type": "string" + }, + "groupKey": { + "type": "string" + }, + "id": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "name": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "quotaPolicy": { + "type": "object", + "additionalProperties": {} + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "rechargeDiscountPolicy": { + "type": "object", + "additionalProperties": {} + }, + "source": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "store.UserGroupInput": { + "type": "object", + "properties": { + "billingDiscountPolicy": { + "type": "object", + "additionalProperties": {} + }, + "description": { + "type": "string" + }, + "groupKey": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "name": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "quotaPolicy": { + "type": "object", + "additionalProperties": {} + }, + "rateLimitPolicy": { + "type": "object", + "additionalProperties": {} + }, + "rechargeDiscountPolicy": { + "type": "object", + "additionalProperties": {} + }, + "source": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "store.WalletSummary": { + "type": "object", + "properties": { + "accounts": { + "type": "array", + "items": { + "$ref": "#/definitions/store.GatewayWalletAccount" + } + }, + "primaryAccount": { + "$ref": "#/definitions/store.GatewayWalletAccount" + } + } + } + }, + "securityDefinitions": { + "BearerAuth": { + "description": "Bearer JWT 或 API Key。", + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +} \ No newline at end of file diff --git a/apps/api/docs/swagger.yaml b/apps/api/docs/swagger.yaml new file mode 100644 index 0000000..8e71851 --- /dev/null +++ b/apps/api/docs/swagger.yaml @@ -0,0 +1,5913 @@ +basePath: / +definitions: + auth.User: + properties: + apiKeyId: + type: string + apiKeyName: + type: string + apiKeyPrefix: + type: string + apiKeyScopes: + items: + type: string + type: array + apiKeySecret: + type: string + gatewayTenantId: + type: string + gatewayUserId: + type: string + role: + items: + type: string + type: array + source: + type: string + sso_id: + type: string + sub: + type: string + tenantId: + type: string + tenantKey: + type: string + userGroupId: + type: string + userGroupKey: + type: string + userGroupKeys: + items: + type: string + type: array + username: + type: string + type: object + httpapi.APIKeyListResponse: + properties: + items: + items: + $ref: '#/definitions/store.APIKey' + type: array + type: object + httpapi.AccessRuleListResponse: + properties: + items: + items: + $ref: '#/definitions/store.AccessRule' + type: array + type: object + httpapi.AuditLogListResponse: + properties: + items: + items: + $ref: '#/definitions/store.AuditLog' + type: array + type: object + httpapi.AuthResponse: + properties: + accessToken: + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... + type: string + expiresIn: + example: 86400 + type: integer + tokenType: + example: Bearer + type: string + user: + $ref: '#/definitions/auth.User' + type: object + httpapi.BaseModelListResponse: + properties: + items: + items: + $ref: '#/definitions/store.BaseModel' + type: array + type: object + httpapi.CatalogProviderListResponse: + properties: + items: + items: + $ref: '#/definitions/store.CatalogProvider' + type: array + type: object + httpapi.ChatMessage: + properties: + content: + example: Hello + type: string + role: + example: user + type: string + type: object + httpapi.CompatibleResponse: + properties: + choices: + items: + additionalProperties: true + type: object + type: array + id: + example: chatcmpl-123 + type: string + model: + example: gpt-4o-mini + type: string + object: + example: chat.completion + type: string + usage: + additionalProperties: true + type: object + type: object + httpapi.ErrorEnvelope: + properties: + error: + $ref: '#/definitions/httpapi.ErrorPayload' + type: object + httpapi.ErrorPayload: + properties: + code: + example: rate_limit + type: string + message: + example: invalid json body + type: string + status: + example: 400 + type: integer + type: object + httpapi.HealthResponse: + properties: + env: + example: development + type: string + identityMode: + example: standalone + type: string + ok: + example: true + type: boolean + service: + example: easyai-ai-gateway + type: string + type: object + httpapi.ModelCatalogFilterOption: + properties: + count: + type: integer + iconPath: + type: string + label: + type: string + value: + type: string + type: object + httpapi.ModelCatalogFilters: + properties: + capabilities: + items: + $ref: '#/definitions/httpapi.ModelCatalogFilterOption' + type: array + providers: + items: + $ref: '#/definitions/httpapi.ModelCatalogFilterOption' + type: array + type: object + httpapi.ModelCatalogItem: + properties: + alias: + type: string + capabilityTags: + items: + type: string + type: array + description: + type: string + discount: + $ref: '#/definitions/httpapi.ModelCatalogText' + displayName: + type: string + enabled: + type: boolean + iconPath: + type: string + id: + type: string + modelName: + type: string + modelType: + items: + type: string + type: array + permission: + $ref: '#/definitions/httpapi.ModelCatalogPermission' + pricing: + $ref: '#/definitions/httpapi.ModelCatalogPricing' + providerKeys: + items: + type: string + type: array + providers: + items: + $ref: '#/definitions/httpapi.ModelCatalogProviderSummary' + type: array + rateLimits: + $ref: '#/definitions/httpapi.ModelCatalogRateLimits' + source: + $ref: '#/definitions/httpapi.ModelCatalogText' + sourceCount: + type: integer + sources: + items: + $ref: '#/definitions/httpapi.ModelCatalogSource' + type: array + statusLabel: + type: string + type: object + httpapi.ModelCatalogPermission: + properties: + allowGroups: + items: + type: string + type: array + denyGroups: + items: + type: string + type: array + label: + type: string + title: + type: string + type: object + httpapi.ModelCatalogPricing: + properties: + lines: + items: + type: string + type: array + title: + type: string + type: object + httpapi.ModelCatalogProviderSummary: + properties: + iconPath: + type: string + key: + type: string + name: + type: string + sourceCount: + type: integer + type: object + httpapi.ModelCatalogRateLimits: + properties: + concurrent: + type: number + label: + type: string + rpm: + type: number + title: + type: string + tpm: + type: number + type: object + httpapi.ModelCatalogResponse: + properties: + filters: + $ref: '#/definitions/httpapi.ModelCatalogFilters' + items: + items: + $ref: '#/definitions/httpapi.ModelCatalogItem' + type: array + summary: + $ref: '#/definitions/httpapi.ModelCatalogSummary' + type: object + httpapi.ModelCatalogSource: + properties: + displayName: + type: string + enabled: + type: boolean + id: + type: string + modelAlias: + type: string + modelName: + type: string + modelType: + items: + type: string + type: array + platformId: + type: string + platformName: + type: string + providerKey: + type: string + providerName: + type: string + rateLimits: + $ref: '#/definitions/httpapi.ModelCatalogRateLimits' + type: object + httpapi.ModelCatalogSummary: + properties: + modelCount: + type: integer + sourceCount: + type: integer + type: object + httpapi.ModelCatalogText: + properties: + label: + type: string + title: + type: string + type: object + httpapi.ModelRateLimitStatusListResponse: + properties: + items: + items: + $ref: '#/definitions/store.ModelRateLimitStatus' + type: array + type: object + httpapi.NetworkProxyConfigResponse: + properties: + globalHttpProxy: + example: http://127.0.0.1:7890 + type: string + globalHttpProxySet: + example: true + type: boolean + globalHttpProxySource: + example: env + type: string + type: object + httpapi.PlatformListResponse: + properties: + items: + items: + $ref: '#/definitions/store.Platform' + type: array + type: object + httpapi.PlatformModelListResponse: + properties: + items: + items: + $ref: '#/definitions/store.PlatformModel' + type: array + type: object + httpapi.PlayableAPIKeyListResponse: + properties: + items: + items: + $ref: '#/definitions/store.PlayableAPIKey' + type: array + type: object + httpapi.PricingEstimateRequest: + properties: + kind: + example: chat.completions + type: string + max_tokens: + example: 512 + type: integer + messages: + items: + $ref: '#/definitions/httpapi.ChatMessage' + type: array + model: + example: gpt-4o-mini + type: string + "n": + example: 1 + type: integer + prompt: + example: A small orange cat + type: string + runMode: + example: simulation + type: string + type: object + httpapi.PricingEstimateResponse: + properties: + items: + items: + additionalProperties: true + type: object + type: array + resolver: + example: effective-pricing-v1 + type: string + type: object + httpapi.PricingRuleListResponse: + properties: + items: + items: + $ref: '#/definitions/store.PricingRule' + type: array + type: object + httpapi.PricingRuleSetListResponse: + properties: + items: + items: + $ref: '#/definitions/store.PricingRuleSet' + type: array + type: object + httpapi.RateLimitWindowListResponse: + properties: + items: + items: + $ref: '#/definitions/store.RateLimitWindow' + type: array + type: object + httpapi.ReadyResponse: + properties: + ok: + example: true + type: boolean + type: object + httpapi.ReplacePlatformModelsRequest: + properties: + models: + items: + $ref: '#/definitions/store.CreatePlatformModelInput' + type: array + type: object + httpapi.RuntimePolicySetListResponse: + properties: + items: + items: + $ref: '#/definitions/store.RuntimePolicySet' + type: array + type: object + httpapi.TaskAcceptedResponse: + properties: + next: + $ref: '#/definitions/httpapi.TaskNextLinks' + task: + $ref: '#/definitions/store.GatewayTask' + taskId: + example: 9f4d8f3d-5f5f-4bb7-a4be-344a9f930e25 + type: string + type: object + httpapi.TaskListResponse: + properties: + items: + items: + $ref: '#/definitions/store.GatewayTask' + type: array + page: + example: 1 + type: integer + pageSize: + example: 50 + type: integer + total: + example: 42 + type: integer + type: object + httpapi.TaskNextLinks: + properties: + detail: + example: /api/v1/tasks/9f4d8f3d-5f5f-4bb7-a4be-344a9f930e25 + type: string + events: + example: /api/v1/tasks/9f4d8f3d-5f5f-4bb7-a4be-344a9f930e25/events + type: string + type: object + httpapi.TaskParamPreprocessingLogListResponse: + properties: + items: + items: + $ref: '#/definitions/store.TaskParamPreprocessingLog' + type: array + type: object + httpapi.TaskRequest: + properties: + duration: + example: 5 + type: integer + input: + example: Tell me a short story + type: string + max_tokens: + example: 512 + type: integer + messages: + items: + $ref: '#/definitions/httpapi.ChatMessage' + type: array + model: + example: gpt-4o-mini + type: string + prompt: + example: A watercolor robot reading a book + type: string + resolution: + example: 720p + type: string + runMode: + example: simulation + type: string + size: + example: 1024x1024 + type: string + stream: + example: false + type: boolean + type: object + httpapi.TenantListResponse: + properties: + items: + items: + $ref: '#/definitions/store.GatewayTenant' + type: array + type: object + httpapi.UserGroupListResponse: + properties: + items: + items: + $ref: '#/definitions/store.UserGroup' + type: array + type: object + httpapi.UserListResponse: + properties: + items: + items: + $ref: '#/definitions/store.GatewayUser' + type: array + type: object + httpapi.WalletAdjustmentResponse: + properties: + account: + $ref: '#/definitions/store.GatewayWalletAccount' + auditLog: + $ref: '#/definitions/store.AuditLog' + before: + $ref: '#/definitions/store.GatewayWalletAccount' + transaction: + $ref: '#/definitions/store.GatewayWalletTransaction' + type: object + httpapi.WalletTransactionListResponse: + properties: + items: + items: + $ref: '#/definitions/store.GatewayWalletTransaction' + type: array + page: + example: 1 + type: integer + pageSize: + example: 50 + type: integer + total: + example: 42 + type: integer + type: object + httpapi.updatePlatformDynamicPriorityRequest: + properties: + dynamicPriority: + example: 10 + type: integer + reset: + example: false + type: boolean + type: object + httpapi.walletBalanceRequest: + properties: + balance: + example: 100 + type: number + currency: + example: USD + type: string + idempotencyKey: + example: wallet-set-20260514-001 + type: string + metadata: + additionalProperties: {} + type: object + reason: + example: manual recharge + type: string + type: object + store.APIKey: + properties: + createdAt: + type: string + expiresAt: + type: string + gatewayTenantId: + type: string + gatewayUserId: + type: string + id: + type: string + keyPrefix: + type: string + lastUsedAt: + type: string + name: + type: string + quotaPolicy: + additionalProperties: {} + type: object + rateLimitPolicy: + additionalProperties: {} + type: object + scopes: + items: + type: string + type: array + secret: + type: string + status: + type: string + tenantId: + type: string + tenantKey: + type: string + updatedAt: + type: string + userGroupId: + type: string + userId: + type: string + type: object + store.AccessRule: + properties: + conditions: + additionalProperties: {} + type: object + createdAt: + type: string + effect: + type: string + id: + type: string + metadata: + additionalProperties: {} + type: object + minPermissionLevel: + type: integer + priority: + type: integer + resourceId: + type: string + resourceType: + type: string + status: + type: string + subjectId: + type: string + subjectType: + type: string + updatedAt: + type: string + type: object + store.AccessRuleBatchInput: + properties: + deleteResources: + items: + $ref: '#/definitions/store.AccessRuleResourceInput' + type: array + effect: + type: string + subjectId: + type: string + subjectType: + type: string + upsertResources: + items: + $ref: '#/definitions/store.AccessRuleResourceInput' + type: array + type: object + store.AccessRuleInput: + properties: + conditions: + additionalProperties: {} + type: object + effect: + type: string + metadata: + additionalProperties: {} + type: object + minPermissionLevel: + type: integer + priority: + type: integer + resourceId: + type: string + resourceType: + type: string + status: + type: string + subjectId: + type: string + subjectType: + type: string + type: object + store.AccessRuleResourceInput: + properties: + conditions: + additionalProperties: {} + type: object + metadata: + additionalProperties: {} + type: object + minPermissionLevel: + type: integer + priority: + type: integer + resourceId: + type: string + resourceType: + type: string + status: + type: string + type: object + store.AuditLog: + properties: + action: + type: string + actorGatewayUserId: + type: string + actorRoles: + items: + type: string + type: array + actorSource: + type: string + actorUserId: + type: string + actorUsername: + type: string + afterState: + additionalProperties: {} + type: object + beforeState: + additionalProperties: {} + type: object + category: + type: string + createdAt: + type: string + id: + type: string + metadata: + additionalProperties: {} + type: object + requestIp: + type: string + targetGatewayTenantId: + type: string + targetGatewayUserId: + type: string + targetId: + type: string + targetType: + type: string + userAgent: + type: string + type: object + store.BaseModel: + properties: + baseBillingConfig: + additionalProperties: {} + type: object + canonicalModelKey: + type: string + capabilities: + additionalProperties: {} + type: object + catalogType: + type: string + createdAt: + type: string + customizedAt: + type: string + defaultRateLimitPolicy: + additionalProperties: {} + type: object + defaultSnapshot: + additionalProperties: {} + type: object + id: + type: string + metadata: + additionalProperties: {} + type: object + modelAlias: + type: string + modelType: + items: + type: string + type: array + pricingRuleSetId: + type: string + pricingVersion: + type: integer + providerKey: + type: string + providerModelName: + type: string + runtimePolicyOverride: + additionalProperties: {} + type: object + runtimePolicySetId: + type: string + status: + type: string + updatedAt: + type: string + type: object + store.BaseModelInput: + properties: + baseBillingConfig: + additionalProperties: {} + type: object + canonicalModelKey: + type: string + capabilities: + additionalProperties: {} + type: object + catalogType: + type: string + defaultRateLimitPolicy: + additionalProperties: {} + type: object + defaultSnapshot: + additionalProperties: {} + type: object + displayName: + type: string + metadata: + additionalProperties: {} + type: object + modelAlias: + type: string + modelType: + items: + type: string + type: array + pricingRuleSetId: + type: string + pricingVersion: + type: integer + providerKey: + type: string + providerModelName: + type: string + runtimePolicyOverride: + additionalProperties: {} + type: object + runtimePolicySetId: + type: string + status: + type: string + type: object + store.CatalogProvider: + properties: + capabilitySchema: + additionalProperties: {} + type: object + code: + type: string + createdAt: + type: string + defaultAuthType: + type: string + defaultBaseUrl: + type: string + defaultRateLimitPolicy: + additionalProperties: {} + type: object + displayName: + type: string + iconPath: + type: string + id: + type: string + metadata: + additionalProperties: {} + type: object + providerKey: + type: string + providerType: + type: string + source: + type: string + status: + type: string + updatedAt: + type: string + type: object + store.CatalogProviderInput: + properties: + capabilitySchema: + additionalProperties: {} + type: object + code: + type: string + defaultAuthType: + type: string + defaultBaseUrl: + type: string + defaultRateLimitPolicy: + additionalProperties: {} + type: object + displayName: + type: string + iconPath: + type: string + metadata: + additionalProperties: {} + type: object + providerKey: + type: string + providerType: + type: string + source: + type: string + status: + type: string + type: object + store.CreateAPIKeyInput: + properties: + expiresAt: + type: string + name: + type: string + scopes: + items: + type: string + type: array + type: object + store.CreatePlatformInput: + properties: + authType: + type: string + baseUrl: + type: string + config: + additionalProperties: {} + type: object + credentials: + additionalProperties: {} + type: object + defaultDiscountFactor: + type: number + defaultPricingMode: + type: string + internalName: + type: string + name: + type: string + platformKey: + type: string + pricingRuleSetId: + type: string + priority: + type: integer + provider: + type: string + rateLimitPolicy: + additionalProperties: {} + type: object + retryPolicy: + additionalProperties: {} + type: object + status: + type: string + type: object + store.CreatePlatformModelInput: + properties: + baseModelId: + type: string + billingConfig: + additionalProperties: {} + type: object + billingConfigOverride: + additionalProperties: {} + type: object + canonicalModelKey: + type: string + capabilities: + additionalProperties: {} + type: object + capabilityOverride: + additionalProperties: {} + type: object + discountFactor: + type: number + displayName: + type: string + enabled: + type: boolean + modelAlias: + type: string + modelName: + type: string + modelType: + items: + type: string + type: array + permissionConfig: + additionalProperties: {} + type: object + platformId: + type: string + pricingMode: + type: string + pricingRuleSetId: + type: string + providerModelName: + type: string + rateLimitPolicy: + additionalProperties: {} + type: object + retryPolicy: + additionalProperties: {} + type: object + runtimePolicyOverride: + additionalProperties: {} + type: object + runtimePolicySetId: + type: string + type: object + store.CreatedAPIKey: + properties: + apiKey: + $ref: '#/definitions/store.APIKey' + secret: + type: string + type: object + store.GatewayTask: + properties: + apiKeyId: + type: string + apiKeyName: + type: string + apiKeyPrefix: + type: string + asyncMode: + type: boolean + attemptCount: + type: integer + attempts: + items: + $ref: '#/definitions/store.TaskAttempt' + type: array + billingSummary: + additionalProperties: {} + type: object + billings: + items: {} + type: array + createdAt: + type: string + error: + type: string + errorCode: + type: string + errorMessage: + type: string + finalChargeAmount: + type: number + finishedAt: + type: string + gatewayTenantId: + type: string + gatewayUserId: + type: string + id: + type: string + kind: + type: string + metrics: + additionalProperties: {} + type: object + model: + type: string + modelType: + type: string + remoteTaskId: + type: string + remoteTaskPayload: + additionalProperties: {} + type: object + request: + additionalProperties: {} + type: object + requestId: + type: string + requestedModel: + type: string + resolvedModel: + type: string + responseDurationMs: + type: integer + responseFinishedAt: + type: string + responseStartedAt: + type: string + result: + additionalProperties: {} + type: object + riverJobId: + type: integer + runMode: + type: string + status: + type: string + tenantId: + type: string + tenantKey: + type: string + updatedAt: + type: string + usage: + additionalProperties: {} + type: object + userGroupId: + type: string + userGroupKey: + type: string + userId: + type: string + userSource: + type: string + type: object + store.GatewayTenant: + properties: + authPolicy: + additionalProperties: {} + type: object + billingProfile: + additionalProperties: {} + type: object + createdAt: + type: string + defaultUserGroupId: + type: string + description: + type: string + externalTenantId: + type: string + id: + type: string + metadata: + additionalProperties: {} + type: object + name: + type: string + planKey: + type: string + rateLimitPolicy: + additionalProperties: {} + type: object + source: + type: string + sourceUpdatedAt: + type: string + status: + type: string + syncedAt: + type: string + tenantKey: + type: string + updatedAt: + type: string + type: object + store.GatewayTenantInput: + properties: + authPolicy: + additionalProperties: {} + type: object + billingProfile: + additionalProperties: {} + type: object + defaultUserGroupId: + type: string + description: + type: string + externalTenantId: + type: string + metadata: + additionalProperties: {} + type: object + name: + type: string + planKey: + type: string + rateLimitPolicy: + additionalProperties: {} + type: object + source: + type: string + status: + type: string + tenantKey: + type: string + type: object + store.GatewayUser: + properties: + authProfile: + additionalProperties: {} + type: object + avatarUrl: + type: string + createdAt: + type: string + defaultUserGroupId: + type: string + displayName: + type: string + email: + type: string + externalUserId: + type: string + gatewayTenantId: + type: string + id: + type: string + lastLoginAt: + type: string + metadata: + additionalProperties: {} + type: object + phone: + type: string + roles: + items: + type: string + type: array + source: + type: string + sourceUpdatedAt: + type: string + status: + type: string + syncedAt: + type: string + tenantId: + type: string + tenantKey: + type: string + updatedAt: + type: string + userKey: + type: string + username: + type: string + walletAccounts: + items: + $ref: '#/definitions/store.GatewayWalletAccount' + type: array + type: object + store.GatewayUserInput: + properties: + authProfile: + additionalProperties: {} + type: object + avatarUrl: + type: string + defaultUserGroupId: + type: string + displayName: + type: string + email: + type: string + externalUserId: + type: string + gatewayTenantId: + type: string + metadata: + additionalProperties: {} + type: object + password: + type: string + phone: + type: string + roles: + items: + type: string + type: array + source: + type: string + status: + type: string + tenantId: + type: string + tenantKey: + type: string + userKey: + type: string + username: + type: string + type: object + store.GatewayWalletAccount: + properties: + balance: + type: number + createdAt: + type: string + currency: + type: string + frozenBalance: + type: number + gatewayTenantId: + type: string + gatewayUserId: + type: string + id: + type: string + metadata: + additionalProperties: {} + type: object + status: + type: string + tenantId: + type: string + tenantKey: + type: string + totalRecharged: + type: number + totalSpent: + type: number + updatedAt: + type: string + userId: + type: string + type: object + store.GatewayWalletTransaction: + properties: + accountId: + type: string + amount: + type: number + balanceAfter: + type: number + balanceBefore: + type: number + createdAt: + type: string + currency: + type: string + direction: + type: string + gatewayTenantId: + type: string + gatewayUserId: + type: string + id: + type: string + idempotencyKey: + type: string + metadata: + additionalProperties: {} + type: object + referenceId: + type: string + referenceType: + type: string + transactionType: + type: string + type: object + store.LocalLoginInput: + properties: + account: + type: string + password: + type: string + type: object + store.LocalRegisterInput: + properties: + displayName: + type: string + email: + type: string + invitationCode: + type: string + password: + type: string + username: + type: string + type: object + store.ModelRateLimitStatus: + properties: + concurrent: + $ref: '#/definitions/store.RateLimitMetricStatus' + displayName: + type: string + enabled: + type: boolean + loadRatio: + type: number + modelAlias: + type: string + modelCooldownUntil: + type: string + modelName: + type: string + modelType: + items: + type: string + type: array + platformCooldownUntil: + type: string + platformDisabledReason: + $ref: '#/definitions/store.PlatformPolicyEvent' + platformDynamicPriority: + type: integer + platformEffectivePriority: + type: integer + platformId: + type: string + platformModelId: + type: string + platformName: + type: string + platformPriority: + type: integer + platformStatus: + type: string + provider: + type: string + providerModelName: + type: string + queuedTasks: + type: number + rateLimitPolicy: + additionalProperties: {} + type: object + recentPriorityDemotions: + items: + $ref: '#/definitions/store.PriorityDemotionRecord' + type: array + rpm: + $ref: '#/definitions/store.RateLimitMetricStatus' + tpm: + $ref: '#/definitions/store.RateLimitMetricStatus' + type: object + store.Platform: + properties: + authType: + type: string + baseUrl: + type: string + config: + additionalProperties: {} + type: object + cooldownUntil: + type: string + createdAt: + type: string + credentialsPreview: + additionalProperties: {} + type: object + defaultDiscountFactor: + type: number + defaultPricingMode: + type: string + dynamicPriority: + type: integer + effectivePriority: + type: integer + id: + type: string + internalName: + type: string + name: + type: string + platformKey: + type: string + pricingRuleSetId: + type: string + priority: + type: integer + provider: + type: string + rateLimitPolicy: + additionalProperties: {} + type: object + retryPolicy: + additionalProperties: {} + type: object + status: + type: string + updatedAt: + type: string + type: object + store.PlatformModel: + properties: + baseModelId: + type: string + billingConfig: + additionalProperties: {} + type: object + billingConfigOverride: + additionalProperties: {} + type: object + capabilities: + additionalProperties: {} + type: object + capabilityOverride: + additionalProperties: {} + type: object + cooldownUntil: + type: string + createdAt: + type: string + discountFactor: + type: number + displayName: + type: string + enabled: + type: boolean + id: + type: string + modelAlias: + type: string + modelName: + type: string + modelType: + items: + type: string + type: array + permissionConfig: + additionalProperties: {} + type: object + platformId: + type: string + platformName: + type: string + pricingMode: + type: string + pricingRuleSetId: + type: string + provider: + type: string + providerModelName: + type: string + rateLimitPolicy: + additionalProperties: {} + type: object + retryPolicy: + additionalProperties: {} + type: object + runtimePolicyOverride: + additionalProperties: {} + type: object + runtimePolicySetId: + type: string + updatedAt: + type: string + type: object + store.PlatformPolicyEvent: + properties: + category: + type: string + createdAt: + type: string + errorCode: + type: string + errorMessage: + type: string + eventType: + type: string + id: + type: string + matchedValue: + type: string + platformId: + type: string + platformModelId: + type: string + policy: + type: string + policyRule: + type: string + policySource: + type: string + reason: + type: string + statusCode: + type: integer + taskId: + type: string + type: object + store.PlayableAPIKey: + properties: + createdAt: + type: string + expiresAt: + type: string + gatewayTenantId: + type: string + gatewayUserId: + type: string + id: + type: string + keyPrefix: + type: string + lastUsedAt: + type: string + name: + type: string + quotaPolicy: + additionalProperties: {} + type: object + rateLimitPolicy: + additionalProperties: {} + type: object + scopes: + items: + type: string + type: array + secret: + type: string + status: + type: string + tenantId: + type: string + tenantKey: + type: string + updatedAt: + type: string + userGroupId: + type: string + userId: + type: string + type: object + store.PricingRule: + properties: + basePrice: + type: number + baseWeight: + additionalProperties: {} + type: object + calculatorType: + type: string + createdAt: + type: string + currency: + type: string + dimensionSchema: + additionalProperties: {} + type: object + displayName: + type: string + dynamicWeight: + additionalProperties: {} + type: object + formulaConfig: + additionalProperties: {} + type: object + id: + type: string + metadata: + additionalProperties: {} + type: object + priority: + type: integer + resourceType: + type: string + ruleKey: + type: string + ruleSetId: + type: string + scopeId: + type: string + scopeType: + type: string + status: + type: string + unit: + type: string + updatedAt: + type: string + type: object + store.PricingRuleInput: + properties: + basePrice: + type: number + baseWeight: + additionalProperties: {} + type: object + calculatorType: + type: string + currency: + type: string + dimensionSchema: + additionalProperties: {} + type: object + displayName: + type: string + dynamicWeight: + additionalProperties: {} + type: object + formulaConfig: + additionalProperties: {} + type: object + metadata: + additionalProperties: {} + type: object + priority: + type: integer + resourceType: + type: string + ruleKey: + type: string + status: + type: string + unit: + type: string + type: object + store.PricingRuleSet: + properties: + category: + type: string + createdAt: + type: string + currency: + type: string + description: + type: string + id: + type: string + metadata: + additionalProperties: {} + type: object + name: + type: string + ruleSetKey: + type: string + rules: + items: + $ref: '#/definitions/store.PricingRule' + type: array + status: + type: string + updatedAt: + type: string + type: object + store.PricingRuleSetInput: + properties: + category: + type: string + currency: + type: string + description: + type: string + metadata: + additionalProperties: {} + type: object + name: + type: string + ruleSetKey: + type: string + rules: + items: + $ref: '#/definitions/store.PricingRuleInput' + type: array + status: + type: string + type: object + store.PriorityDemotionRecord: + properties: + category: + type: string + createdAt: + type: string + dynamicPriority: + type: integer + errorCode: + type: string + errorMessage: + type: string + id: + type: string + matchedValue: + type: string + platformId: + type: string + platformModelId: + type: string + policy: + type: string + policyRule: + type: string + policySource: + type: string + reason: + type: string + statusCode: + type: integer + taskId: + type: string + type: object + store.RateLimitMetricStatus: + properties: + currentValue: + type: number + limitValue: + type: number + limited: + type: boolean + ratio: + type: number + reservedValue: + type: number + resetAt: + type: string + usedValue: + type: number + type: object + store.RateLimitWindow: + properties: + limitValue: + type: number + metric: + type: string + reservedValue: + type: number + resetAt: + type: string + scopeKey: + type: string + scopeType: + type: string + updatedAt: + type: string + usedValue: + type: number + windowStart: + type: string + type: object + store.RunnerPolicy: + properties: + createdAt: + type: string + description: + type: string + failoverPolicy: + additionalProperties: {} + type: object + hardStopPolicy: + additionalProperties: {} + type: object + id: + type: string + metadata: + additionalProperties: {} + type: object + name: + type: string + policyKey: + type: string + priorityDemotePolicy: + additionalProperties: {} + type: object + status: + type: string + updatedAt: + type: string + type: object + store.RunnerPolicyInput: + properties: + description: + type: string + failoverPolicy: + additionalProperties: {} + type: object + hardStopPolicy: + additionalProperties: {} + type: object + metadata: + additionalProperties: {} + type: object + name: + type: string + policyKey: + type: string + priorityDemotePolicy: + additionalProperties: {} + type: object + status: + type: string + type: object + store.RuntimePolicySet: + properties: + autoDisablePolicy: + additionalProperties: {} + type: object + createdAt: + type: string + degradePolicy: + additionalProperties: {} + type: object + description: + type: string + id: + type: string + metadata: + additionalProperties: {} + type: object + name: + type: string + policyKey: + type: string + rateLimitPolicy: + additionalProperties: {} + type: object + retryPolicy: + additionalProperties: {} + type: object + status: + type: string + updatedAt: + type: string + type: object + store.RuntimePolicySetInput: + properties: + autoDisablePolicy: + additionalProperties: {} + type: object + degradePolicy: + additionalProperties: {} + type: object + description: + type: string + metadata: + additionalProperties: {} + type: object + name: + type: string + policyKey: + type: string + rateLimitPolicy: + additionalProperties: {} + type: object + retryPolicy: + additionalProperties: {} + type: object + status: + type: string + type: object + store.TaskAttempt: + properties: + attemptNo: + type: integer + clientId: + type: string + errorCode: + type: string + errorMessage: + type: string + finishedAt: + type: string + id: + type: string + metrics: + additionalProperties: {} + type: object + modelAlias: + type: string + modelName: + type: string + modelType: + type: string + platformId: + type: string + platformModelId: + type: string + platformName: + type: string + provider: + type: string + providerModelName: + type: string + queueKey: + type: string + requestId: + type: string + requestSnapshot: + additionalProperties: {} + type: object + responseDurationMs: + type: integer + responseFinishedAt: + type: string + responseSnapshot: + additionalProperties: {} + type: object + responseStartedAt: + type: string + retryable: + type: boolean + simulated: + type: boolean + startedAt: + type: string + status: + type: string + statusCode: + type: integer + taskId: + type: string + usage: + additionalProperties: {} + type: object + type: object + store.TaskParamPreprocessingLog: + properties: + actualInput: + additionalProperties: {} + type: object + attemptId: + type: string + attemptNo: + type: integer + changeCount: + type: integer + changed: + type: boolean + changes: + items: {} + type: array + clientId: + type: string + convertedOutput: + additionalProperties: {} + type: object + createdAt: + type: string + id: + type: string + model: + additionalProperties: {} + type: object + modelType: + type: string + platformId: + type: string + platformModelId: + type: string + taskId: + type: string + type: object + store.UserGroup: + properties: + billingDiscountPolicy: + additionalProperties: {} + type: object + createdAt: + type: string + description: + type: string + groupKey: + type: string + id: + type: string + metadata: + additionalProperties: {} + type: object + name: + type: string + priority: + type: integer + quotaPolicy: + additionalProperties: {} + type: object + rateLimitPolicy: + additionalProperties: {} + type: object + rechargeDiscountPolicy: + additionalProperties: {} + type: object + source: + type: string + status: + type: string + updatedAt: + type: string + type: object + store.UserGroupInput: + properties: + billingDiscountPolicy: + additionalProperties: {} + type: object + description: + type: string + groupKey: + type: string + metadata: + additionalProperties: {} + type: object + name: + type: string + priority: + type: integer + quotaPolicy: + additionalProperties: {} + type: object + rateLimitPolicy: + additionalProperties: {} + type: object + rechargeDiscountPolicy: + additionalProperties: {} + type: object + source: + type: string + status: + type: string + type: object + store.WalletSummary: + properties: + accounts: + items: + $ref: '#/definitions/store.GatewayWalletAccount' + type: array + primaryAccount: + $ref: '#/definitions/store.GatewayWalletAccount' + type: object +info: + contact: {} + description: |- + EasyAI AI Gateway 的本地鉴权、平台模型管理、定价、运行策略、钱包和 AI 任务接口。 + 受保护接口使用 Authorization: Bearer ,管理接口只接受 JWT 用户凭证。 + title: EasyAI AI Gateway API + version: 0.1.0 +paths: + /api/admin/access-rules: + get: + description: 管理端返回用户组、租户、用户或 API Key 到平台、平台模型、基础模型的访问规则。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.AccessRuleListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出访问规则 + tags: + - access-rules + post: + consumes: + - application/json + description: 管理端创建一条访问控制规则。 + parameters: + - description: 访问规则请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.AccessRuleInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/store.AccessRule' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建访问规则 + tags: + - access-rules + /api/admin/access-rules/{ruleID}: + delete: + description: 管理端删除一条访问控制规则。 + parameters: + - description: 访问规则 ID + in: path + name: ruleID + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 删除访问规则 + tags: + - access-rules + patch: + consumes: + - application/json + description: 管理端更新一条访问控制规则。 + parameters: + - description: 访问规则 ID + in: path + name: ruleID + required: true + type: string + - description: 访问规则请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.AccessRuleInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.AccessRule' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 更新访问规则 + tags: + - access-rules + /api/admin/access-rules/batch: + post: + consumes: + - application/json + description: 管理端为同一主体批量新增、更新或删除资源访问规则。 + parameters: + - description: 访问规则批量请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.AccessRuleBatchInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.AccessRuleListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 批量写入访问规则 + tags: + - access-rules + /api/admin/audit-logs: + get: + description: 管理端按分类、动作、目标类型和目标 ID 查询审计日志。 + parameters: + - description: 审计分类 + in: query + name: category + type: string + - description: 审计动作 + in: query + name: action + type: string + - description: 目标类型 + in: query + name: targetType + type: string + - description: 目标 ID + in: query + name: targetId + type: string + - default: 100 + description: 返回数量 + in: query + name: limit + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.AuditLogListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出审计日志 + tags: + - billing + /api/admin/catalog/base-models: + get: + description: 返回基础模型目录;公共路径和管理路径返回同一结构。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.BaseModelListResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + summary: 列出基础模型 + tags: + - catalog + post: + consumes: + - application/json + description: 管理端新增基础模型目录项,providerKey、providerModelName 和 modelType 必填。 + parameters: + - description: 基础模型请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.BaseModelInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/store.BaseModel' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建基础模型 + tags: + - catalog + /api/admin/catalog/base-models/{baseModelID}: + delete: + description: 管理端删除基础模型目录项。 + parameters: + - description: 基础模型 ID + in: path + name: baseModelID + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 删除基础模型 + tags: + - catalog + patch: + consumes: + - application/json + description: 管理端更新基础模型目录项及能力、图标、默认快照等元数据。 + parameters: + - description: 基础模型 ID + in: path + name: baseModelID + required: true + type: string + - description: 基础模型请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.BaseModelInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.BaseModel' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 更新基础模型 + tags: + - catalog + /api/admin/catalog/base-models/{baseModelID}/reset: + post: + description: 将指定基础模型恢复为系统默认快照;无默认快照时返回 409。 + parameters: + - description: 基础模型 ID + in: path + name: baseModelID + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.BaseModel' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 重置基础模型 + tags: + - catalog + /api/admin/catalog/base-models/reset-all: + post: + description: 将所有具备系统默认快照的基础模型恢复为默认配置。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.BaseModelListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 重置全部基础模型 + tags: + - catalog + /api/admin/catalog/providers: + get: + description: 返回模型目录使用的供应商元数据;公共路径和管理路径返回同一结构。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CatalogProviderListResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + summary: 列出目录供应商 + tags: + - catalog + post: + consumes: + - application/json + description: 管理端新增模型目录供应商,providerKey 和 displayName 必填。 + parameters: + - description: 目录供应商请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.CatalogProviderInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/store.CatalogProvider' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建目录供应商 + tags: + - catalog + /api/admin/catalog/providers/{providerID}: + delete: + description: 管理端删除目录供应商。 + parameters: + - description: 目录供应商 ID + in: path + name: providerID + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 删除目录供应商 + tags: + - catalog + patch: + consumes: + - application/json + description: 管理端更新目录供应商展示信息、图标和元数据。 + parameters: + - description: 目录供应商 ID + in: path + name: providerID + required: true + type: string + - description: 目录供应商请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.CatalogProviderInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.CatalogProvider' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 更新目录供应商 + tags: + - catalog + /api/admin/config/network-proxy: + get: + description: 管理端查看服务当前使用的全局 HTTP 代理配置及来源。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.NetworkProxyConfigResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 获取网络代理配置 + tags: + - config + /api/admin/models: + get: + description: 管理端返回所有平台模型,并补齐有效计费配置。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.PlatformModelListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出平台模型 + tags: + - platform-models + /api/admin/platform-models: + post: + consumes: + - application/json + description: 为平台新增一个可路由模型;路径中的 platformID 会覆盖请求体 platformId。 + parameters: + - description: 平台模型配置请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.CreatePlatformModelInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/store.PlatformModel' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建平台模型 + tags: + - platform-models + /api/admin/platform-models/{modelID}: + delete: + description: 删除指定平台模型路由配置。 + parameters: + - description: 平台模型 ID + in: path + name: modelID + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 删除平台模型 + tags: + - platform-models + /api/admin/platforms: + get: + description: 管理端返回所有接入平台及其优先级、定价和运行策略摘要。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.PlatformListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出平台 + tags: + - platforms + post: + consumes: + - application/json + description: 新增模型供应商平台配置;credentials 会被服务端保存并在返回值中脱敏。 + parameters: + - description: 平台配置请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.CreatePlatformInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/store.Platform' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建平台 + tags: + - platforms + /api/admin/platforms/{platformID}: + delete: + description: 删除指定平台及关联配置;不存在时返回 404。 + parameters: + - description: 平台 ID + in: path + name: platformID + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 删除平台 + tags: + - platforms + patch: + consumes: + - application/json + description: 覆盖指定平台的基础配置、凭证、优先级、定价和运行策略。 + parameters: + - description: 平台 ID + in: path + name: platformID + required: true + type: string + - description: 平台配置请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.CreatePlatformInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.Platform' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 更新平台 + tags: + - platforms + /api/admin/platforms/{platformID}/dynamic-priority: + patch: + consumes: + - application/json + description: 管理端调整平台运行时动态优先级;reset 为 true 时清空动态值。 + parameters: + - description: 平台 ID + in: path + name: platformID + required: true + type: string + - description: 动态优先级请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.updatePlatformDynamicPriorityRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.Platform' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 更新平台动态优先级 + tags: + - runtime + /api/admin/platforms/{platformID}/models: + post: + consumes: + - application/json + description: 为平台新增一个可路由模型;路径中的 platformID 会覆盖请求体 platformId。 + parameters: + - description: 平台 ID,使用 /api/admin/platforms/{platformID}/models 时由路径提供 + in: path + name: platformID + required: true + type: string + - description: 平台模型配置请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.CreatePlatformModelInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/store.PlatformModel' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建平台模型 + tags: + - platform-models + put: + consumes: + - application/json + description: 用请求体中的 models 列表整体替换指定平台下的模型配置。 + parameters: + - description: 平台 ID + in: path + name: platformID + required: true + type: string + - description: 模型列表请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.ReplacePlatformModelsRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.PlatformModelListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 替换平台模型 + tags: + - platform-models + /api/admin/pricing/rule-sets: + get: + description: 管理端返回可分配给平台、模型、租户或用户组的定价规则集。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.PricingRuleSetListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出定价规则集 + tags: + - pricing + post: + consumes: + - application/json + description: 管理端创建定价规则集,ruleSetKey、name 和至少一条 rule 必填。 + parameters: + - description: 定价规则集请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.PricingRuleSetInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/store.PricingRuleSet' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建定价规则集 + tags: + - pricing + /api/admin/pricing/rule-sets/{ruleSetID}: + delete: + description: 管理端删除非默认定价规则集;默认规则集受保护。 + parameters: + - description: 定价规则集 ID + in: path + name: ruleSetID + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 删除定价规则集 + tags: + - pricing + patch: + consumes: + - application/json + description: 管理端更新定价规则集及其规则列表。 + parameters: + - description: 定价规则集 ID + in: path + name: ruleSetID + required: true + type: string + - description: 定价规则集请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.PricingRuleSetInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.PricingRuleSet' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 更新定价规则集 + tags: + - pricing + /api/admin/pricing/rules: + get: + description: 返回所有定价规则明细,便于管理端排查有效价格。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.PricingRuleListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出定价规则 + tags: + - pricing + /api/admin/runtime/model-rate-limits: + get: + description: 管理端查看平台模型维度的限流和冷却状态。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.ModelRateLimitStatusListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出模型限流状态 + tags: + - runtime + /api/admin/runtime/policy-sets: + get: + description: 管理端返回可分配给平台、模型或用户组的运行策略集。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.RuntimePolicySetListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出运行策略集 + tags: + - runtime + post: + consumes: + - application/json + description: 管理端创建运行策略集,policyKey 和 name 必填。 + parameters: + - description: 运行策略集请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.RuntimePolicySetInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/store.RuntimePolicySet' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建运行策略集 + tags: + - runtime + /api/admin/runtime/policy-sets/{policySetID}: + delete: + description: 管理端删除非默认运行策略集;默认策略集受保护。 + parameters: + - description: 运行策略集 ID + in: path + name: policySetID + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 删除运行策略集 + tags: + - runtime + patch: + consumes: + - application/json + description: 管理端更新运行策略集及其限流、重试、超时等策略配置。 + parameters: + - description: 运行策略集 ID + in: path + name: policySetID + required: true + type: string + - description: 运行策略集请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.RuntimePolicySetInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.RuntimePolicySet' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 更新运行策略集 + tags: + - runtime + /api/admin/runtime/rate-limit-windows: + get: + description: 管理端查看当前运行时限流窗口状态。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.RateLimitWindowListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出限流窗口 + tags: + - runtime + /api/admin/runtime/runner-policy: + get: + description: 管理端获取当前生效的默认 Runner 调度策略。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.RunnerPolicy' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 获取 Runner 策略 + tags: + - runtime + patch: + consumes: + - application/json + description: 管理端写入默认 Runner 调度策略。 + parameters: + - description: Runner 策略请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.RunnerPolicyInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.RunnerPolicy' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 更新 Runner 策略 + tags: + - runtime + /api/admin/tenants: + get: + description: 管理端返回网关租户列表。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.TenantListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出租户 + tags: + - identity + post: + consumes: + - application/json + description: 管理端创建网关租户,tenantKey 和 name 必填。 + parameters: + - description: 租户请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.GatewayTenantInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/store.GatewayTenant' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建租户 + tags: + - identity + /api/admin/tenants/{tenantID}: + delete: + description: 管理端删除网关租户。 + parameters: + - description: 租户 ID + in: path + name: tenantID + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 删除租户 + tags: + - identity + patch: + consumes: + - application/json + description: 管理端更新网关租户信息。 + parameters: + - description: 租户 ID + in: path + name: tenantID + required: true + type: string + - description: 租户请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.GatewayTenantInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.GatewayTenant' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 更新租户 + tags: + - identity + /api/admin/user-groups: + get: + description: 管理端返回用户组及其计费、限流和配额策略。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.UserGroupListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出用户组 + tags: + - identity + post: + consumes: + - application/json + description: 管理端创建用户组,可配置默认定价、运行策略、限流和配额策略。 + parameters: + - description: 用户组请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.UserGroupInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/store.UserGroup' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建用户组 + tags: + - identity + /api/admin/user-groups/{groupID}: + delete: + description: 管理端删除用户组。 + parameters: + - description: 用户组 ID + in: path + name: groupID + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 删除用户组 + tags: + - identity + patch: + consumes: + - application/json + description: 管理端更新用户组基础信息和策略配置。 + parameters: + - description: 用户组 ID + in: path + name: groupID + required: true + type: string + - description: 用户组请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.UserGroupInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.UserGroup' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 更新用户组 + tags: + - identity + /api/admin/users: + get: + description: 管理端返回网关用户列表及钱包摘要。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.UserListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出用户 + tags: + - identity + post: + consumes: + - application/json + description: 管理端创建网关用户;password 为空时不设置本地密码,非空时至少 8 位。 + parameters: + - description: 用户请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.GatewayUserInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/store.GatewayUser' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建用户 + tags: + - identity + /api/admin/users/{userID}: + delete: + description: 管理端删除网关用户。 + parameters: + - description: 用户 ID + in: path + name: userID + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 删除用户 + tags: + - identity + patch: + consumes: + - application/json + description: 管理端更新网关用户资料、角色、默认用户组和可选本地密码。 + parameters: + - description: 用户 ID + in: path + name: userID + required: true + type: string + - description: 用户请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.GatewayUserInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.GatewayUser' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 更新用户 + tags: + - identity + /api/admin/users/{userID}/wallet: + patch: + consumes: + - application/json + description: 管理端把指定用户钱包余额调整到目标值,并记录审计日志;balance 不允许为负数。 + parameters: + - description: 用户 ID + in: path + name: userID + required: true + type: string + - description: 钱包余额设置请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.walletBalanceRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.WalletAdjustmentResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 设置用户钱包余额 + tags: + - billing + /api/playground/api-keys: + get: + description: 返回当前本地用户可在 Playground 中直接使用的 API Key 和 secret。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.PlayableAPIKeyListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出 Playground API Key + tags: + - playground + /api/v1/api-keys: + get: + description: 返回当前用户创建的 API Key 元数据,secret 只在创建时返回。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.APIKeyListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出 API Key + tags: + - api-keys + post: + consumes: + - application/json + description: 为当前本地用户创建 API Key;secret 仅在本次响应中返回。 + parameters: + - description: API Key 创建请求 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.CreateAPIKeyInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/store.CreatedAPIKey' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建 API Key + tags: + - api-keys + /api/v1/api-keys/{apiKeyID}: + delete: + description: 删除当前用户拥有的 API Key。 + parameters: + - description: API Key ID + in: path + name: apiKeyID + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 删除 API Key + tags: + - api-keys + /api/v1/api-keys/{apiKeyID}/disable: + patch: + description: 禁用当前用户拥有的 API Key,保留记录但不再允许调用。 + parameters: + - description: API Key ID + in: path + name: apiKeyID + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.APIKey' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 禁用 API Key + tags: + - api-keys + /api/v1/api-keys/access-rules: + get: + description: 返回当前本地用户可管理的 API Key 访问规则。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.AccessRuleListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出 API Key 访问规则 + tags: + - api-keys + /api/v1/api-keys/access-rules/batch: + post: + consumes: + - application/json + description: 当前本地用户为自己的 API Key 批量新增、更新或删除可访问资源。 + parameters: + - description: API Key 访问规则批量请求,subjectType 必须为 api_key + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.AccessRuleBatchInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.AccessRuleListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 批量写入 API Key 访问规则 + tags: + - api-keys + /api/v1/auth/login: + post: + consumes: + - application/json + description: 使用用户名或邮箱登录本地账号,并返回 24 小时 JWT。 + parameters: + - description: 登录请求,account 可为用户名或邮箱 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.LocalLoginInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.AuthResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + summary: 本地登录 + tags: + - auth + /api/v1/auth/register: + post: + consumes: + - application/json + description: 在 standalone 或 hybrid 身份模式下创建本地用户,并返回 24 小时 JWT。 + parameters: + - description: 注册请求,password 至少 8 位,invitationCode 取决于部署策略 + in: body + name: input + required: true + schema: + $ref: '#/definitions/store.LocalRegisterInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/httpapi.AuthResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "409": + description: Conflict + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + summary: 本地注册 + tags: + - auth + /api/v1/chat/completions: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks + /api/v1/images/edits: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks + /api/v1/images/generations: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks + /api/v1/me: + get: + description: 返回鉴权中解析出的用户、租户、用户组和 API Key 上下文。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/auth.User' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 获取当前用户 + tags: + - auth + /api/v1/model-catalog: + get: + description: 聚合平台模型、基础模型、供应商、运行策略和访问规则,返回前端模型目录所需的过滤器、摘要和展示字段。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.ModelCatalogResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出模型目录 + tags: + - model-catalog + /api/v1/models: + get: + description: 按当前用户权限返回可用于 Playground 或 API 调用的模型列表。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.PlatformModelListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出可调用模型 + tags: + - playground + /api/v1/platforms: + get: + description: 按当前用户可访问模型过滤平台,仅返回启用且存在可访问模型的平台。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.PlatformListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出可用平台 + tags: + - playground + /api/v1/playground/models: + get: + description: 按当前用户权限返回可用于 Playground 或 API 调用的模型列表。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.PlatformModelListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出可调用模型 + tags: + - playground + /api/v1/pricing/estimate: + post: + consumes: + - application/json + description: 按当前用户、模型候选、任务类型和请求参数估算计费条目。 + parameters: + - description: 计费估算请求,kind 默认为 chat.completions + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.PricingEstimateRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.PricingEstimateResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 估算请求价格 + tags: + - pricing + /api/v1/public/catalog/base-models: + get: + description: 返回基础模型目录;公共路径和管理路径返回同一结构。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.BaseModelListResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + summary: 列出基础模型 + tags: + - catalog + /api/v1/public/catalog/providers: + get: + description: 返回模型目录使用的供应商元数据;公共路径和管理路径返回同一结构。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CatalogProviderListResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + summary: 列出目录供应商 + tags: + - catalog + /api/v1/responses: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks + /api/v1/tasks: + get: + description: 按当前用户列出任务,支持关键字、模型类型、时间范围和分页过滤。 + parameters: + - description: 搜索关键字,别名 query + in: query + name: q + type: string + - description: 模型类型,别名 type + in: query + name: modelType + type: string + - description: 创建时间起点,支持 RFC3339 或日期格式,别名 from + in: query + name: createdFrom + type: string + - description: 创建时间终点,支持 RFC3339 或日期格式,别名 to + in: query + name: createdTo + type: string + - default: 1 + description: 页码 + in: query + name: page + type: integer + - default: 50 + description: 每页数量,别名 limit + in: query + name: pageSize + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.TaskListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出任务 + tags: + - tasks + /api/v1/tasks/{taskID}: + get: + description: 返回指定任务的请求、状态、输出和执行摘要。 + parameters: + - description: 任务 ID + in: path + name: taskID + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.GatewayTask' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 获取任务详情 + tags: + - tasks + /api/v1/tasks/{taskID}/events: + get: + description: 以 text/event-stream 返回指定任务的历史事件;无事件时返回 task.accepted 占位事件。 + parameters: + - description: 任务 ID + in: path + name: taskID + required: true + type: string + produces: + - text/event-stream + responses: + "200": + description: Server-Sent Events,data 为 store.TaskEvent 或 TaskAcceptedEvent + schema: + type: string + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 订阅任务事件 + tags: + - tasks + /api/v1/tasks/{taskID}/param-preprocessing: + get: + description: 返回指定任务在执行前的参数改写、校验或模板处理日志。 + parameters: + - description: 任务 ID + in: path + name: taskID + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.TaskParamPreprocessingLogListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 获取任务参数预处理日志 + tags: + - tasks + /api/v1/videos/generations: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks + /api/workspace/tasks: + get: + description: 按当前用户列出任务,支持关键字、模型类型、时间范围和分页过滤。 + parameters: + - description: 搜索关键字,别名 query + in: query + name: q + type: string + - description: 模型类型,别名 type + in: query + name: modelType + type: string + - description: 创建时间起点,支持 RFC3339 或日期格式,别名 from + in: query + name: createdFrom + type: string + - description: 创建时间终点,支持 RFC3339 或日期格式,别名 to + in: query + name: createdTo + type: string + - default: 1 + description: 页码 + in: query + name: page + type: integer + - default: 50 + description: 每页数量,别名 limit + in: query + name: pageSize + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.TaskListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出任务 + tags: + - tasks + /api/workspace/tasks/{taskID}: + get: + description: 返回指定任务的请求、状态、输出和执行摘要。 + parameters: + - description: 任务 ID + in: path + name: taskID + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.GatewayTask' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 获取任务详情 + tags: + - tasks + /api/workspace/tasks/{taskID}/events: + get: + description: 以 text/event-stream 返回指定任务的历史事件;无事件时返回 task.accepted 占位事件。 + parameters: + - description: 任务 ID + in: path + name: taskID + required: true + type: string + produces: + - text/event-stream + responses: + "200": + description: Server-Sent Events,data 为 store.TaskEvent 或 TaskAcceptedEvent + schema: + type: string + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 订阅任务事件 + tags: + - tasks + /api/workspace/tasks/{taskID}/param-preprocessing: + get: + description: 返回指定任务在执行前的参数改写、校验或模板处理日志。 + parameters: + - description: 任务 ID + in: path + name: taskID + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.TaskParamPreprocessingLogListResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 获取任务参数预处理日志 + tags: + - tasks + /api/workspace/wallet: + get: + description: 返回当前用户的钱包账户、余额和最近消费摘要,可按 currency 过滤。 + parameters: + - default: USD + description: 币种 + in: query + name: currency + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.WalletSummary' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 获取钱包摘要 + tags: + - wallet + /api/workspace/wallet/transactions: + get: + description: 返回当前用户的钱包交易流水,支持关键字、方向、交易类型、时间范围和分页过滤。 + parameters: + - description: 搜索关键字,别名 query + in: query + name: q + type: string + - description: 交易方向 + in: query + name: direction + type: string + - description: 交易类型 + in: query + name: transactionType + type: string + - description: 创建时间起点,别名 from + in: query + name: createdFrom + type: string + - description: 创建时间终点,别名 to + in: query + name: createdTo + type: string + - default: 1 + description: 页码 + in: query + name: page + type: integer + - default: 50 + description: 每页数量,别名 limit + in: query + name: pageSize + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.WalletTransactionListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 列出钱包交易 + tags: + - wallet + /chat/completions: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks + /healthz: + get: + description: 返回服务进程、运行环境和身份模式,供负载均衡或人工排障使用。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.HealthResponse' + summary: 健康检查 + tags: + - system + /images/edits: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks + /images/generations: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks + /readyz: + get: + description: 检查 Postgres 是否可用;数据库不可用时返回 503。 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.ReadyResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + summary: 就绪检查 + tags: + - system + /responses: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks + /static/simulation/{asset}: + get: + description: 返回本地模拟模式使用的图片、视频封面或短视频资源。 + parameters: + - description: 资源文件名,可选 image.svg、image.png、image-edit.svg、image-edit.png、video-poster.svg、video.mp4 + in: path + name: asset + required: true + type: string + produces: + - image/svg+xml + - video/mp4 + responses: + "200": + description: OK + schema: + type: file + "404": + description: Not Found + schema: + type: string + summary: 获取模拟资源 + tags: + - simulation + /v1/chat/completions: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks + /v1/images/edits: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks + /v1/images/generations: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks + /v1/responses: + post: + consumes: + - application/json + description: 网关任务接口按 model 选择平台模型;/api/v1 路径返回任务受理结果,OpenAI-compatible 路径同步返回兼容响应或 + SSE 流。 + parameters: + - description: true 时异步创建任务并返回 202 + in: header + name: X-Async + type: boolean + - description: AI 任务请求,字段随任务类型变化 + in: body + name: input + required: true + schema: + $ref: '#/definitions/httpapi.TaskRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/httpapi.CompatibleResponse' + "202": + description: Accepted + schema: + $ref: '#/definitions/httpapi.TaskAcceptedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "402": + description: Payment Required + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "403": + description: Forbidden + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "404": + description: Not Found + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/httpapi.ErrorEnvelope' + security: + - BearerAuth: [] + summary: 创建或执行 AI 任务 + tags: + - tasks +schemes: +- http +- https +securityDefinitions: + BearerAuth: + description: Bearer JWT 或 API Key。 + in: header + name: Authorization + type: apiKey +swagger: "2.0" diff --git a/apps/api/internal/httpapi/access_rule_handlers.go b/apps/api/internal/httpapi/access_rule_handlers.go index d75d13f..2062818 100644 --- a/apps/api/internal/httpapi/access_rule_handlers.go +++ b/apps/api/internal/httpapi/access_rule_handlers.go @@ -10,6 +10,17 @@ import ( "github.com/easyai/easyai-ai-gateway/apps/api/internal/store" ) +// listAccessRules godoc +// @Summary 列出访问规则 +// @Description 管理端返回用户组、租户、用户或 API Key 到平台、平台模型、基础模型的访问规则。 +// @Tags access-rules +// @Produce json +// @Security BearerAuth +// @Success 200 {object} AccessRuleListResponse +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/access-rules [get] func (s *Server) listAccessRules(w http.ResponseWriter, r *http.Request) { items, err := s.store.ListAccessRules(r.Context()) if err != nil { @@ -20,6 +31,17 @@ func (s *Server) listAccessRules(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{"items": items}) } +// listAPIKeyAccessRules godoc +// @Summary 列出 API Key 访问规则 +// @Description 返回当前本地用户可管理的 API Key 访问规则。 +// @Tags api-keys +// @Produce json +// @Security BearerAuth +// @Success 200 {object} AccessRuleListResponse +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/v1/api-keys/access-rules [get] func (s *Server) listAPIKeyAccessRules(w http.ResponseWriter, r *http.Request) { user, _ := auth.UserFromContext(r.Context()) items, err := s.store.ListAPIKeyAccessRules(r.Context(), user) @@ -35,6 +57,21 @@ func (s *Server) listAPIKeyAccessRules(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{"items": items}) } +// createAccessRule godoc +// @Summary 创建访问规则 +// @Description 管理端创建一条访问控制规则。 +// @Tags access-rules +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param input body store.AccessRuleInput true "访问规则请求" +// @Success 201 {object} store.AccessRule +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 409 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/access-rules [post] func (s *Server) createAccessRule(w http.ResponseWriter, r *http.Request) { var input store.AccessRuleInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -58,6 +95,20 @@ func (s *Server) createAccessRule(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusCreated, item) } +// batchAccessRules godoc +// @Summary 批量写入访问规则 +// @Description 管理端为同一主体批量新增、更新或删除资源访问规则。 +// @Tags access-rules +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param input body store.AccessRuleBatchInput true "访问规则批量请求" +// @Success 200 {object} AccessRuleListResponse +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/access-rules/batch [post] func (s *Server) batchAccessRules(w http.ResponseWriter, r *http.Request) { var input store.AccessRuleBatchInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -77,6 +128,21 @@ func (s *Server) batchAccessRules(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{"items": items}) } +// batchAPIKeyAccessRules godoc +// @Summary 批量写入 API Key 访问规则 +// @Description 当前本地用户为自己的 API Key 批量新增、更新或删除可访问资源。 +// @Tags api-keys +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param input body store.AccessRuleBatchInput true "API Key 访问规则批量请求,subjectType 必须为 api_key" +// @Success 200 {object} AccessRuleListResponse +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 404 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/v1/api-keys/access-rules/batch [post] func (s *Server) batchAPIKeyAccessRules(w http.ResponseWriter, r *http.Request) { user, _ := auth.UserFromContext(r.Context()) var input store.AccessRuleBatchInput @@ -109,6 +175,23 @@ func (s *Server) batchAPIKeyAccessRules(w http.ResponseWriter, r *http.Request) writeJSON(w, http.StatusOK, map[string]any{"items": items}) } +// updateAccessRule godoc +// @Summary 更新访问规则 +// @Description 管理端更新一条访问控制规则。 +// @Tags access-rules +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param ruleID path string true "访问规则 ID" +// @Param input body store.AccessRuleInput true "访问规则请求" +// @Success 200 {object} store.AccessRule +// @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/access-rules/{ruleID} [patch] func (s *Server) updateAccessRule(w http.ResponseWriter, r *http.Request) { var input store.AccessRuleInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -136,6 +219,19 @@ func (s *Server) updateAccessRule(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, item) } +// deleteAccessRule godoc +// @Summary 删除访问规则 +// @Description 管理端删除一条访问控制规则。 +// @Tags access-rules +// @Produce json +// @Security BearerAuth +// @Param ruleID 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/access-rules/{ruleID} [delete] func (s *Server) deleteAccessRule(w http.ResponseWriter, r *http.Request) { if err := s.store.DeleteAccessRule(r.Context(), r.PathValue("ruleID")); err != nil { if store.IsNotFound(err) { diff --git a/apps/api/internal/httpapi/billing_admin_handlers.go b/apps/api/internal/httpapi/billing_admin_handlers.go index 90f0f60..ac10a96 100644 --- a/apps/api/internal/httpapi/billing_admin_handlers.go +++ b/apps/api/internal/httpapi/billing_admin_handlers.go @@ -12,13 +12,29 @@ import ( ) type walletBalanceRequest struct { - Currency string `json:"currency"` - Balance float64 `json:"balance"` - Reason string `json:"reason"` - IdempotencyKey string `json:"idempotencyKey"` + Currency string `json:"currency" example:"USD"` + Balance float64 `json:"balance" example:"100"` + Reason string `json:"reason" example:"manual recharge"` + IdempotencyKey string `json:"idempotencyKey" example:"wallet-set-20260514-001"` Metadata map[string]any `json:"metadata"` } +// setUserWalletBalance godoc +// @Summary 设置用户钱包余额 +// @Description 管理端把指定用户钱包余额调整到目标值,并记录审计日志;balance 不允许为负数。 +// @Tags billing +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param userID path string true "用户 ID" +// @Param input body walletBalanceRequest true "钱包余额设置请求" +// @Success 200 {object} WalletAdjustmentResponse +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 404 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/users/{userID}/wallet [patch] func (s *Server) setUserWalletBalance(w http.ResponseWriter, r *http.Request) { actor, _ := auth.UserFromContext(r.Context()) var input walletBalanceRequest @@ -79,6 +95,23 @@ func (s *Server) setUserWalletBalance(w http.ResponseWriter, r *http.Request) { }) } +// listAuditLogs godoc +// @Summary 列出审计日志 +// @Description 管理端按分类、动作、目标类型和目标 ID 查询审计日志。 +// @Tags billing +// @Produce json +// @Security BearerAuth +// @Param category query string false "审计分类" +// @Param action query string false "审计动作" +// @Param targetType query string false "目标类型" +// @Param targetId query string false "目标 ID" +// @Param limit query int false "返回数量" default(100) +// @Success 200 {object} AuditLogListResponse +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/audit-logs [get] func (s *Server) listAuditLogs(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() limit, err := positiveQueryInt(query.Get("limit"), 100) diff --git a/apps/api/internal/httpapi/catalog_handlers.go b/apps/api/internal/httpapi/catalog_handlers.go index db88c12..3affb97 100644 --- a/apps/api/internal/httpapi/catalog_handlers.go +++ b/apps/api/internal/httpapi/catalog_handlers.go @@ -9,6 +9,15 @@ import ( "github.com/easyai/easyai-ai-gateway/apps/api/internal/store" ) +// listCatalogProviders godoc +// @Summary 列出目录供应商 +// @Description 返回模型目录使用的供应商元数据;公共路径和管理路径返回同一结构。 +// @Tags catalog +// @Produce json +// @Success 200 {object} CatalogProviderListResponse +// @Failure 500 {object} ErrorEnvelope +// @Router /api/v1/public/catalog/providers [get] +// @Router /api/admin/catalog/providers [get] func (s *Server) listCatalogProviders(w http.ResponseWriter, r *http.Request) { items, err := s.store.ListCatalogProviders(r.Context()) if err != nil { @@ -19,6 +28,21 @@ func (s *Server) listCatalogProviders(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{"items": items}) } +// createCatalogProvider godoc +// @Summary 创建目录供应商 +// @Description 管理端新增模型目录供应商,providerKey 和 displayName 必填。 +// @Tags catalog +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param input body store.CatalogProviderInput true "目录供应商请求" +// @Success 201 {object} store.CatalogProvider +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 409 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/catalog/providers [post] func (s *Server) createCatalogProvider(w http.ResponseWriter, r *http.Request) { var input store.CatalogProviderInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -42,6 +66,23 @@ func (s *Server) createCatalogProvider(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusCreated, item) } +// updateCatalogProvider godoc +// @Summary 更新目录供应商 +// @Description 管理端更新目录供应商展示信息、图标和元数据。 +// @Tags catalog +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param providerID path string true "目录供应商 ID" +// @Param input body store.CatalogProviderInput true "目录供应商请求" +// @Success 200 {object} store.CatalogProvider +// @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/catalog/providers/{providerID} [patch] func (s *Server) updateCatalogProvider(w http.ResponseWriter, r *http.Request) { var input store.CatalogProviderInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -69,6 +110,19 @@ func (s *Server) updateCatalogProvider(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, item) } +// deleteCatalogProvider godoc +// @Summary 删除目录供应商 +// @Description 管理端删除目录供应商。 +// @Tags catalog +// @Produce json +// @Security BearerAuth +// @Param providerID 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/catalog/providers/{providerID} [delete] func (s *Server) deleteCatalogProvider(w http.ResponseWriter, r *http.Request) { if err := s.store.DeleteCatalogProvider(r.Context(), r.PathValue("providerID")); err != nil { if store.IsNotFound(err) { @@ -82,6 +136,15 @@ func (s *Server) deleteCatalogProvider(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) } +// listBaseModels godoc +// @Summary 列出基础模型 +// @Description 返回基础模型目录;公共路径和管理路径返回同一结构。 +// @Tags catalog +// @Produce json +// @Success 200 {object} BaseModelListResponse +// @Failure 500 {object} ErrorEnvelope +// @Router /api/v1/public/catalog/base-models [get] +// @Router /api/admin/catalog/base-models [get] func (s *Server) listBaseModels(w http.ResponseWriter, r *http.Request) { items, err := s.store.ListBaseModels(r.Context()) if err != nil { @@ -92,6 +155,21 @@ func (s *Server) listBaseModels(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{"items": items}) } +// createBaseModel godoc +// @Summary 创建基础模型 +// @Description 管理端新增基础模型目录项,providerKey、providerModelName 和 modelType 必填。 +// @Tags catalog +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param input body store.BaseModelInput true "基础模型请求" +// @Success 201 {object} store.BaseModel +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 409 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/catalog/base-models [post] func (s *Server) createBaseModel(w http.ResponseWriter, r *http.Request) { var input store.BaseModelInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -115,6 +193,23 @@ func (s *Server) createBaseModel(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusCreated, item) } +// updateBaseModel godoc +// @Summary 更新基础模型 +// @Description 管理端更新基础模型目录项及能力、图标、默认快照等元数据。 +// @Tags catalog +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param baseModelID path string true "基础模型 ID" +// @Param input body store.BaseModelInput true "基础模型请求" +// @Success 200 {object} store.BaseModel +// @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/catalog/base-models/{baseModelID} [patch] func (s *Server) updateBaseModel(w http.ResponseWriter, r *http.Request) { var input store.BaseModelInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -142,6 +237,20 @@ func (s *Server) updateBaseModel(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, item) } +// resetBaseModel godoc +// @Summary 重置基础模型 +// @Description 将指定基础模型恢复为系统默认快照;无默认快照时返回 409。 +// @Tags catalog +// @Produce json +// @Security BearerAuth +// @Param baseModelID path string true "基础模型 ID" +// @Success 200 {object} store.BaseModel +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 404 {object} ErrorEnvelope +// @Failure 409 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/catalog/base-models/{baseModelID}/reset [post] func (s *Server) resetBaseModel(w http.ResponseWriter, r *http.Request) { item, err := s.store.ResetBaseModelToDefault(r.Context(), r.PathValue("baseModelID")) if err != nil { @@ -160,6 +269,17 @@ func (s *Server) resetBaseModel(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, item) } +// resetAllBaseModels godoc +// @Summary 重置全部基础模型 +// @Description 将所有具备系统默认快照的基础模型恢复为默认配置。 +// @Tags catalog +// @Produce json +// @Security BearerAuth +// @Success 200 {object} BaseModelListResponse +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/catalog/base-models/reset-all [post] func (s *Server) resetAllBaseModels(w http.ResponseWriter, r *http.Request) { items, err := s.store.ResetAllBaseModelsToDefault(r.Context()) if err != nil { @@ -170,6 +290,19 @@ func (s *Server) resetAllBaseModels(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{"items": items}) } +// deleteBaseModel godoc +// @Summary 删除基础模型 +// @Description 管理端删除基础模型目录项。 +// @Tags catalog +// @Produce json +// @Security BearerAuth +// @Param baseModelID 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/catalog/base-models/{baseModelID} [delete] func (s *Server) deleteBaseModel(w http.ResponseWriter, r *http.Request) { if err := s.store.DeleteBaseModel(r.Context(), r.PathValue("baseModelID")); err != nil { if store.IsNotFound(err) { diff --git a/apps/api/internal/httpapi/config_handlers.go b/apps/api/internal/httpapi/config_handlers.go index 8c4d4ab..abb3b11 100644 --- a/apps/api/internal/httpapi/config_handlers.go +++ b/apps/api/internal/httpapi/config_handlers.go @@ -5,6 +5,16 @@ import ( "strings" ) +// getNetworkProxyConfig godoc +// @Summary 获取网络代理配置 +// @Description 管理端查看服务当前使用的全局 HTTP 代理配置及来源。 +// @Tags config +// @Produce json +// @Security BearerAuth +// @Success 200 {object} NetworkProxyConfigResponse +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Router /api/admin/config/network-proxy [get] func (s *Server) getNetworkProxyConfig(w http.ResponseWriter, r *http.Request) { globalHTTPProxy := strings.TrimSpace(s.cfg.GlobalHTTPProxy) writeJSON(w, http.StatusOK, map[string]any{ diff --git a/apps/api/internal/httpapi/handlers.go b/apps/api/internal/httpapi/handlers.go index a8ea8de..21f3916 100644 --- a/apps/api/internal/httpapi/handlers.go +++ b/apps/api/internal/httpapi/handlers.go @@ -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()) @@ -877,6 +1233,24 @@ func matchedRateLimitRule(policy map[string]any, metric string) map[string]any { return nil } +// 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 { @@ -972,6 +1346,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 { @@ -986,6 +1373,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 { @@ -1006,6 +1406,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 { diff --git a/apps/api/internal/httpapi/identity_admin_handlers.go b/apps/api/internal/httpapi/identity_admin_handlers.go index 1c06d4a..e285c89 100644 --- a/apps/api/internal/httpapi/identity_admin_handlers.go +++ b/apps/api/internal/httpapi/identity_admin_handlers.go @@ -8,6 +8,21 @@ import ( "github.com/easyai/easyai-ai-gateway/apps/api/internal/store" ) +// createTenant godoc +// @Summary 创建租户 +// @Description 管理端创建网关租户,tenantKey 和 name 必填。 +// @Tags identity +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param input body store.GatewayTenantInput true "租户请求" +// @Success 201 {object} store.GatewayTenant +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 409 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/tenants [post] func (s *Server) createTenant(w http.ResponseWriter, r *http.Request) { var input store.GatewayTenantInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -31,6 +46,23 @@ func (s *Server) createTenant(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusCreated, item) } +// updateTenant godoc +// @Summary 更新租户 +// @Description 管理端更新网关租户信息。 +// @Tags identity +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param tenantID path string true "租户 ID" +// @Param input body store.GatewayTenantInput true "租户请求" +// @Success 200 {object} store.GatewayTenant +// @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/tenants/{tenantID} [patch] func (s *Server) updateTenant(w http.ResponseWriter, r *http.Request) { var input store.GatewayTenantInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -58,6 +90,19 @@ func (s *Server) updateTenant(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, item) } +// deleteTenant godoc +// @Summary 删除租户 +// @Description 管理端删除网关租户。 +// @Tags identity +// @Produce json +// @Security BearerAuth +// @Param tenantID 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/tenants/{tenantID} [delete] func (s *Server) deleteTenant(w http.ResponseWriter, r *http.Request) { if err := s.store.DeleteTenant(r.Context(), r.PathValue("tenantID")); err != nil { if store.IsNotFound(err) { @@ -71,6 +116,21 @@ func (s *Server) deleteTenant(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) } +// createGatewayUser godoc +// @Summary 创建用户 +// @Description 管理端创建网关用户;password 为空时不设置本地密码,非空时至少 8 位。 +// @Tags identity +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param input body store.GatewayUserInput true "用户请求" +// @Success 201 {object} store.GatewayUser +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 409 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/users [post] func (s *Server) createGatewayUser(w http.ResponseWriter, r *http.Request) { var input store.GatewayUserInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -98,6 +158,23 @@ func (s *Server) createGatewayUser(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusCreated, item) } +// updateGatewayUser godoc +// @Summary 更新用户 +// @Description 管理端更新网关用户资料、角色、默认用户组和可选本地密码。 +// @Tags identity +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param userID path string true "用户 ID" +// @Param input body store.GatewayUserInput true "用户请求" +// @Success 200 {object} store.GatewayUser +// @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/users/{userID} [patch] func (s *Server) updateGatewayUser(w http.ResponseWriter, r *http.Request) { var input store.GatewayUserInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -129,6 +206,19 @@ func (s *Server) updateGatewayUser(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, item) } +// deleteGatewayUser godoc +// @Summary 删除用户 +// @Description 管理端删除网关用户。 +// @Tags identity +// @Produce json +// @Security BearerAuth +// @Param userID 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/users/{userID} [delete] func (s *Server) deleteGatewayUser(w http.ResponseWriter, r *http.Request) { if err := s.store.DeleteGatewayUser(r.Context(), r.PathValue("userID")); err != nil { if store.IsNotFound(err) { @@ -142,6 +232,21 @@ func (s *Server) deleteGatewayUser(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) } +// createUserGroup godoc +// @Summary 创建用户组 +// @Description 管理端创建用户组,可配置默认定价、运行策略、限流和配额策略。 +// @Tags identity +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param input body store.UserGroupInput true "用户组请求" +// @Success 201 {object} store.UserGroup +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 409 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/user-groups [post] func (s *Server) createUserGroup(w http.ResponseWriter, r *http.Request) { var input store.UserGroupInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -165,6 +270,23 @@ func (s *Server) createUserGroup(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusCreated, item) } +// updateUserGroup godoc +// @Summary 更新用户组 +// @Description 管理端更新用户组基础信息和策略配置。 +// @Tags identity +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param groupID path string true "用户组 ID" +// @Param input body store.UserGroupInput true "用户组请求" +// @Success 200 {object} store.UserGroup +// @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/user-groups/{groupID} [patch] func (s *Server) updateUserGroup(w http.ResponseWriter, r *http.Request) { var input store.UserGroupInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -192,6 +314,19 @@ func (s *Server) updateUserGroup(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, item) } +// deleteUserGroup godoc +// @Summary 删除用户组 +// @Description 管理端删除用户组。 +// @Tags identity +// @Produce json +// @Security BearerAuth +// @Param groupID 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/user-groups/{groupID} [delete] func (s *Server) deleteUserGroup(w http.ResponseWriter, r *http.Request) { if err := s.store.DeleteUserGroup(r.Context(), r.PathValue("groupID")); err != nil { if store.IsNotFound(err) { diff --git a/apps/api/internal/httpapi/model_catalog.go b/apps/api/internal/httpapi/model_catalog.go index c0a0991..23e3568 100644 --- a/apps/api/internal/httpapi/model_catalog.go +++ b/apps/api/internal/httpapi/model_catalog.go @@ -123,6 +123,16 @@ type catalogGroup struct { enabled bool } +// listModelCatalog godoc +// @Summary 列出模型目录 +// @Description 聚合平台模型、基础模型、供应商、运行策略和访问规则,返回前端模型目录所需的过滤器、摘要和展示字段。 +// @Tags model-catalog +// @Produce json +// @Security BearerAuth +// @Success 200 {object} ModelCatalogResponse +// @Failure 401 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/v1/model-catalog [get] func (s *Server) listModelCatalog(w http.ResponseWriter, r *http.Request) { ctx := r.Context() models, err := s.store.ListModels(ctx) diff --git a/apps/api/internal/httpapi/openapi_models.go b/apps/api/internal/httpapi/openapi_models.go new file mode 100644 index 0000000..05e9fa9 --- /dev/null +++ b/apps/api/internal/httpapi/openapi_models.go @@ -0,0 +1,243 @@ +package httpapi + +import ( + "github.com/easyai/easyai-ai-gateway/apps/api/internal/auth" + "github.com/easyai/easyai-ai-gateway/apps/api/internal/store" +) + +type HealthResponse struct { + OK bool `json:"ok" example:"true"` + Service string `json:"service" example:"easyai-ai-gateway"` + Env string `json:"env" example:"development"` + IdentityMode string `json:"identityMode" example:"standalone"` +} + +type ReadyResponse struct { + OK bool `json:"ok" example:"true"` +} + +type ErrorEnvelope struct { + Error ErrorPayload `json:"error"` +} + +type ErrorPayload struct { + Message string `json:"message" example:"invalid json body"` + Status int `json:"status" example:"400"` + Code string `json:"code,omitempty" example:"rate_limit"` +} + +type AuthResponse struct { + AccessToken string `json:"accessToken" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."` + TokenType string `json:"tokenType" example:"Bearer"` + ExpiresIn int `json:"expiresIn" example:"86400"` + User *auth.User `json:"user"` +} + +type ItemListResponse struct { + Items []map[string]interface{} `json:"items"` +} + +type PlatformListResponse struct { + Items []store.Platform `json:"items"` +} + +type PlatformModelListResponse struct { + Items []store.PlatformModel `json:"items"` +} + +type CatalogProviderListResponse struct { + Items []store.CatalogProvider `json:"items"` +} + +type BaseModelListResponse struct { + Items []store.BaseModel `json:"items"` +} + +type TenantListResponse struct { + Items []store.GatewayTenant `json:"items"` +} + +type UserListResponse struct { + Items []store.GatewayUser `json:"items"` +} + +type UserGroupListResponse struct { + Items []store.UserGroup `json:"items"` +} + +type AccessRuleListResponse struct { + Items []store.AccessRule `json:"items"` +} + +type APIKeyListResponse struct { + Items []store.APIKey `json:"items"` +} + +type PlayableAPIKeyListResponse struct { + Items []store.PlayableAPIKey `json:"items"` +} + +type PricingRuleListResponse struct { + Items []store.PricingRule `json:"items"` +} + +type PricingRuleSetListResponse struct { + Items []store.PricingRuleSet `json:"items"` +} + +type RuntimePolicySetListResponse struct { + Items []store.RuntimePolicySet `json:"items"` +} + +type RateLimitWindowListResponse struct { + Items []store.RateLimitWindow `json:"items"` +} + +type ModelRateLimitStatusListResponse struct { + Items []store.ModelRateLimitStatus `json:"items"` +} + +type AuditLogListResponse struct { + Items []store.AuditLog `json:"items"` +} + +type WalletTransactionListResponse struct { + Items []store.GatewayWalletTransaction `json:"items"` + Total int `json:"total" example:"42"` + Page int `json:"page" example:"1"` + PageSize int `json:"pageSize" example:"50"` +} + +type TaskListResponse struct { + Items []store.GatewayTask `json:"items"` + Total int `json:"total" example:"42"` + Page int `json:"page" example:"1"` + PageSize int `json:"pageSize" example:"50"` +} + +type TaskParamPreprocessingLogListResponse struct { + Items []store.TaskParamPreprocessingLog `json:"items"` +} + +type TaskEventListResponse struct { + Items []store.TaskEvent `json:"items"` +} + +type ReplacePlatformModelsRequest struct { + Models []store.CreatePlatformModelInput `json:"models"` +} + +type TaskAcceptedResponse struct { + TaskID string `json:"taskId" example:"9f4d8f3d-5f5f-4bb7-a4be-344a9f930e25"` + Task store.GatewayTask `json:"task"` + Next TaskNextLinks `json:"next"` +} + +type TaskNextLinks struct { + Events string `json:"events" example:"/api/v1/tasks/9f4d8f3d-5f5f-4bb7-a4be-344a9f930e25/events"` + Detail string `json:"detail" example:"/api/v1/tasks/9f4d8f3d-5f5f-4bb7-a4be-344a9f930e25"` +} + +type TaskAcceptedEvent struct { + TaskID string `json:"taskId" example:"9f4d8f3d-5f5f-4bb7-a4be-344a9f930e25"` + Status string `json:"status" example:"pending"` +} + +type PricingEstimateRequest struct { + Kind string `json:"kind" example:"chat.completions"` + Model string `json:"model" example:"gpt-4o-mini"` + Messages []ChatMessage `json:"messages,omitempty"` + Prompt string `json:"prompt,omitempty" example:"A small orange cat"` + MaxTokens int `json:"max_tokens,omitempty" example:"512"` + N int `json:"n,omitempty" example:"1"` + RunMode string `json:"runMode,omitempty" example:"simulation"` +} + +type PricingEstimateResponse struct { + Items []map[string]interface{} `json:"items"` + Resolver string `json:"resolver" example:"effective-pricing-v1"` +} + +type TaskRequest struct { + Model string `json:"model" example:"gpt-4o-mini"` + Messages []ChatMessage `json:"messages,omitempty"` + Input string `json:"input,omitempty" example:"Tell me a short story"` + Prompt string `json:"prompt,omitempty" example:"A watercolor robot reading a book"` + Stream bool `json:"stream,omitempty" example:"false"` + RunMode string `json:"runMode,omitempty" example:"simulation"` + MaxTokens int `json:"max_tokens,omitempty" example:"512"` + Size string `json:"size,omitempty" example:"1024x1024"` + Duration int `json:"duration,omitempty" example:"5"` + Resolution string `json:"resolution,omitempty" example:"720p"` +} + +type ChatCompletionRequest struct { + Model string `json:"model" example:"gpt-4o-mini"` + Messages []ChatMessage `json:"messages"` + Temperature float64 `json:"temperature,omitempty" example:"0.7"` + MaxTokens int `json:"max_tokens,omitempty" example:"512"` + Stream bool `json:"stream,omitempty" example:"false"` + RunMode string `json:"runMode,omitempty" example:"simulation"` +} + +type ChatMessage struct { + Role string `json:"role" example:"user"` + Content string `json:"content" example:"Hello"` +} + +type ResponsesRequest struct { + Model string `json:"model" example:"gpt-4o-mini"` + Input interface{} `json:"input" example:"Tell me a short story"` + Stream bool `json:"stream,omitempty" example:"false"` + RunMode string `json:"runMode,omitempty" example:"simulation"` +} + +type ImageGenerationRequest struct { + Model string `json:"model" example:"gpt-image-1"` + Prompt string `json:"prompt" example:"A watercolor robot reading a book"` + N int `json:"n,omitempty" example:"1"` + Size string `json:"size,omitempty" example:"1024x1024"` + Quality string `json:"quality,omitempty" example:"standard"` + ResponseFormat string `json:"response_format,omitempty" example:"url"` + RunMode string `json:"runMode,omitempty" example:"simulation"` +} + +type ImageEditRequest struct { + Model string `json:"model" example:"gpt-image-1"` + Prompt string `json:"prompt" example:"Add a sunset background"` + Image string `json:"image,omitempty" example:"https://example.com/image.png"` + Mask string `json:"mask,omitempty" example:"https://example.com/mask.png"` + N int `json:"n,omitempty" example:"1"` + Size string `json:"size,omitempty" example:"1024x1024"` + ResponseFormat string `json:"response_format,omitempty" example:"url"` + RunMode string `json:"runMode,omitempty" example:"simulation"` +} + +type VideoGenerationRequest struct { + Model string `json:"model" example:"video-model"` + Prompt string `json:"prompt" example:"A cinematic drone shot over mountains"` + Duration int `json:"duration,omitempty" example:"5"` + Resolution string `json:"resolution,omitempty" example:"720p"` + RunMode string `json:"runMode,omitempty" example:"simulation"` +} + +type CompatibleResponse struct { + ID string `json:"id" example:"chatcmpl-123"` + Object string `json:"object" example:"chat.completion"` + Model string `json:"model" example:"gpt-4o-mini"` + Choices []map[string]interface{} `json:"choices,omitempty"` + Usage map[string]interface{} `json:"usage,omitempty"` +} + +type NetworkProxyConfigResponse struct { + GlobalHTTPProxy string `json:"globalHttpProxy" example:"http://127.0.0.1:7890"` + GlobalHTTPProxySet bool `json:"globalHttpProxySet" example:"true"` + GlobalHTTPProxySource string `json:"globalHttpProxySource" example:"env"` +} + +type WalletAdjustmentResponse struct { + Account store.GatewayWalletAccount `json:"account"` + Before store.GatewayWalletAccount `json:"before"` + Transaction store.GatewayWalletTransaction `json:"transaction"` + AuditLog store.AuditLog `json:"auditLog"` +} diff --git a/apps/api/internal/httpapi/pricing_handlers.go b/apps/api/internal/httpapi/pricing_handlers.go index 8b6d298..3dad415 100644 --- a/apps/api/internal/httpapi/pricing_handlers.go +++ b/apps/api/internal/httpapi/pricing_handlers.go @@ -9,6 +9,17 @@ import ( "github.com/easyai/easyai-ai-gateway/apps/api/internal/store" ) +// listPricingRuleSets godoc +// @Summary 列出定价规则集 +// @Description 管理端返回可分配给平台、模型、租户或用户组的定价规则集。 +// @Tags pricing +// @Produce json +// @Security BearerAuth +// @Success 200 {object} PricingRuleSetListResponse +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/pricing/rule-sets [get] func (s *Server) listPricingRuleSets(w http.ResponseWriter, r *http.Request) { items, err := s.store.ListPricingRuleSets(r.Context()) if err != nil { @@ -19,6 +30,21 @@ func (s *Server) listPricingRuleSets(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{"items": items}) } +// createPricingRuleSet godoc +// @Summary 创建定价规则集 +// @Description 管理端创建定价规则集,ruleSetKey、name 和至少一条 rule 必填。 +// @Tags pricing +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param input body store.PricingRuleSetInput true "定价规则集请求" +// @Success 201 {object} store.PricingRuleSet +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 409 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/pricing/rule-sets [post] func (s *Server) createPricingRuleSet(w http.ResponseWriter, r *http.Request) { var input store.PricingRuleSetInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -42,6 +68,23 @@ func (s *Server) createPricingRuleSet(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusCreated, item) } +// updatePricingRuleSet godoc +// @Summary 更新定价规则集 +// @Description 管理端更新定价规则集及其规则列表。 +// @Tags pricing +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param ruleSetID path string true "定价规则集 ID" +// @Param input body store.PricingRuleSetInput true "定价规则集请求" +// @Success 200 {object} store.PricingRuleSet +// @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/pricing/rule-sets/{ruleSetID} [patch] func (s *Server) updatePricingRuleSet(w http.ResponseWriter, r *http.Request) { var input store.PricingRuleSetInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -69,6 +112,19 @@ func (s *Server) updatePricingRuleSet(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, item) } +// deletePricingRuleSet godoc +// @Summary 删除定价规则集 +// @Description 管理端删除非默认定价规则集;默认规则集受保护。 +// @Tags pricing +// @Produce json +// @Security BearerAuth +// @Param ruleSetID 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/pricing/rule-sets/{ruleSetID} [delete] func (s *Server) deletePricingRuleSet(w http.ResponseWriter, r *http.Request) { if err := s.store.DeletePricingRuleSet(r.Context(), r.PathValue("ruleSetID")); err != nil { if store.IsNotFound(err) { diff --git a/apps/api/internal/httpapi/runtime_policy_handlers.go b/apps/api/internal/httpapi/runtime_policy_handlers.go index 95b0a3a..5440584 100644 --- a/apps/api/internal/httpapi/runtime_policy_handlers.go +++ b/apps/api/internal/httpapi/runtime_policy_handlers.go @@ -9,6 +9,17 @@ import ( "github.com/easyai/easyai-ai-gateway/apps/api/internal/store" ) +// listRuntimePolicySets godoc +// @Summary 列出运行策略集 +// @Description 管理端返回可分配给平台、模型或用户组的运行策略集。 +// @Tags runtime +// @Produce json +// @Security BearerAuth +// @Success 200 {object} RuntimePolicySetListResponse +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/runtime/policy-sets [get] func (s *Server) listRuntimePolicySets(w http.ResponseWriter, r *http.Request) { items, err := s.store.ListRuntimePolicySets(r.Context()) if err != nil { @@ -19,6 +30,17 @@ func (s *Server) listRuntimePolicySets(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{"items": items}) } +// getRunnerPolicy godoc +// @Summary 获取 Runner 策略 +// @Description 管理端获取当前生效的默认 Runner 调度策略。 +// @Tags runtime +// @Produce json +// @Security BearerAuth +// @Success 200 {object} store.RunnerPolicy +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/runtime/runner-policy [get] func (s *Server) getRunnerPolicy(w http.ResponseWriter, r *http.Request) { item, err := s.store.GetActiveRunnerPolicy(r.Context()) if err != nil { @@ -29,6 +51,20 @@ func (s *Server) getRunnerPolicy(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, item) } +// updateRunnerPolicy godoc +// @Summary 更新 Runner 策略 +// @Description 管理端写入默认 Runner 调度策略。 +// @Tags runtime +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param input body store.RunnerPolicyInput true "Runner 策略请求" +// @Success 200 {object} store.RunnerPolicy +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/runtime/runner-policy [patch] func (s *Server) updateRunnerPolicy(w http.ResponseWriter, r *http.Request) { var input store.RunnerPolicyInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -45,10 +81,26 @@ func (s *Server) updateRunnerPolicy(w http.ResponseWriter, r *http.Request) { } type updatePlatformDynamicPriorityRequest struct { - DynamicPriority *int `json:"dynamicPriority"` - Reset bool `json:"reset"` + DynamicPriority *int `json:"dynamicPriority" example:"10"` + Reset bool `json:"reset" example:"false"` } +// updatePlatformDynamicPriority godoc +// @Summary 更新平台动态优先级 +// @Description 管理端调整平台运行时动态优先级;reset 为 true 时清空动态值。 +// @Tags runtime +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param platformID path string true "平台 ID" +// @Param input body updatePlatformDynamicPriorityRequest true "动态优先级请求" +// @Success 200 {object} store.Platform +// @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}/dynamic-priority [patch] func (s *Server) updatePlatformDynamicPriority(w http.ResponseWriter, r *http.Request) { var input updatePlatformDynamicPriorityRequest if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -82,6 +134,21 @@ func (s *Server) updatePlatformDynamicPriority(w http.ResponseWriter, r *http.Re writeJSON(w, http.StatusOK, item) } +// createRuntimePolicySet godoc +// @Summary 创建运行策略集 +// @Description 管理端创建运行策略集,policyKey 和 name 必填。 +// @Tags runtime +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param input body store.RuntimePolicySetInput true "运行策略集请求" +// @Success 201 {object} store.RuntimePolicySet +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 403 {object} ErrorEnvelope +// @Failure 409 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/admin/runtime/policy-sets [post] func (s *Server) createRuntimePolicySet(w http.ResponseWriter, r *http.Request) { var input store.RuntimePolicySetInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -105,6 +172,23 @@ func (s *Server) createRuntimePolicySet(w http.ResponseWriter, r *http.Request) writeJSON(w, http.StatusCreated, item) } +// updateRuntimePolicySet godoc +// @Summary 更新运行策略集 +// @Description 管理端更新运行策略集及其限流、重试、超时等策略配置。 +// @Tags runtime +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param policySetID path string true "运行策略集 ID" +// @Param input body store.RuntimePolicySetInput true "运行策略集请求" +// @Success 200 {object} store.RuntimePolicySet +// @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/runtime/policy-sets/{policySetID} [patch] func (s *Server) updateRuntimePolicySet(w http.ResponseWriter, r *http.Request) { var input store.RuntimePolicySetInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { @@ -132,6 +216,19 @@ func (s *Server) updateRuntimePolicySet(w http.ResponseWriter, r *http.Request) writeJSON(w, http.StatusOK, item) } +// deleteRuntimePolicySet godoc +// @Summary 删除运行策略集 +// @Description 管理端删除非默认运行策略集;默认策略集受保护。 +// @Tags runtime +// @Produce json +// @Security BearerAuth +// @Param policySetID 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/runtime/policy-sets/{policySetID} [delete] func (s *Server) deleteRuntimePolicySet(w http.ResponseWriter, r *http.Request) { if err := s.store.DeleteRuntimePolicySet(r.Context(), r.PathValue("policySetID")); err != nil { if store.IsNotFound(err) { diff --git a/apps/api/internal/httpapi/simulation_assets.go b/apps/api/internal/httpapi/simulation_assets.go index fb70a6f..8c77574 100644 --- a/apps/api/internal/httpapi/simulation_assets.go +++ b/apps/api/internal/httpapi/simulation_assets.go @@ -18,6 +18,16 @@ const simulationVideoMP4Base64 = "AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAA var simulationVideoMP4 = mustDecodeSimulationAsset(simulationVideoMP4Base64) +// serveSimulationAsset godoc +// @Summary 获取模拟资源 +// @Description 返回本地模拟模式使用的图片、视频封面或短视频资源。 +// @Tags simulation +// @Produce image/svg+xml +// @Produce video/mp4 +// @Param asset path string true "资源文件名,可选 image.svg、image.png、image-edit.svg、image-edit.png、video-poster.svg、video.mp4" +// @Success 200 {file} binary +// @Failure 404 {string} string "Not Found" +// @Router /static/simulation/{asset} [get] func serveSimulationAsset(w http.ResponseWriter, r *http.Request) { asset := strings.ToLower(strings.TrimSpace(r.PathValue("asset"))) switch asset { diff --git a/apps/api/internal/httpapi/wallet_handlers.go b/apps/api/internal/httpapi/wallet_handlers.go index dc23d4c..f02f1e9 100644 --- a/apps/api/internal/httpapi/wallet_handlers.go +++ b/apps/api/internal/httpapi/wallet_handlers.go @@ -7,6 +7,17 @@ import ( "github.com/easyai/easyai-ai-gateway/apps/api/internal/store" ) +// getWallet godoc +// @Summary 获取钱包摘要 +// @Description 返回当前用户的钱包账户、余额和最近消费摘要,可按 currency 过滤。 +// @Tags wallet +// @Produce json +// @Security BearerAuth +// @Param currency query string false "币种" default(USD) +// @Success 200 {object} store.WalletSummary +// @Failure 401 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/workspace/wallet [get] func (s *Server) getWallet(w http.ResponseWriter, r *http.Request) { user, ok := auth.UserFromContext(r.Context()) if !ok { @@ -22,6 +33,24 @@ func (s *Server) getWallet(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, summary) } +// listWalletTransactions godoc +// @Summary 列出钱包交易 +// @Description 返回当前用户的钱包交易流水,支持关键字、方向、交易类型、时间范围和分页过滤。 +// @Tags wallet +// @Produce json +// @Security BearerAuth +// @Param q query string false "搜索关键字,别名 query" +// @Param direction query string false "交易方向" +// @Param transactionType query string false "交易类型" +// @Param createdFrom query string false "创建时间起点,别名 from" +// @Param createdTo query string false "创建时间终点,别名 to" +// @Param page query int false "页码" default(1) +// @Param pageSize query int false "每页数量,别名 limit" default(50) +// @Success 200 {object} WalletTransactionListResponse +// @Failure 400 {object} ErrorEnvelope +// @Failure 401 {object} ErrorEnvelope +// @Failure 500 {object} ErrorEnvelope +// @Router /api/workspace/wallet/transactions [get] func (s *Server) listWalletTransactions(w http.ResponseWriter, r *http.Request) { user, ok := auth.UserFromContext(r.Context()) if !ok { diff --git a/apps/api/project.json b/apps/api/project.json index b1f2d30..204346b 100644 --- a/apps/api/project.json +++ b/apps/api/project.json @@ -19,6 +19,14 @@ "command": "go run ./cmd/migrate" } }, + "openapi": { + "executor": "nx:run-commands", + "outputs": ["{projectRoot}/docs/swagger.json", "{projectRoot}/docs/swagger.yaml"], + "options": { + "cwd": "apps/api", + "command": "go run github.com/swaggo/swag/cmd/swag@v1.16.4 init --parseInternal -d ./cmd/gateway,./internal/httpapi,./internal/store,./internal/auth -g main.go -o docs --outputTypes json,yaml" + } + }, "test": { "executor": "nx:run-commands", "outputs": ["{workspaceRoot}/coverage/apps/api"], diff --git a/package.json b/package.json index 2dc929f..cec2c82 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "test": "nx run-many -t test -p api web", "lint": "nx run-many -t lint -p web contracts", "db:create": "scripts/create-database.sh", - "migrate": "nx run api:migrate" + "migrate": "nx run api:migrate", + "openapi": "nx run api:openapi" }, "devDependencies": { "@nx/vite": "^21.0.0",