Files
Luminary/internal/provider/endpoints.go
T
renjue 76ba500417
CI / docker (push) Successful in 2m4s
Initial commit: Luminary AI Gateway
OpenAI-compatible AI gateway with Vue admin UI, multi-provider egress,
ingress key governance, monitoring, and security controls.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-23 21:46:16 +08:00

177 lines
6.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package provider
import (
"strings"
"github.com/rose_cat707/luminary/internal/model"
)
// EndpointType 接口类型,对应入口 /v1/* 与上游 path 映射
type EndpointType string
const (
EndpointListModels EndpointType = "list_models"
EndpointTextCompletion EndpointType = "text_completion"
EndpointChatCompletion EndpointType = "chat_completion"
EndpointResponses EndpointType = "responses"
EndpointEmbeddings EndpointType = "embeddings"
EndpointRerank EndpointType = "rerank"
EndpointSpeech EndpointType = "speech"
EndpointTranscription EndpointType = "transcription"
EndpointImageGeneration EndpointType = "image_generation"
)
type EndpointMeta struct {
Key EndpointType `json:"key"`
Label string `json:"label"`
Method string `json:"method"`
IngressPath string `json:"ingress_path"`
Categories []model.ProviderCategory `json:"categories"`
}
var AllEndpoints = []EndpointMeta{
{Key: EndpointListModels, Label: "List Models", Method: "GET", IngressPath: "/v1/models", Categories: []model.ProviderCategory{model.CategoryLLM, model.CategoryEmbedding, model.CategoryRerank}},
{Key: EndpointTextCompletion, Label: "Text Completion", Method: "POST", IngressPath: "/v1/completions", Categories: []model.ProviderCategory{model.CategoryLLM}},
{Key: EndpointChatCompletion, Label: "Chat Completion", Method: "POST", IngressPath: "/v1/chat/completions", Categories: []model.ProviderCategory{model.CategoryLLM}},
{Key: EndpointResponses, Label: "Responses", Method: "POST", IngressPath: "/v1/responses", Categories: []model.ProviderCategory{model.CategoryLLM}},
{Key: EndpointEmbeddings, Label: "Embeddings", Method: "POST", IngressPath: "/v1/embeddings", Categories: []model.ProviderCategory{model.CategoryEmbedding}},
{Key: EndpointRerank, Label: "Rerank", Method: "POST", IngressPath: "/v1/rerank", Categories: []model.ProviderCategory{model.CategoryRerank}},
{Key: EndpointSpeech, Label: "Speech", Method: "POST", IngressPath: "/v1/audio/speech", Categories: []model.ProviderCategory{model.CategorySpeech}},
{Key: EndpointTranscription, Label: "Transcription", Method: "POST", IngressPath: "/v1/audio/transcriptions", Categories: []model.ProviderCategory{model.CategoryAudio}},
{Key: EndpointImageGeneration, Label: "Image Generation", Method: "POST", IngressPath: "/v1/images/generations", Categories: []model.ProviderCategory{model.CategoryImage}},
}
// DefaultPaths 各 Provider 类型的默认上游 path(相对 base_url
var DefaultPaths = map[model.ProviderType]map[EndpointType]string{
model.ProviderOpenAI: {
EndpointListModels: "/models",
EndpointTextCompletion: "/completions",
EndpointChatCompletion: "/chat/completions",
EndpointResponses: "/responses",
EndpointEmbeddings: "/embeddings",
EndpointRerank: "/rerank",
EndpointSpeech: "/audio/speech",
EndpointTranscription: "/audio/transcriptions",
EndpointImageGeneration: "/images/generations",
},
model.ProviderAnthropic: {
EndpointListModels: "/models",
EndpointChatCompletion: "/messages",
},
model.ProviderCustom: {
EndpointListModels: "/models",
EndpointTextCompletion: "/completions",
EndpointChatCompletion: "/chat/completions",
EndpointResponses: "/responses",
EndpointEmbeddings: "/embeddings",
EndpointRerank: "/rerank",
EndpointSpeech: "/audio/speech",
EndpointTranscription: "/audio/transcriptions",
EndpointImageGeneration: "/images/generations",
},
model.ProviderAzureOpenAI: {
EndpointListModels: "/models",
EndpointChatCompletion: "/chat/completions",
EndpointResponses: "/responses",
EndpointEmbeddings: "/embeddings",
EndpointRerank: "/rerank",
},
model.ProviderOpenRouter: {
EndpointListModels: "/models",
EndpointChatCompletion: "/chat/completions",
EndpointResponses: "/responses",
EndpointEmbeddings: "/embeddings",
EndpointRerank: "/rerank",
},
model.ProviderOllama: {
EndpointListModels: "/models",
EndpointChatCompletion: "/chat/completions",
EndpointEmbeddings: "/embeddings",
EndpointRerank: "/rerank",
},
model.ProviderComfyUI: {},
}
func DefaultPath(providerType model.ProviderType, endpoint EndpointType) string {
if m, ok := DefaultPaths[providerType]; ok {
if p, ok := m[endpoint]; ok {
return p
}
}
if p, ok := DefaultPaths[model.ProviderOpenAI][endpoint]; ok {
return p
}
return ""
}
// DefaultEndpointsForCategory 创建出口时默认启用的 endpoint keys
func DefaultEndpointsForCategory(cat model.ProviderCategory) []string {
switch cat {
case model.CategoryEmbedding:
return []string{string(EndpointListModels), string(EndpointEmbeddings)}
case model.CategoryRerank:
return []string{string(EndpointListModels), string(EndpointRerank)}
case model.CategoryImage:
return []string{}
default:
return []string{string(EndpointListModels), string(EndpointChatCompletion)}
}
}
func EndpointsForCategory(cat model.ProviderCategory) []EndpointMeta {
var out []EndpointMeta
for _, e := range AllEndpoints {
for _, c := range e.Categories {
if c == cat {
out = append(out, e)
break
}
}
}
return out
}
// ResolveURL 解析最终请求 URLoverride 可为相对 path 或完整 URL
func ResolveURL(baseURL, override, defaultPath string) string {
if override != "" {
if strings.HasPrefix(override, "http://") || strings.HasPrefix(override, "https://") {
return override
}
return joinURL(baseURL, override)
}
return joinURL(baseURL, defaultPath)
}
func joinURL(base, path string) string {
base = strings.TrimRight(base, "/")
if path == "" {
return base
}
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
if base == "" {
return path
}
return base + path
}
func CategoryLabel(cat model.ProviderCategory) string {
switch cat {
case model.CategoryLLM:
return "语言模型"
case model.CategoryEmbedding:
return "向量嵌入"
case model.CategoryRerank:
return "重排序"
case model.CategorySpeech:
return "语音合成"
case model.CategoryImage:
return "图像生成"
case model.CategoryAudio:
return "音频转写"
default:
return string(cat)
}
}