Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
package aiprovider
|
||||
|
||||
import "strings"
|
||||
|
||||
// Mode values stored on ai_providers.mode (UI / API).
|
||||
const (
|
||||
ModeInternal = "internal"
|
||||
ModePopular = "popular"
|
||||
ModeCustom = "custom"
|
||||
)
|
||||
|
||||
// ModeInternalLabel is the analytics / job recording value when using platform OpenAI (admin settings or env fallback).
|
||||
const ModeInternalLabel = "internal"
|
||||
|
||||
// ModeCustomLabel is the analytics value for custom OpenAI-compatible endpoints.
|
||||
const ModeCustomLabel = "custom"
|
||||
|
||||
// PopularProvider is a curated OpenAI-compatible catalog entry.
|
||||
type PopularProvider struct {
|
||||
Name string `json:"name"`
|
||||
Label string `json:"label"`
|
||||
BaseURL string `json:"base_url"`
|
||||
DefaultModel string `json:"default_model"`
|
||||
Models []string `json:"models"`
|
||||
}
|
||||
|
||||
// PopularCatalog lists OpenAI-compatible providers tenants can pick by API key only.
|
||||
var PopularCatalog = []PopularProvider{
|
||||
{
|
||||
Name: "openai",
|
||||
Label: "OpenAI",
|
||||
BaseURL: "https://api.openai.com/v1",
|
||||
DefaultModel: "gpt-4o-mini",
|
||||
Models: []string{"gpt-4o-mini", "gpt-4o", "gpt-4.1-mini", "gpt-4.1"},
|
||||
},
|
||||
{
|
||||
Name: "google",
|
||||
Label: "Google (Gemini OpenAI compat)",
|
||||
BaseURL: "https://generativelanguage.googleapis.com/v1beta/openai",
|
||||
DefaultModel: "gemini-2.0-flash",
|
||||
Models: []string{"gemini-2.0-flash", "gemini-2.5-flash", "gemini-2.0-flash-lite"},
|
||||
},
|
||||
{
|
||||
Name: "groq",
|
||||
Label: "Groq",
|
||||
BaseURL: "https://api.groq.com/openai/v1",
|
||||
DefaultModel: "llama-3.3-70b-versatile",
|
||||
Models: []string{"llama-3.3-70b-versatile", "llama-3.1-8b-instant", "mixtral-8x7b-32768"},
|
||||
},
|
||||
{
|
||||
Name: "mistral",
|
||||
Label: "Mistral",
|
||||
BaseURL: "https://api.mistral.ai/v1",
|
||||
DefaultModel: "mistral-small-latest",
|
||||
Models: []string{"mistral-small-latest", "mistral-medium-latest", "mistral-large-latest"},
|
||||
},
|
||||
{
|
||||
Name: "deepseek",
|
||||
Label: "DeepSeek",
|
||||
BaseURL: "https://api.deepseek.com/v1",
|
||||
DefaultModel: "deepseek-chat",
|
||||
Models: []string{"deepseek-chat", "deepseek-reasoner"},
|
||||
},
|
||||
{
|
||||
Name: "openrouter",
|
||||
Label: "OpenRouter",
|
||||
BaseURL: "https://openrouter.ai/api/v1",
|
||||
DefaultModel: "openai/gpt-4o-mini",
|
||||
Models: []string{"openai/gpt-4o-mini", "anthropic/claude-sonnet-4", "google/gemini-2.0-flash-001"},
|
||||
},
|
||||
}
|
||||
|
||||
func FindPopular(name string) (PopularProvider, bool) {
|
||||
name = strings.ToLower(strings.TrimSpace(name))
|
||||
for _, p := range PopularCatalog {
|
||||
if p.Name == name {
|
||||
return p, true
|
||||
}
|
||||
}
|
||||
return PopularProvider{}, false
|
||||
}
|
||||
|
||||
// AnalyticsMode returns the recorded provider mode for jobs/products.
|
||||
// Contract for analytics: "internal" | "popular:<name>" | "custom"
|
||||
func AnalyticsMode(mode, popularName string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(mode)) {
|
||||
case ModePopular:
|
||||
name := strings.ToLower(strings.TrimSpace(popularName))
|
||||
if name == "" {
|
||||
name = "unknown"
|
||||
}
|
||||
return "popular:" + name
|
||||
case ModeCustom:
|
||||
return ModeCustomLabel
|
||||
default:
|
||||
return ModeInternalLabel
|
||||
}
|
||||
}
|
||||
|
||||
// AnalyticsClass maps a stored ai_provider_mode value to a rollup class.
|
||||
// Returns: internal | popular | custom | unknown
|
||||
func AnalyticsClass(modeLabel string) string {
|
||||
m := strings.ToLower(strings.TrimSpace(modeLabel))
|
||||
switch {
|
||||
case m == "" || m == "unknown":
|
||||
return "unknown"
|
||||
case m == ModeInternalLabel || m == ModeInternal:
|
||||
return ModeInternal
|
||||
case m == ModeCustomLabel || m == ModeCustom:
|
||||
return ModeCustom
|
||||
case strings.HasPrefix(m, "popular:"):
|
||||
return ModePopular
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// NormalizeAnalyticsMode coerces free-form labels into the analytics contract.
|
||||
func NormalizeAnalyticsMode(modeLabel string) string {
|
||||
m := strings.ToLower(strings.TrimSpace(modeLabel))
|
||||
switch {
|
||||
case m == "" || m == "unknown":
|
||||
return "unknown"
|
||||
case m == ModeInternalLabel || m == ModeInternal:
|
||||
return ModeInternalLabel
|
||||
case m == ModeCustomLabel || m == ModeCustom:
|
||||
return ModeCustomLabel
|
||||
case strings.HasPrefix(m, "popular:"):
|
||||
name := strings.TrimSpace(strings.TrimPrefix(m, "popular:"))
|
||||
if name == "" {
|
||||
name = "unknown"
|
||||
}
|
||||
return "popular:" + name
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeMode(mode string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(mode)) {
|
||||
case ModePopular:
|
||||
return ModePopular
|
||||
case ModeCustom:
|
||||
return ModeCustom
|
||||
default:
|
||||
return ModeInternal
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user