Files
team-api/internal/logic/docs/openapi.go
T
fa053529af 图片请求统一异步处理 (#11)
* fix:未导入unicode包

* feat:图片异步转换

* feat:添加R2支持

* feat:新增文件管理

* fix:修复错误信息双写导致响应异常

* chore:渠道列表中添加快捷启用停止按钮

* fix:修复模型异常终端导致报错的问题

* improve:优化无可用渠道的日志打印,减少日志污染

* fix:在线体验出错缺少提示信息

* fix:修复日志库问题,只有请求日志保存到独立的库中

* feat:新增阿里图片模型说明文档

* fix:阿里千问图片生成

* fix:修复图片异步控制无效问题

* improve:优化文件展示,支持缩略图查看

* feat:实时监控中添加图片异步转换池状态信息

* improve:优化在线体验页面布局

* fix:修复异步任务状态显示异常问题

* feat:图片异步任务停止时等待任务完成后再退出程序

* chore:调整存储路径

---------

Co-authored-by: qian <wuchengqian5@163.com>
Co-authored-by: chengqian <wuchengqian@kkidc.com>
2026-07-18 00:26:13 +08:00

349 lines
12 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/images/generations/async": map[string]any{
"post": map[string]any{
"summary": "Image Generations Async (Submit)",
"description": "异步图像生成任务提交。阿里云百炼(DashScope)等异步图像上游无法经同步接口一次性返回,需提交任务拿到 task_id 后轮询 /v1/images/generations/async/{task_id} 取图。",
"operationId": "createImageAsync",
"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": "wanx2.1-t2i-turbo"},
"prompt": map[string]any{"type": "string"},
"n": map[string]any{"type": "integer", "default": 1},
"size": map[string]any{"type": "string", "example": "1024x1024"},
},
},
},
},
},
"responses": map[string]any{
"200": map[string]any{"description": "任务已提交,返回 task_id 与初始状态"},
},
},
},
"/v1/images/generations/async/{task_id}": map[string]any{
"get": map[string]any{
"summary": "Image Generations Async (Fetch)",
"description": "查询异步图像生成任务结果。轮询直到 status 为 SUCCESS(含图片 url)或 FAILURE(含 error),建议间隔 2~3 秒。",
"operationId": "getImageAsync",
"security": []map[string]any{{"BearerAuth": []any{}}},
"parameters": []map[string]any{
{
"name": "task_id",
"in": "path",
"required": true,
"schema": map[string]any{"type": "string"},
},
},
"responses": map[string]any{
"200": map[string]any{"description": "任务状态与结果"},
},
},
},
"/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"}},
}},
},
},
},
},
}
}