ModelInfoView.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import { useMemo } from "react"
  2. import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
  3. import { useAppTranslation } from "@/i18n/TranslationContext"
  4. import { formatPrice } from "@/utils/formatPrice"
  5. import { cn } from "@/lib/utils"
  6. import { ModelInfo, geminiModels } from "../../../../src/shared/api"
  7. import { ModelDescriptionMarkdown } from "./ModelDescriptionMarkdown"
  8. type ModelInfoViewProps = {
  9. selectedModelId: string
  10. modelInfo: ModelInfo
  11. isDescriptionExpanded: boolean
  12. setIsDescriptionExpanded: (isExpanded: boolean) => void
  13. }
  14. export const ModelInfoView = ({
  15. selectedModelId,
  16. modelInfo,
  17. isDescriptionExpanded,
  18. setIsDescriptionExpanded,
  19. }: ModelInfoViewProps) => {
  20. const { t } = useAppTranslation()
  21. const isGemini = useMemo(() => Object.keys(geminiModels).includes(selectedModelId), [selectedModelId])
  22. const infoItems = [
  23. <ModelInfoSupportsItem
  24. isSupported={modelInfo.supportsImages ?? false}
  25. supportsLabel={t("settings:modelInfo.supportsImages")}
  26. doesNotSupportLabel={t("settings:modelInfo.noImages")}
  27. />,
  28. <ModelInfoSupportsItem
  29. isSupported={modelInfo.supportsComputerUse ?? false}
  30. supportsLabel={t("settings:modelInfo.supportsComputerUse")}
  31. doesNotSupportLabel={t("settings:modelInfo.noComputerUse")}
  32. />,
  33. !isGemini && (
  34. <ModelInfoSupportsItem
  35. isSupported={modelInfo.supportsPromptCache}
  36. supportsLabel={t("settings:modelInfo.supportsPromptCache")}
  37. doesNotSupportLabel={t("settings:modelInfo.noPromptCache")}
  38. />
  39. ),
  40. typeof modelInfo.maxTokens === "number" && modelInfo.maxTokens > 0 && (
  41. <>
  42. <span className="font-medium">{t("settings:modelInfo.maxOutput")}:</span>{" "}
  43. {modelInfo.maxTokens?.toLocaleString()} tokens
  44. </>
  45. ),
  46. modelInfo.inputPrice !== undefined && modelInfo.inputPrice > 0 && (
  47. <>
  48. <span className="font-medium">{t("settings:modelInfo.inputPrice")}:</span>{" "}
  49. {formatPrice(modelInfo.inputPrice)} / 1M tokens
  50. </>
  51. ),
  52. modelInfo.outputPrice !== undefined && modelInfo.outputPrice > 0 && (
  53. <>
  54. <span className="font-medium">{t("settings:modelInfo.outputPrice")}:</span>{" "}
  55. {formatPrice(modelInfo.outputPrice)} / 1M tokens
  56. </>
  57. ),
  58. modelInfo.supportsPromptCache && modelInfo.cacheReadsPrice && (
  59. <>
  60. <span className="font-medium">{t("settings:modelInfo.cacheReadsPrice")}:</span>{" "}
  61. {formatPrice(modelInfo.cacheReadsPrice || 0)} / 1M tokens
  62. </>
  63. ),
  64. modelInfo.supportsPromptCache && modelInfo.cacheWritesPrice && (
  65. <>
  66. <span className="font-medium">{t("settings:modelInfo.cacheWritesPrice")}:</span>{" "}
  67. {formatPrice(modelInfo.cacheWritesPrice || 0)} / 1M tokens
  68. </>
  69. ),
  70. isGemini && (
  71. <span className="italic">
  72. {selectedModelId === "gemini-2.5-pro-preview-03-25"
  73. ? t("settings:modelInfo.gemini.billingEstimate")
  74. : t("settings:modelInfo.gemini.freeRequests", {
  75. count: selectedModelId && selectedModelId.includes("flash") ? 15 : 2,
  76. })}{" "}
  77. <VSCodeLink href="https://ai.google.dev/pricing" className="text-sm">
  78. {t("settings:modelInfo.gemini.pricingDetails")}
  79. </VSCodeLink>
  80. </span>
  81. ),
  82. ].filter(Boolean)
  83. return (
  84. <>
  85. {modelInfo.description && (
  86. <ModelDescriptionMarkdown
  87. key="description"
  88. markdown={modelInfo.description}
  89. isExpanded={isDescriptionExpanded}
  90. setIsExpanded={setIsDescriptionExpanded}
  91. />
  92. )}
  93. <div className="text-sm text-vscode-descriptionForeground">
  94. {infoItems.map((item, index) => (
  95. <div key={index}>{item}</div>
  96. ))}
  97. </div>
  98. </>
  99. )
  100. }
  101. const ModelInfoSupportsItem = ({
  102. isSupported,
  103. supportsLabel,
  104. doesNotSupportLabel,
  105. }: {
  106. isSupported: boolean
  107. supportsLabel: string
  108. doesNotSupportLabel: string
  109. }) => (
  110. <div
  111. className={cn(
  112. "flex items-center gap-1 font-medium",
  113. isSupported ? "text-vscode-charts-green" : "text-vscode-errorForeground",
  114. )}>
  115. <span className={cn("codicon", isSupported ? "codicon-check" : "codicon-x")} />
  116. {isSupported ? supportsLabel : doesNotSupportLabel}
  117. </div>
  118. )