モデル

AIプロダクトの設定にあるモデルページです。コンテキスト、速度、コストが一目でわかるデフォルトモデル、各モデルが対応する内容を把握しているデフォルトの推論量、フィルター、ピン留め、一括切り替えを備えプロバイダーごとにグループ化された検索可能なモデルリスト、実際の接続テストができるOpenAI互換サーバー、新着を知らせる更新を備えています。

あらゆるAIプロダクトには、どのモデルをピッカーに表示するか、新しいチャットをどのモデルで始めるか、どれだけ深く考えさせるか、どの小さなモデルでバックグラウンドジョブを実行するか、を決めるModelsページが必要になります。Modelsはそのページを1つのコンポーネントModelSettingsにしたもので、どの設定セクションにも組み込め、他の設定と同じアイランドを通じて保存されます。

Default modelは、オンのモデルをプロバイダーごとにグループ化し、それぞれのコンテキスト、コスト、機能を示すメニューを開きます。ピッカーの下のチップには、選択したモデルのコンテキストウィンドウ、速度、コストが表示されるため、チャットを開く前にトレードオフがわかります。Default effortはPrompt Inputの推論量スライダーを使い、デフォルトのモデルが対応する内容を把握しています。モデルができる範囲を超えてドラッグすると、スライダーは最高レベルで止まり、その下の行が理由を説明し、スクリーンリーダーにも読み上げられます。推論を行わないモデルではスライダーがグレーアウトされ、推論量が適用されないことが説明されます。

モデルリストは、名前、プロバイダー、機能で検索でき、Enabled、Reasoning、Fast、Visionで絞り込めます。モデルはプロバイダーごとにグループ化され、オンになっている数と、プロバイダー全体をオンまたはオフにする1つのスイッチが付きます。各行にはコンテキスト、4つのドットによるコストの尺度、NewとPreviewのバッジが表示されます。よく使うモデルは行のメニューからピン留めでき、ピッカーに表示される順序で、上部のPinnedグループに移動します。何もドラッグせずに、Move upとMove down、またはAltと矢印キーで並べ替えられます。

Add modelは、ローカルのものを含め、OpenAI互換のサーバーを接続します。URLを確認し、すでに追加したモデルを警告し、追加する前に接続をテストして、サーバーが応答するまでにかかった時間、または失敗の理由を表示します。キーのフィールドは、表示するまでキーを隠します。Refreshはサーバーに最新のカタログを問い合わせ、「2 new models: Nova 3.5 and Atlas 2 Vision」のような控えめなバナーを表示し、Showでそれらに絞り込めます。新しいモデルはオフの状態で届くため、選択するまでピッカーは変わりません。

Task modelsは、exploreサブエージェント、チャットのタイトル、要約に、それぞれ独自のモデルまたはAutoを割り当てます。保存するまで何も保存されません。すべての変更が設定の保存バーを呼び出し、Discardは削除したカスタムモデルを含むすべてを元に戻し、デフォルトのモデルが誤ってオフになることはありません。

  1. Proレジストリをcomponents.jsonに追加する

    components.json
    {
      "registries": {
        "@hextaui-pro": {
          "url": "https://hextaui.com/r/pro/{name}.json",
          "headers": {
            "Authorization": "Bearer ${HEXTAUI_PRO_TOKEN}"
          }
        }
      }
    }
  2. トークンを追加する

    アカウントページでトークンを作成し、.env.local に HEXTAUI_PRO_TOKEN として設定してください。

  3. ブロックを追加する

    pnpm dlx shadcn@latest add @hextaui-pro/models

APIに接続する

ModelSettingsをSettingsSectionの中に置きます。カタログと保存済みの内容を渡し、onSaveで保存し、onRefreshから最新のカタログを返します。どちらかからエラーを投げるとメッセージが表示され、下書きは保持されます。

"use client"

import { IconCube } from "@tabler/icons-react"

import { SettingsSection, SettingsShell, type SettingsSectionItem } from "../settings/settings"
import { ModelSettings, type ModelInfo, type ModelSettingsValues } from "@/components/blocks/models/model-settings"

const sections: SettingsSectionItem[] = [{ id: "models", label: "Models", icon: <IconCube /> }]

export function ModelsPage({
  models,
  values,
}: {
  models: ModelInfo[]
  values: ModelSettingsValues
}) {
  return (
    <SettingsShell sections={sections} className="h-svh">
      <SettingsSection id="models">
        <ModelSettings
          models={models}
          values={values}
          onSave={async (next) => {
            const response = await fetch("/api/settings/models", {
              method: "PUT",
              body: JSON.stringify(next),
            })
            if (!response.ok) throw new Error("Check your connection and try again.")
          }}
          onRefresh={async () => {
            const response = await fetch("/api/models")
            if (!response.ok) throw new Error("The model list is unavailable.")
            return (await response.json()) as ModelInfo[]
          }}
        />
      </SettingsSection>
    </SettingsShell>
  )
}

カスタムサーバーをテストする

onTestConnectionは、ベースURL、モデルID、キーを受け取ります。サーバーが応答したらresolveし、そうでなければ、ユーザーが対処できるメッセージとともにエラーを投げます。Add modelは先に同じテストを実行するため、壊れたサーバーがリストに入ることはありません。

"use client"

import { ModelSettings, type ModelConnection, type ModelInfo, type ModelSettingsValues } from "@/components/blocks/models/model-settings"

async function testConnection({ baseUrl, model, apiKey }: ModelConnection) {
  const response = await fetch(`${baseUrl}/chat/completions`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
    },
    body: JSON.stringify({ model, max_tokens: 1, messages: [{ role: "user", content: "ping" }] }),
  }).catch(() => {
    throw new Error(`Couldn’t reach ${new URL(baseUrl).host}. Check the URL and that the server is running.`)
  })
  if (response.status === 401) throw new Error("The server said 401. Check the API key.")
  if (response.status === 404) throw new Error(`The server doesn’t know “${model}”.`)
  if (!response.ok) throw new Error(`The server said ${response.status}.`)
}

export function ModelsWithCustomServers({
  models,
  values,
  onSave,
}: {
  models: ModelInfo[]
  values: ModelSettingsValues
  onSave: (values: ModelSettingsValues) => Promise<void>
}) {
  return (
    <ModelSettings
      models={models}
      values={values}
      onSave={onSave}
      onTestConnection={testConnection}
    />
  )
}

独自の推論量レベルとタスク

effortsはスライダーのレベルを設定し、各モデルのeffortsはそのモデルが対応するレベルを列挙します。tasksは、独自のモデルを持つバックグラウンドジョブを設定します。

"use client"

import { ModelSettings, type ModelInfo, type ModelSettingsValues } from "@/components/blocks/models/model-settings"

const models: ModelInfo[] = [
  {
    id: "nova-3",
    name: "Nova 3",
    provider: "Hexta",
    context: 200_000,
    speed: "balanced",
    price: 2,
    efforts: ["none", "light", "deep"],
    recommendedEffort: "light",
  },
  {
    id: "nova-3-mini",
    name: "Nova 3 Mini",
    provider: "Hexta",
    context: 128_000,
    speed: "fast",
    price: 1,
    efforts: ["none", "light"],
  },
]

const efforts = [
  { value: "none", label: "None" },
  { value: "light", label: "Light" },
  { value: "deep", label: "Deep" },
]

const tasks = [
  { id: "titles", label: "Chat titles", description: "Names new chats from the first message." },
]

export function ModelsWithOwnLevels({
  values,
  onSave,
}: {
  values: ModelSettingsValues
  onSave: (values: ModelSettingsValues) => Promise<void>
}) {
  return (
    <ModelSettings models={models} values={values} onSave={onSave} efforts={efforts} tasks={tasks} />
  )
}

構造

外側から内側へ組み合わせるパーツ。

パーツ説明
ModelSettingsModelsセクション全体。デフォルト、モデルピッカーのリスト、タスクモデル。SettingsSectionの内側に置きます。
Default model有効なモデルとその統計情報を一覧するメニューと、選択されたモデルのコンテキスト、速度、コストを示すチップ。
Default effortPrompt Inputの推論量スライダー。デフォルトのモデルが対応するレベルに制限されます。
Model picker検索、フィルター、更新バナー、Pinnedグループ、プロバイダーごとの1グループ。各行にはスイッチとメニューがあります。
Add model dialogOpenAI互換サーバーのBase URL、モデルID、表示名、APIキー。接続テストつきです。
Task modelsバックグラウンドジョブごとのモデル、またはAuto。

ModelSettings

SettingsShellの内側、通常はSettingsSectionの中でレンダリングする必要があります。シェルの保存バーを通じて保存するためです。

プロパティ型デフォルト
modelsカタログ。{ id, name, provider, context?, speed?, price?, vision?, efforts?, recommendedEffort?, status?, description? }。speedは "fast" | "balanced" | "thorough"、priceは1から4、effortsはモデルが対応する推論量の値を列挙し(推論しないモデルでは省略)、statusは "new" | "preview" です。
ModelInfo[]–
values保存される内容: { defaultModel, effort, enabled, pinned, tasks, custom }。enabledとpinnedはモデルidで、pinnedはピッカーの順序です。tasksはタスクidをモデルidまたは "auto" に対応付けます。customは追加されたサーバーを保持します。
ModelSettingsValues–
onSave下書きを保存します。エラーを投げると、そのメッセージが保存バーに表示され、下書きは保持されます。
(values) => void | Promise<void>–
onRefresh最新のカタログを取得します。未知のidを持つモデルにはNewバッジとバナーが表示されます。エラーを投げると、理由とともにTry againが表示されます。省略すると、更新ボタンは非表示になります。
() => Promise<ModelInfo[]>–
onTestConnectionカスタムサーバーを確認します。応答すればresolveし、応答しなければメッセージとともにエラーを投げます。省略すると、テストなしでカスタムモデルを追加できます。
(connection: { baseUrl, model, apiKey }) => Promise<void>–
efforts推論量のレベル。最速から最高性能の順です。
{ value, label }[]Low, Medium, High, Max
tasks専用のモデルを持つバックグラウンドジョブ。グループを非表示にするには、[] を渡します。
{ id, label, description? }[]Explore subagent, Chat titles, Summaries
キーアクション
Escape検索中は、クエリをクリアします。
Enter一致するものがない検索では、クエリをモデルIDとしてAdd modelを開きます。
←→フィルター間を移動します。推論量スライダーでは、デフォルトのモデルが対応する範囲までレベルを変更します。
Spaceフォーカスのあるモデルをオンまたはオフにします。
Alt↑ピン留めされたモデルのスイッチまたはメニューで、ピッカー内の位置を上に移動します。Alt+↓で下に移動します。フォーカスは同じコントロールに残ります。
⌘SSettingsの他の部分と同様に保存します。WindowsとLinuxではCtrl+Sです。
  • 各プロバイダーとPinnedグループは、見出しにちなんだ名前のリストで、すべての行にはモデルの名前が付きます。
  • スイッチにはモデルの名前がラベルとして付き、そのコンテキスト、コスト、機能が説明として付きます。デフォルトのモデルのスイッチは無効になり、その理由が示されます。
  • politeなライブリージョンが、検索やフィルターに一致するモデルの数、更新結果、一括変更、ピン留め、移動、そしてモデルによって推論量が制限されたときに読み上げます。
  • ピン留めされたモデルが移動したり、行が別のグループに移ったりしても、フォーカスは同じコントロールに追従します。
  • コストの尺度にはLow costのような文字の名前があるため、ドットが唯一の手がかりになることはありません。
  • モーション軽減時は、バナー、行のハイライト、スライダーはアニメーションしません。

使用技術

Models を構成する無料のHextaUIコンポーネントです。それぞれ単独でインストールできます。

コード

4 個のファイルを components/blocks/models に追加しました。