// 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 };