| 24 | } |
| 25 | |
| 26 | export const ModelTooltip: Component<{ model: ModelInfo; latest?: boolean; free?: boolean }> = (props) => { |
| 27 | const language = useLanguage() |
| 28 | const sourceName = (model: ModelInfo) => { |
| 29 | const value = `${model.id} ${model.name}`.toLowerCase() |
| 30 | |
| 31 | if (/claude|anthropic/.test(value)) return language.t("model.provider.anthropic") |
| 32 | if (/gpt|o[1-4]|codex|openai/.test(value)) return language.t("model.provider.openai") |
| 33 | if (/gemini|palm|bard|google/.test(value)) return language.t("model.provider.google") |
| 34 | if (/grok|xai/.test(value)) return language.t("model.provider.xai") |
| 35 | if (/llama|meta/.test(value)) return language.t("model.provider.meta") |
| 36 | |
| 37 | return model.provider.name |
| 38 | } |
| 39 | const inputLabel = (value: string) => { |
| 40 | if (value === "text") return language.t("model.input.text") |
| 41 | if (value === "image") return language.t("model.input.image") |
| 42 | if (value === "audio") return language.t("model.input.audio") |
| 43 | if (value === "video") return language.t("model.input.video") |
| 44 | if (value === "pdf") return language.t("model.input.pdf") |
| 45 | return value |
| 46 | } |
| 47 | const title = () => { |
| 48 | const tags: Array<string> = [] |
| 49 | if (props.latest) tags.push(language.t("model.tag.latest")) |
| 50 | if (props.free) tags.push(language.t("model.tag.free")) |
| 51 | const suffix = tags.length ? ` (${tags.join(", ")})` : "" |
| 52 | return `${sourceName(props.model)} ${props.model.name}${suffix}` |
| 53 | } |
| 54 | const inputs = () => { |
| 55 | if (props.model.capabilities) { |
| 56 | const input = props.model.capabilities.input |
| 57 | const order: Array<InputKey> = ["text", "image", "audio", "video", "pdf"] |
| 58 | const entries = order.filter((key) => input[key]).map((key) => inputLabel(key)) |
| 59 | return entries.length ? entries.join(", ") : undefined |
| 60 | } |
| 61 | const raw = props.model.modalities?.input |
| 62 | if (!raw) return |
| 63 | const entries = raw.map((value) => inputLabel(value)) |
| 64 | return entries.length ? entries.join(", ") : undefined |
| 65 | } |
| 66 | const reasoning = () => { |
| 67 | if (props.model.capabilities) |
| 68 | return props.model.capabilities.reasoning |
| 69 | ? language.t("model.tooltip.reasoning.allowed") |
| 70 | : language.t("model.tooltip.reasoning.none") |
| 71 | return props.model.reasoning |
| 72 | ? language.t("model.tooltip.reasoning.allowed") |
| 73 | : language.t("model.tooltip.reasoning.none") |
| 74 | } |
| 75 | const context = () => language.t("model.tooltip.context", { limit: props.model.limit.context.toLocaleString() }) |
| 76 | |
| 77 | return ( |
| 78 | <div class="flex flex-col gap-1 py-1"> |
| 79 | <div class="text-13-medium">{title()}</div> |
| 80 | <Show when={inputs()}> |
| 81 | {(value) => ( |
| 82 | <div class="text-12-regular text-text-invert-base"> |
| 83 | {language.t("model.tooltip.allows", { inputs: value() })} |