Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: James Long <longster@gmail.com> Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Co-authored-by: Dustin Deus <deusdustin@gmail.com> Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box> Co-authored-by: Frank <frank@anoma.ly> Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com> Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com> Co-authored-by: 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 <little-frank@opencord.local> Co-authored-by: Aiden Cline <aidenpcline@gmail.com> Co-authored-by: Dax <mail@thdxr.com> Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com> Co-authored-by: Jay <53023+jayair@users.noreply.github.com> Co-authored-by: Brendan Allan <git@brendonovich.dev> Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Co-authored-by: runvip <164729189+runvip@users.noreply.github.com> Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com> Co-authored-by: Jack <jack@anoma.ly> Co-authored-by: opencode <opencode@sst.dev> Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com> Co-authored-by: Julian Coy <julian@ex-machina.co> Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com> Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com> Co-authored-by: Kit Langton <kit.langton@gmail.com> Co-authored-by: Simon Klee <hello@simonklee.dk> Co-authored-by: Jay <air@live.ca> Co-authored-by: David Hill <1879069+iamdavidhill@users.noreply.github.com> Co-authored-by: James Long <jlongster@users.noreply.github.com> Co-authored-by: 冯基魁 <56265583+fengjikui@users.noreply.github.com> Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
124 lines
4.6 KiB
TypeScript
124 lines
4.6 KiB
TypeScript
import { Show, type Component, type JSX } from "solid-js"
|
|
import { useLanguage } from "@/context/language"
|
|
|
|
type InputKey = "text" | "image" | "audio" | "video" | "pdf"
|
|
type InputMap = Record<InputKey, boolean>
|
|
|
|
type ModelInfo = {
|
|
id: string
|
|
name: string
|
|
provider: {
|
|
name: string
|
|
}
|
|
capabilities?: {
|
|
reasoning: boolean
|
|
input: InputMap
|
|
}
|
|
modalities?: {
|
|
input: Array<string>
|
|
}
|
|
reasoning?: boolean
|
|
limit: {
|
|
context: number
|
|
}
|
|
}
|
|
|
|
function ModelTooltipRow(props: { name: JSX.Element; value: JSX.Element }) {
|
|
return (
|
|
<div class="flex min-w-0 items-center gap-4">
|
|
<span class="shrink-0 text-v2-text-text-muted">{props.name}</span>
|
|
<span class="ml-auto min-w-0 truncate text-right text-v2-text-text-base">{props.value}</span>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const ModelTooltip: Component<{ model: ModelInfo; latest?: boolean; free?: boolean; v2?: boolean }> = (
|
|
props,
|
|
) => {
|
|
const language = useLanguage()
|
|
const sourceName = (model: ModelInfo) => {
|
|
const value = `${model.id} ${model.name}`.toLowerCase()
|
|
|
|
if (/claude|anthropic/.test(value)) return language.t("model.provider.anthropic")
|
|
if (/gpt|o[1-4]|codex|openai/.test(value)) return language.t("model.provider.openai")
|
|
if (/gemini|palm|bard|google/.test(value)) return language.t("model.provider.google")
|
|
if (/grok|xai/.test(value)) return language.t("model.provider.xai")
|
|
if (/llama|meta/.test(value)) return language.t("model.provider.meta")
|
|
|
|
return model.provider.name
|
|
}
|
|
const inputLabel = (value: string) => {
|
|
if (value === "text") return language.t("model.input.text")
|
|
if (value === "image") return language.t("model.input.image")
|
|
if (value === "audio") return language.t("model.input.audio")
|
|
if (value === "video") return language.t("model.input.video")
|
|
if (value === "pdf") return language.t("model.input.pdf")
|
|
return value
|
|
}
|
|
const title = () => {
|
|
const tags: Array<string> = []
|
|
if (props.latest) tags.push(language.t("model.tag.latest"))
|
|
if (props.free) tags.push(language.t("model.tag.free"))
|
|
const suffix = tags.length ? ` (${tags.join(", ")})` : ""
|
|
return `${sourceName(props.model)} ${props.model.name}${suffix}`
|
|
}
|
|
const name = () => {
|
|
const tags: Array<string> = []
|
|
if (props.latest) tags.push(language.t("model.tag.latest"))
|
|
if (props.free) tags.push(language.t("model.tag.free"))
|
|
const suffix = tags.length ? ` (${tags.join(", ")})` : ""
|
|
return `${props.model.name}${suffix}`
|
|
}
|
|
const inputs = () => {
|
|
if (props.model.capabilities) {
|
|
const input = props.model.capabilities.input
|
|
const order: Array<InputKey> = ["text", "image", "audio", "video", "pdf"]
|
|
const entries = order.filter((key) => input[key]).map((key) => inputLabel(key))
|
|
return entries.length ? entries.join(", ") : undefined
|
|
}
|
|
const raw = props.model.modalities?.input
|
|
if (!raw) return
|
|
const entries = raw.map((value) => inputLabel(value))
|
|
return entries.length ? entries.join(", ") : undefined
|
|
}
|
|
const reasoning = () => {
|
|
if (props.model.capabilities)
|
|
return props.model.capabilities.reasoning
|
|
? language.t("model.tooltip.reasoning.allowed")
|
|
: language.t("model.tooltip.reasoning.none")
|
|
return props.model.reasoning
|
|
? language.t("model.tooltip.reasoning.allowed")
|
|
: language.t("model.tooltip.reasoning.none")
|
|
}
|
|
const context = () => language.t("model.tooltip.context", { limit: props.model.limit.context.toLocaleString() })
|
|
const contextLimit = () => props.model.limit.context.toLocaleString(language.intl())
|
|
|
|
if (props.v2) {
|
|
return (
|
|
<div class="flex w-[180px] flex-col gap-2">
|
|
<ModelTooltipRow name={language.t("model.tooltip.model")} value={name()} />
|
|
<ModelTooltipRow name={language.t("model.tooltip.provider")} value={props.model.provider.name} />
|
|
<Show when={inputs()}>
|
|
{(value) => <ModelTooltipRow name={language.t("model.tooltip.inputs")} value={value()} />}
|
|
</Show>
|
|
<ModelTooltipRow name={language.t("model.tooltip.reasoning")} value={reasoning()} />
|
|
<ModelTooltipRow name={language.t("model.tooltip.context.label")} value={contextLimit()} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div class="flex flex-col gap-1 py-1">
|
|
<div class="text-13-medium">{title()}</div>
|
|
<Show when={inputs()}>
|
|
{(value) => (
|
|
<div class="text-12-regular text-text-invert-base">
|
|
{language.t("model.tooltip.allows", { inputs: value() })}
|
|
</div>
|
|
)}
|
|
</Show>
|
|
<div class="text-12-regular text-text-invert-base">{reasoning()}</div>
|
|
<div class="text-12-regular text-text-invert-base">{context()}</div>
|
|
</div>
|
|
)
|
|
}
|