Files
wehub-resource-sync e4dcfc49aa
Tests / Import Check (Python 3.13) (push) Has been cancelled
Tests / Import Check (Python 3.14) (push) Has been cancelled
Tests / Python Tests (Python 3.11) (push) Has been cancelled
Tests / Python Tests (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.14) (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Tests / Lint and Format (push) Has been cancelled
Tests / Web Node Tests (push) Has been cancelled
Tests / Import Check (Python 3.11) (push) Has been cancelled
Tests / Import Check (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.13) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:00:43 +08:00

174 lines
5.2 KiB
TypeScript

"use client";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import type { CatalogModel, EmbeddingCapabilities } from "./SettingsContext";
import { nativeSelectClass, selectOptionClass } from "./shared";
const CUSTOM_DIM_SENTINEL = "__custom__";
const AUTO_DIM_SENTINEL = "";
function parseSupportedCsv(csv: string | undefined): number[] {
if (!csv) return [];
return csv
.split(",")
.map((s) => s.trim())
.filter(Boolean)
.map((s) => Number(s))
.filter((n) => Number.isFinite(n) && n > 0);
}
function sourceBadge(
source: string | undefined,
t: (key: string) => string,
): { label: string; tone: "muted" | "ok" | "warn" } | null {
if (source === "detected") {
return { label: t("Source: detected from API probe"), tone: "ok" };
}
return null;
}
export function DimensionField({
activeModel,
activeBinding,
capabilities,
embeddingDefaultDim,
inputClass,
onChangeDimension,
}: {
activeModel: CatalogModel;
activeBinding?: string;
capabilities: EmbeddingCapabilities | null;
embeddingDefaultDim: (binding?: string) => string;
inputClass: string;
onChangeDimension: (value: string) => void;
}) {
const { t } = useTranslation();
const fallback = embeddingDefaultDim(activeBinding);
const rawValue = activeModel.dimension ?? "";
const isEmpty = rawValue === "";
const currentNum = isEmpty ? NaN : Number(rawValue);
const liveSupported = capabilities?.supported_dimensions;
const cachedSupported = parseSupportedCsv(activeModel.supported_dimensions);
const supported =
liveSupported && liveSupported.length > 0 ? liveSupported : cachedSupported;
const supportsVariable =
capabilities?.supports_variable_dimensions ?? supported.length > 1;
const useDropdown = supported.length > 1 && supportsVariable;
const currentInList =
Number.isFinite(currentNum) && supported.includes(currentNum);
const [customRequested, setCustomRequested] = useState<boolean>(false);
const customMode =
customRequested || (useDropdown && !isEmpty && !currentInList);
const detected = capabilities?.detected_dim;
const showDetectedBadge =
typeof detected === "number" &&
detected > 0 &&
detected !== currentNum &&
!isEmpty;
const sourceInfo = sourceBadge(capabilities?.active_dim_source, t);
const disabled = activeModel.send_dimensions === false;
const handleSelect = (value: string) => {
if (value === CUSTOM_DIM_SENTINEL) {
setCustomRequested(true);
return;
}
setCustomRequested(false);
onChangeDimension(value);
};
const dropdownValue = isEmpty
? AUTO_DIM_SENTINEL
: currentInList
? String(currentNum)
: CUSTOM_DIM_SENTINEL;
return (
<div className="space-y-1.5">
{useDropdown && !customMode ? (
<select
className={nativeSelectClass}
value={dropdownValue}
onChange={(e) => handleSelect(e.target.value)}
disabled={disabled}
>
<option className={selectOptionClass} value={AUTO_DIM_SENTINEL}>
{t("Auto (probe on next test)")}
</option>
{supported.map((dim) => (
<option className={selectOptionClass} key={dim} value={String(dim)}>
{dim}
</option>
))}
<option className={selectOptionClass} value={CUSTOM_DIM_SENTINEL}>
{t("Custom…")}
</option>
</select>
) : (
<input
className={inputClass}
value={rawValue}
placeholder={fallback}
onChange={(e) => onChangeDimension(e.target.value)}
disabled={disabled}
inputMode="numeric"
/>
)}
{useDropdown && customMode && (
<button
type="button"
onClick={() => {
setCustomRequested(false);
if (isEmpty) {
return;
}
const closest = supported.reduce((acc, dim) =>
Math.abs(dim - currentNum) < Math.abs(acc - currentNum)
? dim
: acc,
);
onChangeDimension(String(closest));
}}
className="text-[11px] text-[var(--muted-foreground)] underline-offset-2 hover:underline"
>
{t("Use a supported value")}
</button>
)}
{sourceInfo && (
<div
className={`text-[11px] ${
sourceInfo.tone === "warn"
? "text-amber-600 dark:text-amber-400"
: sourceInfo.tone === "ok"
? "text-emerald-600 dark:text-emerald-400"
: "text-[var(--muted-foreground)]"
}`}
>
{sourceInfo.label}
</div>
)}
{showDetectedBadge && (
<div className="flex items-center gap-2 text-[11px] text-[var(--muted-foreground)]">
<span>
{t("Detected")}: <strong>{detected}d</strong>
</span>
<button
type="button"
onClick={() => onChangeDimension(String(detected))}
className="rounded-md border border-[var(--border)]/60 px-1.5 py-0.5 text-[10px] text-[var(--foreground)] transition-colors hover:border-[var(--border)]"
disabled={disabled}
>
{t("Use this")}
</button>
</div>
)}
</div>
);
}