// AI provider logo SVGs — regex-based matching for self-hosted model names
// Uses official logos from Simple Icons where available, custom minimal SVGs otherwise
// All SVGs use viewBox="0 0 24 24" fill="currentColor"
const _PROVIDERS = [
// Ollama
[/ollama|:11434/i,
''],
// OpenAI — GPT, o1, o3, dall-e, chatgpt
[/openai|gpt-|^o[13]-|chatgpt|dall-e/i,
''],
// OpenRouter
[/openrouter|open router/i,
''],
// Ollama / Ollama Cloud
[/ollama/i,
''],
// Anthropic — Claude (official Simple Icons)
[/anthropic|claude/i,
''],
// Google Gemini (official Simple Icons)
[/google|gemini|gemma/i,
''],
// Meta — Llama models (official Simple Icons). Exclude the llama.cpp / llama-cpp
// / llamacpp inference engine — that's an independent project (ggml), not Meta.
[/meta|llama(?![.\-_ ]?cpp)/i,
''],
// Mistral AI (official Simple Icons). Match Mixtral and Ministral too.
[/mi[sx]tral|ministral/i,
''],
// Qwen (Tongyi Qianwen) — official geometric hexagonal logo
[/qwen|alibaba/i,
''],
// DeepSeek (official whale logo from LobeHub icons)
[/deepseek/i,
''],
// xAI — Grok (stylized X)
[/x-ai|xai|grok/i,
''],
// Cohere — Command (stylized C)
[/cohere|command-r/i,
''],
// Perplexity (official Simple Icons)
[/perplexity|sonar/i,
''],
// Nous Research / Hermes
[/nous|hermes/i,
''],
// Microsoft / Phi (four squares)
[/microsoft|phi-/i,
''],
// Zhipu AI — GLM, ChatGLM (official Z logo)
[/zhipu|glm|chatglm/i,
''],
// MiniMax
[/minimax/i,
''],
// Kimi / Moonshot AI (crescent moon)
[/kimi|moonshot/i,
''],
// NVIDIA / Nemotron (official Simple Icons)
[/nvidia|nemotron/i,
''],
];
// Returns an SVG string for the given model ID, or null if no match
export function providerLogo(modelId) {
if (!modelId) return null;
for (const [re, svg] of _PROVIDERS) {
if (re.test(modelId)) return svg;
}
return null;
}
// Host suffix → friendly provider label. The model-info card shows this so the
// SAME model name served by DIFFERENT routes is distinguishable (e.g.
// `claude-haiku` via OpenRouter vs GitHub Copilot vs Anthropic direct); the logo
// only reflects the model vendor, not the actual endpoint. Patterns are anchored
// to the end of the hostname (^|.)domain$ so a host like `max.airlines.com`
// doesn't match `x.ai`.
const _ENDPOINT_LABELS = [
[/(^|\.)githubcopilot\.com$/i, "GitHub Copilot"],
[/(^|\.)openrouter\.ai$/i, "OpenRouter"],
[/(^|\.)anthropic\.com$/i, "Anthropic"],
[/(^|\.)openai\.com$/i, "OpenAI"],
[/(^|\.)(generativelanguage|aiplatform)\.googleapis\.com$/i, "Google"],
[/(^|\.)bedrock[\w.-]*\.amazonaws\.com$/i, "AWS Bedrock"],
[/(^|\.)deepseek\.com$/i, "DeepSeek"],
[/(^|\.)mistral\.ai$/i, "Mistral"],
[/(^|\.)groq\.com$/i, "Groq"],
[/(^|\.)together\.(ai|xyz)$/i, "Together"],
[/(^|\.)fireworks\.ai$/i, "Fireworks"],
[/(^|\.)perplexity\.ai$/i, "Perplexity"],
[/(^|\.)x\.ai$/i, "xAI"],
];
/**
* Friendly label for the endpoint that served a model, from its URL.
* Returns "Local" for loopback/LAN hosts, a known provider name when matched,
* else the bare host. Null when no URL is available.
*/
export function providerLabel(endpointUrl) {
if (!endpointUrl || typeof endpointUrl !== "string") return null;
let host;
try {
host = new URL(endpointUrl).hostname;
} catch (_) {
// Not a full URL (e.g. bare host[:port]) — strip scheme/path/port best-effort.
host = endpointUrl.replace(/^[a-z]+:\/\//i, "").split("/")[0].split(":")[0];
}
if (!host) return null;
if (/^(localhost|127\.|0\.0\.0\.0|::1|192\.168\.|10\.|172\.(1[6-9]|2\d|3[01])\.)/i.test(host)) {
return "Local";
}
for (const [re, label] of _ENDPOINT_LABELS) {
if (re.test(host)) return label;
}
// Unknown host → drop a leading "api." for a cleaner readout.
return host.replace(/^api\./i, "");
}
export default { providerLogo, providerLabel };