model-tooltip.tsx 3.3 KB

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