Modelle

Die Modelle-Seite in den Einstellungen eines KI-Produkts. Ein Standardmodell mit Kontext, Geschwindigkeit und Kosten auf einen Blick, ein Standard-Effort, der weiß, was jedes Modell unterstützt, eine durchsuchbare Modellliste nach Anbieter gruppiert mit Filtern, Pins und Sammelschaltern, OpenAI-kompatible Server mit echtem Verbindungstest und ein Refresh, der dir sagt, was neu ist.

Jedes KI-Produkt bekommt eine Modelle-Seite: welche Modelle im Picker erscheinen, mit welchem neue Chats starten, wie intensiv es denkt und welches kleine Modell die Hintergrundjobs ausführt. Models ist diese Seite als eine Komponente, ModelSettings, die in jeden Settings-Bereich passt und über dieselbe Insel speichert wie der Rest deiner Einstellungen.

Default model öffnet ein Menü der aktiven Modelle, nach Anbieter gruppiert, jedes mit Kontext, Kosten und Fähigkeiten. Unter dem Picker zeigen Chips Kontextfenster, Geschwindigkeit und Kosten des gewählten Modells, sodass der Kompromiss sichtbar ist, bevor jemand einen Chat öffnet. Default effort nutzt den Effort-Slider aus Prompt Input und weiß, was das Standardmodell unterstützt. Ziehst du über dessen Fähigkeiten hinaus, setzt sich der Slider auf seine höchste Stufe, die Zeile darunter sagt warum, und Screenreader hören es ebenfalls. Modelle, die nicht schlussfolgern, graut den Slider aus und erklärt, dass Effort nicht gilt.

Die Modellliste durchsucht Name, Anbieter und Fähigkeit und filtert auf Enabled, Reasoning, Fast oder Vision. Modelle sind nach Anbieter gruppiert, mit einer Zahl der aktiven und einem Switch, um einen ganzen Anbieter ein- oder auszuschalten. Jede Zeile zeigt Kontext, eine vierpunktige Kostenskala und Badges für New und Preview. Hefte die Modelle, die du am meisten nutzt, über das Zeilenmenü an, und sie wandern in eine Pinned-Gruppe oben, in der Reihenfolge, die der Picker zeigt. Verschiebe sie mit Move up und Move down oder Alt und den Pfeiltasten, ohne etwas zu ziehen.

Add model verbindet jeden OpenAI-kompatiblen Server, auch lokale. Es prüft die URL, markiert ein bereits hinzugefügtes Modell und testet vor dem Hinzufügen die Verbindung, wobei es zeigt, wie lange der Server zum Antworten brauchte oder warum es fehlschlug. Das Schlüsselfeld verbirgt den Schlüssel, bis du ihn einblendest. Refresh fragt deinen Server nach dem neuesten Katalog und zeigt ein dezentes Banner wie „2 neue Modelle: Nova 3.5 und Atlas 2 Vision“, mit Show, um darauf zu filtern. Neue Modelle kommen deaktiviert an, sodass sich im Picker nichts ändert, bis du wählst.

Task-Modelle geben dem Explore-Subagenten, Chat-Titeln und Zusammenfassungen ein eigenes Modell oder Auto. Nichts wird gespeichert, bis du speicherst: Jede Änderung blendet die Settings-Speicherleiste ein, Discard setzt alles zurück, auch entfernte eigene Modelle, und das Standardmodell lässt sich nicht versehentlich ausschalten.

  1. Die Pro-Registry zu components.json hinzufügen

    components.json
    {
      "registries": {
        "@hextaui-pro": {
          "url": "https://hextaui.com/r/pro/{name}.json",
          "headers": {
            "Authorization": "Bearer ${HEXTAUI_PRO_TOKEN}"
          }
        }
      }
    }
  2. Token hinzufügen

    Erstelle auf deiner Kontoseite einen Token und trage ihn in .env.local als HEXTAUI_PRO_TOKEN ein.

  3. Den Block hinzufügen

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

An deine API anbinden

Setze ModelSettings in eine SettingsSection. Übergib den Katalog und das Gespeicherte, speichere in onSave und gib aus onRefresh den neuesten Katalog zurück. Wirf bei beiden einen Fehler, um die Meldung zu zeigen, und der Entwurf bleibt.

"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>
  )
}

Eigene Server testen

onTestConnection erhält die Base-URL, die Modell-ID und den Schlüssel. Löse auf, wenn der Server antwortet, oder wirf mit einer Meldung, mit der Leute etwas anfangen können. Add model führt zuerst denselben Test aus, sodass nie ein defekter Server in der Liste landet.

"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}
    />
  )
}

Deine eigenen Effort-Stufen und Tasks

efforts legt die Stufen des Sliders fest, und das efforts jedes Modells listet die, die es unterstützt. tasks legt die Hintergrundjobs fest, die ein eigenes Modell bekommen.

"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} />
  )
}

Aufbau

Die Teile, die du zusammensetzt, von außen nach innen.

PartBeschreibung
ModelSettingsDer ganze Models-Bereich: Standards, die Picker-Liste der Modelle und Task-Modelle. Platziere ihn in einer SettingsSection.
Default modelEin Menü der aktivierten Modelle mit ihren Kennzahlen und Chips für Kontext, Geschwindigkeit und Kosten des gewählten.
Default effortDer Effort-Slider aus Prompt Input, begrenzt auf die Stufen, die das Standardmodell unterstützt.
Model pickerSuche, Filter, ein Refresh-Banner, eine Pinned-Gruppe und eine Gruppe pro Anbieter, jede Zeile mit einem Switch und einem Menü.
Add model dialogBase-URL, Modell-ID, Anzeigename und API-Schlüssel für einen OpenAI-kompatiblen Server, mit Verbindungstest.
Task modelsEin Modell pro Hintergrundjob, oder Auto.

ModelSettings

Muss innerhalb von SettingsShell gerendert werden, meist in einer SettingsSection, weil es über die Speicherleiste der Shell speichert.

PropTypStandard
modelsDer Katalog. { id, name, provider, context?, speed?, price?, vision?, efforts?, recommendedEffort?, status?, description? }. speed ist "fast" | "balanced" | "thorough", price ist 1 bis 4, efforts listet die Effort-Werte, die das Modell unterstützt (lass es bei Modellen weg, die nicht schlussfolgern), und status ist "new" | "preview".
ModelInfo[]–
valuesDas Gespeicherte: { defaultModel, effort, enabled, pinned, tasks, custom }. enabled und pinned sind Modell-IDs, pinned in Picker-Reihenfolge. tasks ordnet einer Task-ID eine Modell-ID oder "auto" zu. custom enthält die hinzugefügten Server.
ModelSettingsValues–
onSaveSpeichert den Entwurf. Wirf einen Fehler, um die Meldung in der Speicherleiste zu zeigen und den Entwurf zu behalten.
(values) => void | Promise<void>–
onRefreshRuft den neuesten Katalog ab. Modelle mit IDs, die es noch nicht kannte, bekommen ein New-Badge und ein Banner. Wirf einen Fehler, um den Grund mit Try again zu zeigen. Lass es weg, um den Refresh-Button auszublenden.
() => Promise<ModelInfo[]>–
onTestConnectionPrüft einen eigenen Server. Löse auf, wenn er antwortet, und wirf mit einer Meldung einen Fehler, wenn nicht. Lass es weg, um eigene Modelle ohne Test hinzuzufügen.
(connection: { baseUrl, model, apiKey }) => Promise<void>–
effortsDie Effort-Stufen, vom schnellsten zum klügsten.
{ value, label }[]Low, Medium, High, Max
tasksHintergrundjobs, die ein eigenes Modell bekommen. Übergib [], um die Gruppe auszublenden.
{ id, label, description? }[]Explore subagent, Chat titles, Summaries
TasteAktion
EscapeLeert in der Suche die Anfrage.
EnterÖffnet in der Suche ohne Treffer Add model mit der Suchanfrage als Modell-ID.
←→Wechselt zwischen Filtern. Ändert im Effort-Slider die Stufe und hält bei dem an, was das Standardmodell unterstützt.
SpaceSchaltet das fokussierte Modell ein oder aus.
Alt↑Verschiebt auf dem Switch oder Menü eines angehefteten Modells dieses im Picker nach oben. Alt+↓ verschiebt es nach unten. Der Fokus bleibt auf demselben Steuerelement.
⌘SSpeichert, wie der Rest der Settings. Strg+S unter Windows und Linux.
  • Jeder Anbieter und die Gruppe Pinned ist eine Liste, benannt nach ihrer Überschrift, und jede Zeile trägt den Namen ihres Modells.
  • Switches tragen den Namen des Modells als Label und werden durch Kontext, Kosten und Fähigkeiten beschrieben. Der Switch des Standardmodells ist deaktiviert und sagt warum.
  • Eine höfliche Live-Region sagt an, wie viele Modelle zu einer Suche oder einem Filter passen, sowie Refresh-Ergebnisse, Sammeländerungen, Pins, Verschiebungen und wenn der Effort durch das Modell begrenzt ist.
  • Wenn ein angeheftetes Modell wandert oder eine Zeile die Gruppe wechselt, folgt der Fokus ihm zum selben Steuerelement.
  • Die Kostenskala hat einen Textnamen, etwa Low cost, sodass die Punkte nie das einzige Signal sind.
  • Bei reduzierter Bewegung animieren Banner, Zeilenhervorhebung und Slider nicht.

Gebaut mit

Die kostenlosen HextaUI-Komponenten, aus denen Models besteht. Jede lässt sich einzeln installieren.

Code

4 Dateien, hinzugefügt zu components/blocks/models.