mirror of
https://github.com/EZ-Api/ez-api.git
synced 2026-01-13 17:47:51 +00:00
refactor(api): update traffic chart response structure
Change the traffic chart API response from bucket-based to series-based to better support frontend visualization libraries. The new format provides a shared X-axis and aligned data arrays for each model series. - Replace `buckets` with `x` and `series` in response - Implement data alignment and zero-filling for time slots - Update Swagger documentation including pending definitions BREAKING CHANGE: The `GET /admin/logs/stats/traffic-chart` response schema has changed. `buckets` and `models` fields are removed.
This commit is contained in:
@@ -1183,7 +1183,7 @@ const docTemplate = `{
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "time period: today, week, month, all",
|
||||
"description": "time period: today, week, month, last7d, last30d, all",
|
||||
"name": "period",
|
||||
"in": "query"
|
||||
},
|
||||
@@ -1198,6 +1198,12 @@ const docTemplate = `{
|
||||
"description": "unix seconds",
|
||||
"name": "until",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"description": "include trend data comparing to previous period",
|
||||
"name": "include_trends",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -1302,6 +1308,272 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/ip-bans": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"AdminAuth": []
|
||||
}
|
||||
],
|
||||
"description": "List all global IP/CIDR ban rules",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin",
|
||||
"ip-bans"
|
||||
],
|
||||
"summary": "List IP bans",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by status (active, expired)",
|
||||
"name": "status",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/internal_api.IPBanView"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"AdminAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Create a new global IP/CIDR ban rule",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin",
|
||||
"ip-bans"
|
||||
],
|
||||
"summary": "Create an IP ban",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "IP Ban Info",
|
||||
"name": "ban",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_api.CreateIPBanRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_api.IPBanView"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "Conflict",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/ip-bans/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"AdminAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Get a single global IP/CIDR ban rule by ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin",
|
||||
"ip-bans"
|
||||
],
|
||||
"summary": "Get an IP ban",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "IP Ban ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_api.IPBanView"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"AdminAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Update a global IP/CIDR ban rule",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin",
|
||||
"ip-bans"
|
||||
],
|
||||
"summary": "Update an IP ban",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "IP Ban ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "IP Ban Update",
|
||||
"name": "ban",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_api.UpdateIPBanRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_api.IPBanView"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "Conflict",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"AdminAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Delete a global IP/CIDR ban rule",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin",
|
||||
"ip-bans"
|
||||
],
|
||||
"summary": "Delete an IP ban",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "IP Ban ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/keys/{id}/access": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -1617,7 +1889,7 @@ const docTemplate = `{
|
||||
"AdminAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Get time × model aggregated data for stacked traffic charts. Returns time buckets with per-model breakdown.",
|
||||
"description": "Get time × model aggregated data for stacked traffic charts. Returns a shared time axis under ` + "`" + `x` + "`" + ` and per-model series arrays aligned to that axis. Models outside top_n are aggregated under the series name \"other\".",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -3522,7 +3794,7 @@ const docTemplate = `{
|
||||
"MasterAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Returns the identity of the authenticated user based on the Authorization header.\nSupports Admin Token, Master Key, and Child Key (API Key) authentication.\n\nResponse varies by token type:\n- Admin Token: {\"type\": \"admin\", \"role\": \"admin\"}\n- Master Key: {\"type\": \"master\", \"id\": 1, \"name\": \"...\", ...}\n- Child Key: {\"type\": \"key\", \"id\": 5, \"master_id\": 1, \"issued_by\": \"master\", ...}",
|
||||
"description": "Returns complete identity and realtime statistics of the authenticated user.\nSupports Admin Token, Master Key, and Child Key (API Key) authentication.\nThis endpoint is designed for frontend initialization - call once after login\nand store the response for subsequent use.\n\n**Response varies by token type:**\n\n**Admin Token:**\n- type: \"admin\"\n- role: \"admin\"\n- permissions: [\"*\"] (full access)\n\n**Master Key:**\n- type: \"master\"\n- Basic info: id, name, group, namespaces, status, epoch, max_child_keys, global_qps\n- Timestamps: created_at, updated_at\n- Realtime stats: requests, tokens, qps, qps_limit, rate_limited\n\n**Child Key (API Key):**\n- type: \"key\"\n- Basic info: id, master_id, master_name, group, scopes, namespaces, status\n- Security: issued_at_epoch, issued_by, allow_ips, deny_ips, expires_at\n- Model limits: model_limits, model_limits_enabled\n- Quota: quota_limit, quota_used, quota_reset_at, quota_reset_type\n- Usage stats: request_count, used_tokens, last_accessed_at\n- Realtime stats: requests, tokens, qps, qps_limit, rate_limited\n\n**Error responses:**\n- 401: authorization header required\n- 401: invalid authorization header format\n- 401: invalid token\n- 401: token is not active\n- 401: token has expired\n- 401: token has been revoked\n- 401: master is not active",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -5157,6 +5429,23 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.CreateIPBanRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"cidr"
|
||||
],
|
||||
"properties": {
|
||||
"cidr": {
|
||||
"type": "string"
|
||||
},
|
||||
"expires_at": {
|
||||
"type": "integer"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.CreateMasterRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -5208,11 +5497,36 @@ const docTemplate = `{
|
||||
"$ref": "#/definitions/internal_api.TopModelStat"
|
||||
}
|
||||
},
|
||||
"trends": {
|
||||
"description": "Only present when include_trends=true",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/internal_api.DashboardTrends"
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.DashboardTrends": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error_rate": {
|
||||
"$ref": "#/definitions/internal_api.TrendInfo"
|
||||
},
|
||||
"latency": {
|
||||
"$ref": "#/definitions/internal_api.TrendInfo"
|
||||
},
|
||||
"requests": {
|
||||
"$ref": "#/definitions/internal_api.TrendInfo"
|
||||
},
|
||||
"tokens": {
|
||||
"$ref": "#/definitions/internal_api.TrendInfo"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.DeleteLogsRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5283,6 +5597,38 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.IPBanView": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cidr": {
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "integer"
|
||||
},
|
||||
"created_by": {
|
||||
"type": "string"
|
||||
},
|
||||
"expires_at": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hit_count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.IssueChildKeyRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5907,42 +6253,36 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.TrafficBucket": {
|
||||
"internal_api.TrafficChartAxis": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"breakdown": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/internal_api.TrafficMetrics"
|
||||
"labels": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
"type": "string"
|
||||
"timestamps": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "integer"
|
||||
},
|
||||
"total": {
|
||||
"$ref": "#/definitions/internal_api.TrafficMetrics"
|
||||
"totals": {
|
||||
"$ref": "#/definitions/internal_api.TrafficTotals"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.TrafficChartResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"buckets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/internal_api.TrafficBucket"
|
||||
}
|
||||
},
|
||||
"granularity": {
|
||||
"type": "string"
|
||||
},
|
||||
"models": {
|
||||
"series": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
"$ref": "#/definitions/internal_api.TrafficSeries"
|
||||
}
|
||||
},
|
||||
"since": {
|
||||
@@ -5950,20 +6290,71 @@ const docTemplate = `{
|
||||
},
|
||||
"until": {
|
||||
"type": "integer"
|
||||
},
|
||||
"x": {
|
||||
"$ref": "#/definitions/internal_api.TrafficChartAxis"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.TrafficMetrics": {
|
||||
"internal_api.TrafficSeries": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"count": {
|
||||
"type": "integer"
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"tokens_in": {
|
||||
"type": "integer"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"tokens_out": {
|
||||
"type": "integer"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.TrafficTotals": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"tokens_in": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"tokens_out": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.TrendInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"delta": {
|
||||
"description": "Percentage change from previous period (nil if no baseline)",
|
||||
"type": "number"
|
||||
},
|
||||
"direction": {
|
||||
"description": "\"up\", \"down\", \"stable\", or \"new\" (no baseline)",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -6010,6 +6401,20 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.UpdateIPBanRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"expires_at": {
|
||||
"$ref": "#/definitions/internal_api.optionalInt64"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.UpdateMasterRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -6071,9 +6476,49 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.WhoamiRealtimeView": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"qps": {
|
||||
"description": "Current QPS",
|
||||
"type": "integer",
|
||||
"example": 5
|
||||
},
|
||||
"qps_limit": {
|
||||
"description": "QPS limit",
|
||||
"type": "integer",
|
||||
"example": 100
|
||||
},
|
||||
"rate_limited": {
|
||||
"description": "Whether currently rate limited",
|
||||
"type": "boolean",
|
||||
"example": false
|
||||
},
|
||||
"requests": {
|
||||
"description": "Total requests",
|
||||
"type": "integer",
|
||||
"example": 100
|
||||
},
|
||||
"tokens": {
|
||||
"description": "Total tokens used",
|
||||
"type": "integer",
|
||||
"example": 50000
|
||||
},
|
||||
"updated_at": {
|
||||
"description": "Last updated timestamp",
|
||||
"type": "integer",
|
||||
"example": 1703505600
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.WhoamiResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow_ips": {
|
||||
"description": "IP whitelist (for diagnostics)",
|
||||
"type": "string",
|
||||
"example": ""
|
||||
},
|
||||
"created_at": {
|
||||
"type": "integer",
|
||||
"example": 1703505600
|
||||
@@ -6082,10 +6527,20 @@ const docTemplate = `{
|
||||
"type": "string",
|
||||
"example": "default"
|
||||
},
|
||||
"deny_ips": {
|
||||
"description": "IP blacklist (for diagnostics)",
|
||||
"type": "string",
|
||||
"example": ""
|
||||
},
|
||||
"epoch": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"expires_at": {
|
||||
"description": "Expiration timestamp (0 = never)",
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"global_qps": {
|
||||
"type": "integer",
|
||||
"example": 100
|
||||
@@ -6107,15 +6562,35 @@ const docTemplate = `{
|
||||
"type": "string",
|
||||
"example": "master"
|
||||
},
|
||||
"last_accessed_at": {
|
||||
"description": "Last access timestamp",
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"master_id": {
|
||||
"description": "Key fields (only present when type is \"key\")",
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"master_name": {
|
||||
"description": "Parent master name (for display)",
|
||||
"type": "string",
|
||||
"example": "tenant-a"
|
||||
},
|
||||
"max_child_keys": {
|
||||
"type": "integer",
|
||||
"example": 5
|
||||
},
|
||||
"model_limits": {
|
||||
"description": "Model restrictions",
|
||||
"type": "string",
|
||||
"example": "gpt-4,claude"
|
||||
},
|
||||
"model_limits_enabled": {
|
||||
"description": "Whether model limits are active",
|
||||
"type": "boolean",
|
||||
"example": false
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "tenant-a"
|
||||
@@ -6124,6 +6599,46 @@ const docTemplate = `{
|
||||
"type": "string",
|
||||
"example": "default,ns1"
|
||||
},
|
||||
"permissions": {
|
||||
"description": "Admin permissions (always [\"*\"])",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"quota_limit": {
|
||||
"description": "Token quota limit (-1 = unlimited)",
|
||||
"type": "integer",
|
||||
"example": -1
|
||||
},
|
||||
"quota_reset_at": {
|
||||
"description": "Quota reset timestamp",
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"quota_reset_type": {
|
||||
"description": "Quota reset type",
|
||||
"type": "string",
|
||||
"example": "monthly"
|
||||
},
|
||||
"quota_used": {
|
||||
"description": "Token quota used",
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"realtime": {
|
||||
"description": "Realtime stats (for master and key types)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/internal_api.WhoamiRealtimeView"
|
||||
}
|
||||
]
|
||||
},
|
||||
"request_count": {
|
||||
"description": "Total request count (from DB)",
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"role": {
|
||||
"description": "Admin fields (only present when type is \"admin\")",
|
||||
"type": "string",
|
||||
@@ -6145,6 +6660,11 @@ const docTemplate = `{
|
||||
"updated_at": {
|
||||
"type": "integer",
|
||||
"example": 1703505600
|
||||
},
|
||||
"used_tokens": {
|
||||
"description": "Total tokens used (from DB)",
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -6173,6 +6693,18 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.optionalInt64": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"set": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"value": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.refreshModelRegistryRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -1177,7 +1177,7 @@
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "time period: today, week, month, all",
|
||||
"description": "time period: today, week, month, last7d, last30d, all",
|
||||
"name": "period",
|
||||
"in": "query"
|
||||
},
|
||||
@@ -1192,6 +1192,12 @@
|
||||
"description": "unix seconds",
|
||||
"name": "until",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"description": "include trend data comparing to previous period",
|
||||
"name": "include_trends",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -1296,6 +1302,272 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/ip-bans": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"AdminAuth": []
|
||||
}
|
||||
],
|
||||
"description": "List all global IP/CIDR ban rules",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin",
|
||||
"ip-bans"
|
||||
],
|
||||
"summary": "List IP bans",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by status (active, expired)",
|
||||
"name": "status",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/internal_api.IPBanView"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"AdminAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Create a new global IP/CIDR ban rule",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin",
|
||||
"ip-bans"
|
||||
],
|
||||
"summary": "Create an IP ban",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "IP Ban Info",
|
||||
"name": "ban",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_api.CreateIPBanRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_api.IPBanView"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "Conflict",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/ip-bans/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"AdminAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Get a single global IP/CIDR ban rule by ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin",
|
||||
"ip-bans"
|
||||
],
|
||||
"summary": "Get an IP ban",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "IP Ban ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_api.IPBanView"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"AdminAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Update a global IP/CIDR ban rule",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin",
|
||||
"ip-bans"
|
||||
],
|
||||
"summary": "Update an IP ban",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "IP Ban ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "IP Ban Update",
|
||||
"name": "ban",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_api.UpdateIPBanRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_api.IPBanView"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "Conflict",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"AdminAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Delete a global IP/CIDR ban rule",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin",
|
||||
"ip-bans"
|
||||
],
|
||||
"summary": "Delete an IP ban",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "IP Ban ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gin.H"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/keys/{id}/access": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -1611,7 +1883,7 @@
|
||||
"AdminAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Get time × model aggregated data for stacked traffic charts. Returns time buckets with per-model breakdown.",
|
||||
"description": "Get time × model aggregated data for stacked traffic charts. Returns a shared time axis under `x` and per-model series arrays aligned to that axis. Models outside top_n are aggregated under the series name \"other\".",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -3516,7 +3788,7 @@
|
||||
"MasterAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Returns the identity of the authenticated user based on the Authorization header.\nSupports Admin Token, Master Key, and Child Key (API Key) authentication.\n\nResponse varies by token type:\n- Admin Token: {\"type\": \"admin\", \"role\": \"admin\"}\n- Master Key: {\"type\": \"master\", \"id\": 1, \"name\": \"...\", ...}\n- Child Key: {\"type\": \"key\", \"id\": 5, \"master_id\": 1, \"issued_by\": \"master\", ...}",
|
||||
"description": "Returns complete identity and realtime statistics of the authenticated user.\nSupports Admin Token, Master Key, and Child Key (API Key) authentication.\nThis endpoint is designed for frontend initialization - call once after login\nand store the response for subsequent use.\n\n**Response varies by token type:**\n\n**Admin Token:**\n- type: \"admin\"\n- role: \"admin\"\n- permissions: [\"*\"] (full access)\n\n**Master Key:**\n- type: \"master\"\n- Basic info: id, name, group, namespaces, status, epoch, max_child_keys, global_qps\n- Timestamps: created_at, updated_at\n- Realtime stats: requests, tokens, qps, qps_limit, rate_limited\n\n**Child Key (API Key):**\n- type: \"key\"\n- Basic info: id, master_id, master_name, group, scopes, namespaces, status\n- Security: issued_at_epoch, issued_by, allow_ips, deny_ips, expires_at\n- Model limits: model_limits, model_limits_enabled\n- Quota: quota_limit, quota_used, quota_reset_at, quota_reset_type\n- Usage stats: request_count, used_tokens, last_accessed_at\n- Realtime stats: requests, tokens, qps, qps_limit, rate_limited\n\n**Error responses:**\n- 401: authorization header required\n- 401: invalid authorization header format\n- 401: invalid token\n- 401: token is not active\n- 401: token has expired\n- 401: token has been revoked\n- 401: master is not active",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -5151,6 +5423,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.CreateIPBanRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"cidr"
|
||||
],
|
||||
"properties": {
|
||||
"cidr": {
|
||||
"type": "string"
|
||||
},
|
||||
"expires_at": {
|
||||
"type": "integer"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.CreateMasterRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -5202,11 +5491,36 @@
|
||||
"$ref": "#/definitions/internal_api.TopModelStat"
|
||||
}
|
||||
},
|
||||
"trends": {
|
||||
"description": "Only present when include_trends=true",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/internal_api.DashboardTrends"
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.DashboardTrends": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error_rate": {
|
||||
"$ref": "#/definitions/internal_api.TrendInfo"
|
||||
},
|
||||
"latency": {
|
||||
"$ref": "#/definitions/internal_api.TrendInfo"
|
||||
},
|
||||
"requests": {
|
||||
"$ref": "#/definitions/internal_api.TrendInfo"
|
||||
},
|
||||
"tokens": {
|
||||
"$ref": "#/definitions/internal_api.TrendInfo"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.DeleteLogsRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5277,6 +5591,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.IPBanView": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cidr": {
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "integer"
|
||||
},
|
||||
"created_by": {
|
||||
"type": "string"
|
||||
},
|
||||
"expires_at": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hit_count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.IssueChildKeyRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5901,42 +6247,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.TrafficBucket": {
|
||||
"internal_api.TrafficChartAxis": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"breakdown": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/internal_api.TrafficMetrics"
|
||||
"labels": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
"type": "string"
|
||||
"timestamps": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "integer"
|
||||
},
|
||||
"total": {
|
||||
"$ref": "#/definitions/internal_api.TrafficMetrics"
|
||||
"totals": {
|
||||
"$ref": "#/definitions/internal_api.TrafficTotals"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.TrafficChartResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"buckets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/internal_api.TrafficBucket"
|
||||
}
|
||||
},
|
||||
"granularity": {
|
||||
"type": "string"
|
||||
},
|
||||
"models": {
|
||||
"series": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
"$ref": "#/definitions/internal_api.TrafficSeries"
|
||||
}
|
||||
},
|
||||
"since": {
|
||||
@@ -5944,20 +6284,71 @@
|
||||
},
|
||||
"until": {
|
||||
"type": "integer"
|
||||
},
|
||||
"x": {
|
||||
"$ref": "#/definitions/internal_api.TrafficChartAxis"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.TrafficMetrics": {
|
||||
"internal_api.TrafficSeries": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"count": {
|
||||
"type": "integer"
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"tokens_in": {
|
||||
"type": "integer"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"tokens_out": {
|
||||
"type": "integer"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.TrafficTotals": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"tokens_in": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"tokens_out": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.TrendInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"delta": {
|
||||
"description": "Percentage change from previous period (nil if no baseline)",
|
||||
"type": "number"
|
||||
},
|
||||
"direction": {
|
||||
"description": "\"up\", \"down\", \"stable\", or \"new\" (no baseline)",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -6004,6 +6395,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.UpdateIPBanRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"expires_at": {
|
||||
"$ref": "#/definitions/internal_api.optionalInt64"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.UpdateMasterRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -6065,9 +6470,49 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.WhoamiRealtimeView": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"qps": {
|
||||
"description": "Current QPS",
|
||||
"type": "integer",
|
||||
"example": 5
|
||||
},
|
||||
"qps_limit": {
|
||||
"description": "QPS limit",
|
||||
"type": "integer",
|
||||
"example": 100
|
||||
},
|
||||
"rate_limited": {
|
||||
"description": "Whether currently rate limited",
|
||||
"type": "boolean",
|
||||
"example": false
|
||||
},
|
||||
"requests": {
|
||||
"description": "Total requests",
|
||||
"type": "integer",
|
||||
"example": 100
|
||||
},
|
||||
"tokens": {
|
||||
"description": "Total tokens used",
|
||||
"type": "integer",
|
||||
"example": 50000
|
||||
},
|
||||
"updated_at": {
|
||||
"description": "Last updated timestamp",
|
||||
"type": "integer",
|
||||
"example": 1703505600
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.WhoamiResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow_ips": {
|
||||
"description": "IP whitelist (for diagnostics)",
|
||||
"type": "string",
|
||||
"example": ""
|
||||
},
|
||||
"created_at": {
|
||||
"type": "integer",
|
||||
"example": 1703505600
|
||||
@@ -6076,10 +6521,20 @@
|
||||
"type": "string",
|
||||
"example": "default"
|
||||
},
|
||||
"deny_ips": {
|
||||
"description": "IP blacklist (for diagnostics)",
|
||||
"type": "string",
|
||||
"example": ""
|
||||
},
|
||||
"epoch": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"expires_at": {
|
||||
"description": "Expiration timestamp (0 = never)",
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"global_qps": {
|
||||
"type": "integer",
|
||||
"example": 100
|
||||
@@ -6101,15 +6556,35 @@
|
||||
"type": "string",
|
||||
"example": "master"
|
||||
},
|
||||
"last_accessed_at": {
|
||||
"description": "Last access timestamp",
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"master_id": {
|
||||
"description": "Key fields (only present when type is \"key\")",
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"master_name": {
|
||||
"description": "Parent master name (for display)",
|
||||
"type": "string",
|
||||
"example": "tenant-a"
|
||||
},
|
||||
"max_child_keys": {
|
||||
"type": "integer",
|
||||
"example": 5
|
||||
},
|
||||
"model_limits": {
|
||||
"description": "Model restrictions",
|
||||
"type": "string",
|
||||
"example": "gpt-4,claude"
|
||||
},
|
||||
"model_limits_enabled": {
|
||||
"description": "Whether model limits are active",
|
||||
"type": "boolean",
|
||||
"example": false
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "tenant-a"
|
||||
@@ -6118,6 +6593,46 @@
|
||||
"type": "string",
|
||||
"example": "default,ns1"
|
||||
},
|
||||
"permissions": {
|
||||
"description": "Admin permissions (always [\"*\"])",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"quota_limit": {
|
||||
"description": "Token quota limit (-1 = unlimited)",
|
||||
"type": "integer",
|
||||
"example": -1
|
||||
},
|
||||
"quota_reset_at": {
|
||||
"description": "Quota reset timestamp",
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"quota_reset_type": {
|
||||
"description": "Quota reset type",
|
||||
"type": "string",
|
||||
"example": "monthly"
|
||||
},
|
||||
"quota_used": {
|
||||
"description": "Token quota used",
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"realtime": {
|
||||
"description": "Realtime stats (for master and key types)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/internal_api.WhoamiRealtimeView"
|
||||
}
|
||||
]
|
||||
},
|
||||
"request_count": {
|
||||
"description": "Total request count (from DB)",
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"role": {
|
||||
"description": "Admin fields (only present when type is \"admin\")",
|
||||
"type": "string",
|
||||
@@ -6139,6 +6654,11 @@
|
||||
"updated_at": {
|
||||
"type": "integer",
|
||||
"example": 1703505600
|
||||
},
|
||||
"used_tokens": {
|
||||
"description": "Total tokens used (from DB)",
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -6167,6 +6687,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.optionalInt64": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"set": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"value": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_api.refreshModelRegistryRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -562,6 +562,17 @@ definitions:
|
||||
- title
|
||||
- type
|
||||
type: object
|
||||
internal_api.CreateIPBanRequest:
|
||||
properties:
|
||||
cidr:
|
||||
type: string
|
||||
expires_at:
|
||||
type: integer
|
||||
reason:
|
||||
type: string
|
||||
required:
|
||||
- cidr
|
||||
type: object
|
||||
internal_api.CreateMasterRequest:
|
||||
properties:
|
||||
global_qps:
|
||||
@@ -596,9 +607,24 @@ definitions:
|
||||
items:
|
||||
$ref: '#/definitions/internal_api.TopModelStat'
|
||||
type: array
|
||||
trends:
|
||||
allOf:
|
||||
- $ref: '#/definitions/internal_api.DashboardTrends'
|
||||
description: Only present when include_trends=true
|
||||
updated_at:
|
||||
type: integer
|
||||
type: object
|
||||
internal_api.DashboardTrends:
|
||||
properties:
|
||||
error_rate:
|
||||
$ref: '#/definitions/internal_api.TrendInfo'
|
||||
latency:
|
||||
$ref: '#/definitions/internal_api.TrendInfo'
|
||||
requests:
|
||||
$ref: '#/definitions/internal_api.TrendInfo'
|
||||
tokens:
|
||||
$ref: '#/definitions/internal_api.TrendInfo'
|
||||
type: object
|
||||
internal_api.DeleteLogsRequest:
|
||||
properties:
|
||||
before:
|
||||
@@ -646,6 +672,27 @@ definitions:
|
||||
$ref: '#/definitions/internal_api.GroupedStatsItem'
|
||||
type: array
|
||||
type: object
|
||||
internal_api.IPBanView:
|
||||
properties:
|
||||
cidr:
|
||||
type: string
|
||||
created_at:
|
||||
type: integer
|
||||
created_by:
|
||||
type: string
|
||||
expires_at:
|
||||
type: integer
|
||||
hit_count:
|
||||
type: integer
|
||||
id:
|
||||
type: integer
|
||||
reason:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
updated_at:
|
||||
type: integer
|
||||
type: object
|
||||
internal_api.IssueChildKeyRequest:
|
||||
properties:
|
||||
allow_ips:
|
||||
@@ -1055,44 +1102,74 @@ definitions:
|
||||
tokens:
|
||||
type: integer
|
||||
type: object
|
||||
internal_api.TrafficBucket:
|
||||
internal_api.TrafficChartAxis:
|
||||
properties:
|
||||
breakdown:
|
||||
additionalProperties:
|
||||
$ref: '#/definitions/internal_api.TrafficMetrics'
|
||||
type: object
|
||||
time:
|
||||
type: string
|
||||
timestamp:
|
||||
type: integer
|
||||
total:
|
||||
$ref: '#/definitions/internal_api.TrafficMetrics'
|
||||
labels:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
timestamps:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
totals:
|
||||
$ref: '#/definitions/internal_api.TrafficTotals'
|
||||
type: object
|
||||
internal_api.TrafficChartResponse:
|
||||
properties:
|
||||
buckets:
|
||||
items:
|
||||
$ref: '#/definitions/internal_api.TrafficBucket'
|
||||
type: array
|
||||
granularity:
|
||||
type: string
|
||||
models:
|
||||
series:
|
||||
items:
|
||||
type: string
|
||||
$ref: '#/definitions/internal_api.TrafficSeries'
|
||||
type: array
|
||||
since:
|
||||
type: integer
|
||||
until:
|
||||
type: integer
|
||||
x:
|
||||
$ref: '#/definitions/internal_api.TrafficChartAxis'
|
||||
type: object
|
||||
internal_api.TrafficMetrics:
|
||||
internal_api.TrafficSeries:
|
||||
properties:
|
||||
count:
|
||||
type: integer
|
||||
data:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
name:
|
||||
type: string
|
||||
tokens_in:
|
||||
type: integer
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
tokens_out:
|
||||
type: integer
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
type: object
|
||||
internal_api.TrafficTotals:
|
||||
properties:
|
||||
data:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
tokens_in:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
tokens_out:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
type: object
|
||||
internal_api.TrendInfo:
|
||||
properties:
|
||||
delta:
|
||||
description: Percentage change from previous period (nil if no baseline)
|
||||
type: number
|
||||
direction:
|
||||
description: '"up", "down", "stable", or "new" (no baseline)'
|
||||
type: string
|
||||
type: object
|
||||
internal_api.UpdateAccessRequest:
|
||||
properties:
|
||||
@@ -1122,6 +1199,15 @@ definitions:
|
||||
min_tpm_tokens_1m:
|
||||
type: integer
|
||||
type: object
|
||||
internal_api.UpdateIPBanRequest:
|
||||
properties:
|
||||
expires_at:
|
||||
$ref: '#/definitions/internal_api.optionalInt64'
|
||||
reason:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
type: object
|
||||
internal_api.UpdateMasterRequest:
|
||||
properties:
|
||||
global_qps:
|
||||
@@ -1162,17 +1248,56 @@ definitions:
|
||||
description: active/suspended
|
||||
type: string
|
||||
type: object
|
||||
internal_api.WhoamiRealtimeView:
|
||||
properties:
|
||||
qps:
|
||||
description: Current QPS
|
||||
example: 5
|
||||
type: integer
|
||||
qps_limit:
|
||||
description: QPS limit
|
||||
example: 100
|
||||
type: integer
|
||||
rate_limited:
|
||||
description: Whether currently rate limited
|
||||
example: false
|
||||
type: boolean
|
||||
requests:
|
||||
description: Total requests
|
||||
example: 100
|
||||
type: integer
|
||||
tokens:
|
||||
description: Total tokens used
|
||||
example: 50000
|
||||
type: integer
|
||||
updated_at:
|
||||
description: Last updated timestamp
|
||||
example: 1703505600
|
||||
type: integer
|
||||
type: object
|
||||
internal_api.WhoamiResponse:
|
||||
properties:
|
||||
allow_ips:
|
||||
description: IP whitelist (for diagnostics)
|
||||
example: ""
|
||||
type: string
|
||||
created_at:
|
||||
example: 1703505600
|
||||
type: integer
|
||||
default_namespace:
|
||||
example: default
|
||||
type: string
|
||||
deny_ips:
|
||||
description: IP blacklist (for diagnostics)
|
||||
example: ""
|
||||
type: string
|
||||
epoch:
|
||||
example: 1
|
||||
type: integer
|
||||
expires_at:
|
||||
description: Expiration timestamp (0 = never)
|
||||
example: 0
|
||||
type: integer
|
||||
global_qps:
|
||||
example: 100
|
||||
type: integer
|
||||
@@ -1189,19 +1314,64 @@ definitions:
|
||||
issued_by:
|
||||
example: master
|
||||
type: string
|
||||
last_accessed_at:
|
||||
description: Last access timestamp
|
||||
example: 0
|
||||
type: integer
|
||||
master_id:
|
||||
description: Key fields (only present when type is "key")
|
||||
example: 1
|
||||
type: integer
|
||||
master_name:
|
||||
description: Parent master name (for display)
|
||||
example: tenant-a
|
||||
type: string
|
||||
max_child_keys:
|
||||
example: 5
|
||||
type: integer
|
||||
model_limits:
|
||||
description: Model restrictions
|
||||
example: gpt-4,claude
|
||||
type: string
|
||||
model_limits_enabled:
|
||||
description: Whether model limits are active
|
||||
example: false
|
||||
type: boolean
|
||||
name:
|
||||
example: tenant-a
|
||||
type: string
|
||||
namespaces:
|
||||
example: default,ns1
|
||||
type: string
|
||||
permissions:
|
||||
description: Admin permissions (always ["*"])
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
quota_limit:
|
||||
description: Token quota limit (-1 = unlimited)
|
||||
example: -1
|
||||
type: integer
|
||||
quota_reset_at:
|
||||
description: Quota reset timestamp
|
||||
example: 0
|
||||
type: integer
|
||||
quota_reset_type:
|
||||
description: Quota reset type
|
||||
example: monthly
|
||||
type: string
|
||||
quota_used:
|
||||
description: Token quota used
|
||||
example: 0
|
||||
type: integer
|
||||
realtime:
|
||||
allOf:
|
||||
- $ref: '#/definitions/internal_api.WhoamiRealtimeView'
|
||||
description: Realtime stats (for master and key types)
|
||||
request_count:
|
||||
description: Total request count (from DB)
|
||||
example: 0
|
||||
type: integer
|
||||
role:
|
||||
description: Admin fields (only present when type is "admin")
|
||||
example: admin
|
||||
@@ -1219,6 +1389,10 @@ definitions:
|
||||
updated_at:
|
||||
example: 1703505600
|
||||
type: integer
|
||||
used_tokens:
|
||||
description: Total tokens used (from DB)
|
||||
example: 0
|
||||
type: integer
|
||||
type: object
|
||||
internal_api.apiKeyStatsFlushEntry:
|
||||
properties:
|
||||
@@ -1236,6 +1410,14 @@ definitions:
|
||||
$ref: '#/definitions/internal_api.apiKeyStatsFlushEntry'
|
||||
type: array
|
||||
type: object
|
||||
internal_api.optionalInt64:
|
||||
properties:
|
||||
set:
|
||||
type: boolean
|
||||
value:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
internal_api.refreshModelRegistryRequest:
|
||||
properties:
|
||||
ref:
|
||||
@@ -2086,7 +2268,7 @@ paths:
|
||||
description: Returns aggregated metrics for dashboard display including requests,
|
||||
tokens, latency, masters, keys, and provider keys statistics
|
||||
parameters:
|
||||
- description: 'time period: today, week, month, all'
|
||||
- description: 'time period: today, week, month, last7d, last30d, all'
|
||||
in: query
|
||||
name: period
|
||||
type: string
|
||||
@@ -2098,6 +2280,10 @@ paths:
|
||||
in: query
|
||||
name: until
|
||||
type: integer
|
||||
- description: include trend data comparing to previous period
|
||||
in: query
|
||||
name: include_trends
|
||||
type: boolean
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -2169,6 +2355,177 @@ paths:
|
||||
summary: Update feature flags
|
||||
tags:
|
||||
- admin
|
||||
/admin/ip-bans:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: List all global IP/CIDR ban rules
|
||||
parameters:
|
||||
- description: Filter by status (active, expired)
|
||||
in: query
|
||||
name: status
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/internal_api.IPBanView'
|
||||
type: array
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/gin.H'
|
||||
security:
|
||||
- AdminAuth: []
|
||||
summary: List IP bans
|
||||
tags:
|
||||
- admin
|
||||
- ip-bans
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Create a new global IP/CIDR ban rule
|
||||
parameters:
|
||||
- description: IP Ban Info
|
||||
in: body
|
||||
name: ban
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/internal_api.CreateIPBanRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
schema:
|
||||
$ref: '#/definitions/internal_api.IPBanView'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/gin.H'
|
||||
"409":
|
||||
description: Conflict
|
||||
schema:
|
||||
$ref: '#/definitions/gin.H'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/gin.H'
|
||||
security:
|
||||
- AdminAuth: []
|
||||
summary: Create an IP ban
|
||||
tags:
|
||||
- admin
|
||||
- ip-bans
|
||||
/admin/ip-bans/{id}:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Delete a global IP/CIDR ban rule
|
||||
parameters:
|
||||
- description: IP Ban ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: '#/definitions/gin.H'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/gin.H'
|
||||
security:
|
||||
- AdminAuth: []
|
||||
summary: Delete an IP ban
|
||||
tags:
|
||||
- admin
|
||||
- ip-bans
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Get a single global IP/CIDR ban rule by ID
|
||||
parameters:
|
||||
- description: IP Ban ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/internal_api.IPBanView'
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: '#/definitions/gin.H'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/gin.H'
|
||||
security:
|
||||
- AdminAuth: []
|
||||
summary: Get an IP ban
|
||||
tags:
|
||||
- admin
|
||||
- ip-bans
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Update a global IP/CIDR ban rule
|
||||
parameters:
|
||||
- description: IP Ban ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
- description: IP Ban Update
|
||||
in: body
|
||||
name: ban
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/internal_api.UpdateIPBanRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/internal_api.IPBanView'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/gin.H'
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: '#/definitions/gin.H'
|
||||
"409":
|
||||
description: Conflict
|
||||
schema:
|
||||
$ref: '#/definitions/gin.H'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/gin.H'
|
||||
security:
|
||||
- AdminAuth: []
|
||||
summary: Update an IP ban
|
||||
tags:
|
||||
- admin
|
||||
- ip-bans
|
||||
/admin/keys/{id}/access:
|
||||
get:
|
||||
description: Returns key default_namespace and namespaces
|
||||
@@ -2375,7 +2732,8 @@ paths:
|
||||
/admin/logs/stats/traffic-chart:
|
||||
get:
|
||||
description: Get time × model aggregated data for stacked traffic charts. Returns
|
||||
time buckets with per-model breakdown.
|
||||
a shared time axis under `x` and per-model series arrays aligned to that axis.
|
||||
Models outside top_n are aggregated under the series name "other".
|
||||
parameters:
|
||||
- description: 'Time granularity: hour (default) or minute'
|
||||
enum:
|
||||
@@ -3587,13 +3945,41 @@ paths:
|
||||
/auth/whoami:
|
||||
get:
|
||||
description: |-
|
||||
Returns the identity of the authenticated user based on the Authorization header.
|
||||
Returns complete identity and realtime statistics of the authenticated user.
|
||||
Supports Admin Token, Master Key, and Child Key (API Key) authentication.
|
||||
This endpoint is designed for frontend initialization - call once after login
|
||||
and store the response for subsequent use.
|
||||
|
||||
Response varies by token type:
|
||||
- Admin Token: {"type": "admin", "role": "admin"}
|
||||
- Master Key: {"type": "master", "id": 1, "name": "...", ...}
|
||||
- Child Key: {"type": "key", "id": 5, "master_id": 1, "issued_by": "master", ...}
|
||||
**Response varies by token type:**
|
||||
|
||||
**Admin Token:**
|
||||
- type: "admin"
|
||||
- role: "admin"
|
||||
- permissions: ["*"] (full access)
|
||||
|
||||
**Master Key:**
|
||||
- type: "master"
|
||||
- Basic info: id, name, group, namespaces, status, epoch, max_child_keys, global_qps
|
||||
- Timestamps: created_at, updated_at
|
||||
- Realtime stats: requests, tokens, qps, qps_limit, rate_limited
|
||||
|
||||
**Child Key (API Key):**
|
||||
- type: "key"
|
||||
- Basic info: id, master_id, master_name, group, scopes, namespaces, status
|
||||
- Security: issued_at_epoch, issued_by, allow_ips, deny_ips, expires_at
|
||||
- Model limits: model_limits, model_limits_enabled
|
||||
- Quota: quota_limit, quota_used, quota_reset_at, quota_reset_type
|
||||
- Usage stats: request_count, used_tokens, last_accessed_at
|
||||
- Realtime stats: requests, tokens, qps, qps_limit, rate_limited
|
||||
|
||||
**Error responses:**
|
||||
- 401: authorization header required
|
||||
- 401: invalid authorization header format
|
||||
- 401: invalid token
|
||||
- 401: token is not active
|
||||
- 401: token has expired
|
||||
- 401: token has been revoked
|
||||
- 401: master is not active
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
||||
Reference in New Issue
Block a user