Files
team-api/internal/logic/docs/openapi.go
T
2026-06-03 15:34:38 +08:00

302 lines
10 KiB
Go

package docs
import (
"context"
"encoding/json"
"github.com/gogf/gf/v2/frame/g"
v1 "github.com/qianfree/team-api/api/docs/v1"
"github.com/qianfree/team-api/internal/logic/common"
"github.com/qianfree/team-api/internal/service"
)
func init() {
service.RegisterDocs(New())
}
type sDocs struct{}
func New() *sDocs {
return &sDocs{}
}
func (s *sDocs) OpenAPISpec(ctx context.Context, _ *v1.OpenAPISpecReq) (json.RawMessage, error) {
// Try cache first
cached, err := g.Redis().Do(ctx, "GET", "docs:openapi:spec")
if err == nil && !cached.IsNil() && !cached.IsEmpty() {
return json.RawMessage(cached.String()), nil
}
spec := buildOpenAPISpec()
raw, err := json.Marshal(spec)
if err != nil {
return nil, err
}
// Cache for 1 hour
_, _ = g.Redis().Do(ctx, "SET", "docs:openapi:spec", string(raw), "EX", 3600)
return raw, nil
}
func buildOpenAPISpec() map[string]any {
baseURL := common.Config().GetString(nil, "api_base_url")
if baseURL == "" {
baseURL = "https://api.team-api.example.com"
}
return map[string]any{
"openapi": "3.0.3",
"info": map[string]any{
"title": "Team API",
"description": "多租户 大模型 API 网关,兼容 OpenAI API 格式",
"version": "1.0.0",
},
"servers": []map[string]any{
{"url": baseURL, "description": "Production"},
},
"paths": map[string]any{
"/v1/chat/completions": map[string]any{
"post": map[string]any{
"summary": "Chat Completions",
"description": "创建聊天补全,兼容 OpenAI API 格式,支持流式和非流式响应。",
"operationId": "createChatCompletion",
"security": []map[string]any{{"BearerAuth": []any{}}},
"requestBody": map[string]any{
"required": true,
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{"$ref": "#/components/schemas/ChatCompletionRequest"},
},
},
},
"responses": map[string]any{
"200": map[string]any{
"description": "Successful response",
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{"$ref": "#/components/schemas/ChatCompletionResponse"},
},
"text/event-stream": map[string]any{
"schema": map[string]any{"type": "string", "description": "SSE stream"},
},
},
},
"401": map[string]any{"description": "Authentication failed"},
"402": map[string]any{"description": "Insufficient quota"},
"429": map[string]any{"description": "Rate limit exceeded"},
"500": map[string]any{"description": "Internal error"},
},
},
},
"/v1/completions": map[string]any{
"post": map[string]any{
"summary": "Text Completions",
"description": "文本补全,兼容 OpenAI API 格式。",
"operationId": "createCompletion",
"security": []map[string]any{{"BearerAuth": []any{}}},
"requestBody": map[string]any{
"required": true,
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{"$ref": "#/components/schemas/CompletionRequest"},
},
},
},
"responses": map[string]any{
"200": map[string]any{"description": "Successful response"},
},
},
},
"/v1/embeddings": map[string]any{
"post": map[string]any{
"summary": "Embeddings",
"description": "创建文本向量嵌入,兼容 OpenAI API 格式。",
"operationId": "createEmbedding",
"security": []map[string]any{{"BearerAuth": []any{}}},
"requestBody": map[string]any{
"required": true,
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{"$ref": "#/components/schemas/EmbeddingRequest"},
},
},
},
"responses": map[string]any{
"200": map[string]any{"description": "Successful response"},
},
},
},
"/v1/images/generations": map[string]any{
"post": map[string]any{
"summary": "Image Generations",
"description": "AI 图像生成,兼容 OpenAI API 格式。",
"operationId": "createImage",
"security": []map[string]any{{"BearerAuth": []any{}}},
"requestBody": map[string]any{
"required": true,
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{
"type": "object",
"required": []string{"model", "prompt"},
"properties": map[string]any{
"model": map[string]any{"type": "string", "example": "dall-e-3"},
"prompt": map[string]any{"type": "string"},
"n": map[string]any{"type": "integer", "default": 1},
"size": map[string]any{"type": "string", "enum": []string{"256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"}},
},
},
},
},
},
"responses": map[string]any{
"200": map[string]any{"description": "Successful response"},
},
},
},
"/v1/messages": map[string]any{
"post": map[string]any{
"summary": "Claude Messages",
"description": "Claude Messages API,兼容 Anthropic API 格式。",
"operationId": "createClaudeMessage",
"security": []map[string]any{{"BearerAuth": []any{}}},
"requestBody": map[string]any{
"required": true,
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{
"type": "object",
"required": []string{"model", "messages"},
"properties": map[string]any{
"model": map[string]any{"type": "string", "example": "claude-sonnet-4-20250514"},
"messages": map[string]any{"type": "array"},
"max_tokens": map[string]any{"type": "integer", "default": 4096},
"stream": map[string]any{"type": "boolean", "default": false},
},
},
},
},
},
"responses": map[string]any{
"200": map[string]any{"description": "Successful response"},
},
},
},
"/v1/models": map[string]any{
"get": map[string]any{
"summary": "List Models",
"description": "获取可用模型列表。",
"operationId": "listModels",
"security": []map[string]any{{"BearerAuth": []any{}}},
"responses": map[string]any{
"200": map[string]any{"description": "Successful response"},
},
},
},
"/v1/models/{model_id}": map[string]any{
"get": map[string]any{
"summary": "Get Model",
"description": "获取模型详情。",
"operationId": "getModel",
"security": []map[string]any{{"BearerAuth": []any{}}},
"parameters": []map[string]any{
{"name": "model_id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}},
},
"responses": map[string]any{
"200": map[string]any{"description": "Successful response"},
},
},
},
},
"components": map[string]any{
"securitySchemes": map[string]any{
"BearerAuth": map[string]any{
"type": "http",
"scheme": "bearer",
"bearerFormat": "API Key",
},
},
"schemas": map[string]any{
"ChatCompletionRequest": map[string]any{
"type": "object",
"required": []string{"model", "messages"},
"properties": map[string]any{
"model": map[string]any{"type": "string", "example": "gpt-4o", "description": "模型 ID"},
"messages": map[string]any{
"type": "array",
"items": map[string]any{"$ref": "#/components/schemas/ChatMessage"},
},
"temperature": map[string]any{"type": "number", "minimum": 0, "maximum": 2, "default": 1},
"top_p": map[string]any{"type": "number", "minimum": 0, "maximum": 1, "default": 1},
"max_tokens": map[string]any{"type": "integer", "minimum": 1},
"stream": map[string]any{"type": "boolean", "default": false},
"frequency_penalty": map[string]any{"type": "number", "minimum": -2, "maximum": 2},
"presence_penalty": map[string]any{"type": "number", "minimum": -2, "maximum": 2},
"stop": map[string]any{"type": "array", "items": map[string]any{"type": "string"}},
},
},
"ChatMessage": map[string]any{
"type": "object",
"required": []string{"role", "content"},
"properties": map[string]any{
"role": map[string]any{"type": "string", "enum": []string{"system", "user", "assistant"}},
"content": map[string]any{"type": "string"},
},
},
"ChatCompletionResponse": map[string]any{
"type": "object",
"properties": map[string]any{
"id": map[string]any{"type": "string"},
"object": map[string]any{"type": "string"},
"created": map[string]any{"type": "integer"},
"model": map[string]any{"type": "string"},
"choices": map[string]any{
"type": "array",
"items": map[string]any{"$ref": "#/components/schemas/ChatChoice"},
},
"usage": map[string]any{"$ref": "#/components/schemas/Usage"},
},
},
"ChatChoice": map[string]any{
"type": "object",
"properties": map[string]any{
"index": map[string]any{"type": "integer"},
"message": map[string]any{"$ref": "#/components/schemas/ChatMessage"},
"finish_reason": map[string]any{"type": "string"},
},
},
"Usage": map[string]any{
"type": "object",
"properties": map[string]any{
"prompt_tokens": map[string]any{"type": "integer"},
"completion_tokens": map[string]any{"type": "integer"},
"total_tokens": map[string]any{"type": "integer"},
},
},
"CompletionRequest": map[string]any{
"type": "object",
"required": []string{"model", "prompt"},
"properties": map[string]any{
"model": map[string]any{"type": "string", "example": "gpt-4o"},
"prompt": map[string]any{"type": "string"},
"max_tokens": map[string]any{"type": "integer", "default": 16},
"stream": map[string]any{"type": "boolean", "default": false},
},
},
"EmbeddingRequest": map[string]any{
"type": "object",
"required": []string{"model", "input"},
"properties": map[string]any{
"model": map[string]any{"type": "string", "example": "text-embedding-3-small"},
"input": map[string]any{"oneOf": []any{
map[string]any{"type": "string"},
map[string]any{"type": "array", "items": map[string]any{"type": "string"}},
}},
},
},
},
},
}
}