'use strict'; /** * openvibe-shared/ai-marks — the AI makers' marks, one place for every site that lists models (Exchange, Report, Chat, * Bench, Design). The owner, 11-09, on Exchange's home: model-family glyphs we drew ourselves read as "what is it even * supposed to be?"; the AI comparison plan asks for the makers' recognisable marks, as every leaderboard shows them. * * const marks = require('openvibe-shared/ai-marks'); * marks.family('deepseek/deepseek-chat') → 'DeepSeek' (a model id, a slug, a family or a provider name) * marks.mark('anthropic', { size: 24 }) → … * marks.mark('someone-new') → the neutral spark (never a letter in a circle, never another maker's mark) * marks.CSS the few rules (a tile in the theme's tokens), once per page * * Marks are monochrome in currentColor (they follow the theme); the maker's name is the label (label: false when the row * already names it). The drawings come from @lobehub/icons-static-svg (MIT; see ai-marks-data.js and NOTICE in it). */ const DATA = require('./ai-marks-data'); const NAMES = { OpenAI: 'OpenAI', Anthropic: 'Anthropic', Google: 'Google', Gemma: 'Gemma', Meta: 'Meta', DeepSeek: 'DeepSeek', Qwen: 'Qwen', Mistral: 'Mistral AI', Kimi: 'Moonshot AI', GLM: 'Zhipu AI', MiniMax: 'MiniMax', Microsoft: 'Microsoft', xAI: 'xAI', NVIDIA: 'NVIDIA', Cohere: 'Cohere', Perplexity: 'Perplexity', }; // Order matters: the more specific first (gemma before gemini/google; grok before x). const RULES = [ [/gemma/i, 'Gemma'], [/gemini|google|palm|bard/i, 'Google'], [/claude|anthropic/i, 'Anthropic'], [/deepseek/i, 'DeepSeek'], [/qwen|qwq|alibaba|tongyi/i, 'Qwen'], [/kimi|moonshot/i, 'Kimi'], [/glm|zhipu|z\.ai|chatglm/i, 'GLM'], [/minimax|abab/i, 'MiniMax'], [/llama|meta\b|^meta|facebook/i, 'Meta'], [/mistral|mixtral|codestral|ministral|magistral|pixtral/i, 'Mistral'], [/\bphi-?\d|microsoft|wizardlm/i, 'Microsoft'], [/grok|x-ai|\bxai\b/i, 'xAI'], [/nvidia|nemotron/i, 'NVIDIA'], [/cohere|command-?r|\baya\b/i, 'Cohere'], [/perplexity|sonar/i, 'Perplexity'], [/openai|gpt|\bo[134](-|\b)|chatgpt|davinci|whisper|dall-?e/i, 'OpenAI'], ]; const SPARK = ''; const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c])); /** The maker's family key for a model id, slug, family or provider name; null when none matches. */ function family(text) { const t = String(text || '').trim(); if (!t) return null; const exact = Object.keys(DATA).find((k) => k.toLowerCase() === t.toLowerCase()); if (exact) return exact; for (const [re, key] of RULES) if (re.test(t)) return key; return null; } /** The mark as HTML: a tile with the maker's drawing (or the neutral spark), labelled with the maker's name. */ function mark(text, { size = 24, label = true, cls = '' } = {}) { const key = family(text); const px = Math.max(12, Math.min(96, Number(size) || 24)); const name = key ? NAMES[key] : String(text || 'Other'); const svg = ``; return ``; } const CSS = '.ov-aim{display:inline-grid;place-items:center;flex:none;width:var(--ov-aim,24px);height:var(--ov-aim,24px);border-radius:calc(var(--ov-aim,24px) * .28);' + 'background:color-mix(in srgb,var(--text-primary,#e8ecf3) 8%,transparent);color:var(--text-primary,#e8ecf3);box-shadow:inset 0 0 0 1px var(--border,rgba(255,255,255,.1))}' + '.ov-aim svg{display:block}.ov-aim--other{color:var(--accent,#3b82f6)}'; module.exports = { family, mark, CSS, FAMILIES: Object.keys(DATA), NAMES };