refactor(web): lib/indexing/ becomes lib/searchSettings/ (#14982)

This commit is contained in:
Raunak Bhagat authored and GitHub committed 2026-09-22 16:36:38 +00:00
1 parent 6dbc329bcd
commit e5e8fa0da7
15 files changed
+379 -267

No files matched your search

+1 -1
View File
@@ -76,7 +76,6 @@ packages:
src/lib/headers: 100
src/lib/hierarchy: 100
src/lib/hooks: 95.7
src/lib/indexing: 99.4
src/lib/languageModels: 98.8
src/lib/multiModel: 100
src/lib/notifications: 99.3
@@ -86,6 +85,7 @@ packages:
src/lib/projects: 99.7
src/lib/search: 99.1
src/lib/searchFilters: 95.3
src/lib/searchSettings: 99.4
src/lib/settings: 96.6
src/lib/sidebar: 100
src/lib/skills: 97.4
+251
View File
@@ -0,0 +1,251 @@
import { SvgHardDrive } from "@opal/icons";
import {
SvgAzure,
SvgCohere,
SvgGoogle,
SvgLitellm,
SvgMicrosoft,
SvgNomic,
SvgOpenai,
SvgVoyage,
} from "@opal/logos";
import {
EmbeddingProvider,
EmbeddingProviderName,
} from "@/lib/searchSettings/types";
import { DOCS_ADMINS_PATH } from "@/lib/constants";
// ═══════════════════════════════════════════════════════════════════════════
// Embedding
// ═══════════════════════════════════════════════════════════════════════════
export const CLOUD_BASED_PROVIDERS: EmbeddingProvider[] = [
{
providerName: EmbeddingProviderName.COHERE,
displayName: "Cohere",
icon: SvgCohere,
docsLink: `${DOCS_ADMINS_PATH}/advanced_configs/search_configs`,
apiLink: "https://dashboard.cohere.ai/api-keys",
costslink: "https://cohere.com/pricing",
embeddingModels: [
{
modelName: "embed-english-v3.0",
modelDim: 1024,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.cohereEmbedEnglishV3",
},
{
modelName: "embed-english-light-v3.0",
modelDim: 384,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.cohereEmbedEnglishLightV3",
},
{
modelName: "embed-v4.0",
modelDim: 1536,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.cohereEmbedV4",
},
],
},
{
providerName: EmbeddingProviderName.OPENAI,
displayName: "OpenAI",
icon: SvgOpenai,
docsLink: `${DOCS_ADMINS_PATH}/advanced_configs/search_configs`,
apiLink: "https://platform.openai.com/api-keys",
costslink: "https://openai.com/pricing",
embeddingModels: [
{
modelName: "text-embedding-3-large",
modelDim: 3072,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.openaiTextEmbedding3Large",
},
{
modelName: "text-embedding-3-small",
modelDim: 1536,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.openaiTextEmbedding3Small",
},
],
},
{
providerName: EmbeddingProviderName.GOOGLE,
displayName: "Google",
icon: SvgGoogle,
docsLink: `${DOCS_ADMINS_PATH}/advanced_configs/search_configs`,
apiLink: "https://console.cloud.google.com/apis/credentials",
costslink: "https://cloud.google.com/vertex-ai/pricing",
embeddingModels: [
{
modelName: "gemini-embedding-001",
modelDim: 3072,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.googleGeminiEmbedding001",
},
{
modelName: "text-embedding-005",
modelDim: 768,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.googleTextEmbedding005",
},
{
modelName: "gemini-embedding-2",
modelDim: 3072,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.googleGeminiEmbedding2",
},
{
modelName: "gemini-embedding-2-preview",
modelDim: 3072,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.googleGeminiEmbedding2Preview",
},
],
},
{
providerName: EmbeddingProviderName.VOYAGE,
displayName: "Voyage",
icon: SvgVoyage,
docsLink: `${DOCS_ADMINS_PATH}/advanced_configs/search_configs`,
apiLink: "https://www.voyageai.com/dashboard",
costslink: "https://www.voyageai.com/pricing",
deprecated: true,
embeddingModels: [
{
modelName: "voyage-large-2-instruct",
modelDim: 1024,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.voyageLarge2Instruct",
},
{
modelName: "voyage-light-2-instruct",
modelDim: 1024,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.voyageLight2Instruct",
},
],
},
{
providerName: EmbeddingProviderName.LITELLM,
displayName: "LiteLLM",
icon: SvgLitellm,
apiLink: "https://docs.litellm.ai/docs/proxy/quick_start",
embeddingModels: [],
},
{
providerName: EmbeddingProviderName.AZURE,
displayName: "Azure",
icon: SvgAzure,
apiLink:
"https://docs.microsoft.com/en-us/azure/ai-services/openai/how-to/create-resource",
costslink:
"https://azure.microsoft.com/en-us/pricing/details/cognitive-services/openai/",
embeddingModels: [],
},
];
export const SELF_HOSTED_PROVIDERS: EmbeddingProvider[] = [
{
providerName: EmbeddingProviderName.NOMIC,
displayName: "Nomic",
icon: SvgNomic,
docsLink: "https://huggingface.co/nomic-ai",
embeddingModels: [
{
modelName: "nomic-ai/nomic-embed-text-v1",
modelDim: 768,
normalize: true,
queryPrefix: "search_query: ",
passagePrefix: "search_document: ",
descriptionKey: "modelDescriptions.nomicEmbedTextV1",
},
],
},
{
providerName: EmbeddingProviderName.MICROSOFT,
displayName: "Microsoft",
icon: SvgMicrosoft,
docsLink: "https://huggingface.co/intfloat",
embeddingModels: [
{
modelName: "intfloat/e5-base-v2",
modelDim: 768,
normalize: true,
queryPrefix: "query: ",
passagePrefix: "passage: ",
descriptionKey: "modelDescriptions.e5BaseV2",
},
{
modelName: "intfloat/e5-small-v2",
modelDim: 384,
normalize: true,
queryPrefix: "query: ",
passagePrefix: "passage: ",
descriptionKey: "modelDescriptions.e5SmallV2",
},
{
modelName: "intfloat/multilingual-e5-base",
modelDim: 768,
normalize: true,
queryPrefix: "query: ",
passagePrefix: "passage: ",
descriptionKey: "modelDescriptions.multilingualE5Base",
},
{
modelName: "intfloat/multilingual-e5-small",
modelDim: 384,
normalize: true,
queryPrefix: "query: ",
passagePrefix: "passage: ",
descriptionKey: "modelDescriptions.multilingualE5Small",
},
],
},
];
/**
* Synthetic provider used by the "Add Custom Model" flow. Not a real provider —
* its `providerName` never reaches the backend (custom self-hosted models are
* persisted with `provider_type=null` like other self-hosted models). Exists so
* the modal can be dispatched through `ProviderCredentialsModal` like every
* other provider.
*/
export const CUSTOM_PROVIDER: EmbeddingProvider = {
providerName: EmbeddingProviderName.CUSTOM,
displayName: "Custom Model",
icon: SvgHardDrive,
embeddingModels: [],
};
// ═══════════════════════════════════════════════════════════════════════════
// Image processing
// ═══════════════════════════════════════════════════════════════════════════
export const MAX_IMAGE_SIZE_OPTIONS = ["5", "10", "20", "50", "100"];
/** Mirrors `DEFAULT_IMAGE_ANALYSIS_MAX_SIZE_MB` on the backend. */
export const DEFAULT_IMAGE_ANALYSIS_MAX_SIZE_MB = 20;
@@ -1,5 +1,5 @@
import { secondaryRefreshInterval } from "@/lib/indexing/hooks";
import type { EmbeddingModelResponse } from "@/lib/indexing/types";
import { secondaryRefreshInterval } from "@/lib/searchSettings/hooks";
import type { EmbeddingModelResponse } from "@/lib/searchSettings/types";
const embeddingModelResponse: EmbeddingModelResponse = {
model_name: "text-embedding-3-small",
@@ -18,8 +18,9 @@ import {
LLMContextualCost,
ReindexErrorRow,
ReindexProgress,
ImageProcessingSettings,
SavedSearchSettings,
} from "@/lib/indexing/types";
} from "@/lib/searchSettings/types";
/**
* Determines the SWR `refreshInterval` for the secondary (in-progress)
@@ -129,3 +130,14 @@ export function useConfiguredEmbeddingProviders() {
errorHandlingFetcher
);
}
/**
* The tenant's image processing settings. `data` is `null` when the feature
* is off and `undefined` while loading.
*/
export function useImageProcessingSettings() {
return useSWR<ImageProcessingSettings | null>(
SWR_KEYS.imageProcessingSettings,
errorHandlingFetcher
);
}
@@ -1,247 +1,14 @@
import { SvgHardDrive } from "@opal/icons";
import {
SvgAzure,
SvgCohere,
SvgGoogle,
SvgLitellm,
SvgMicrosoft,
SvgNomic,
SvgOpenai,
SvgVoyage,
} from "@opal/logos";
CLOUD_BASED_PROVIDERS,
CUSTOM_PROVIDER,
SELF_HOSTED_PROVIDERS,
} from "@/lib/searchSettings/constants";
import {
EmbeddingModel,
EmbeddingProvider,
EmbeddingProviderName,
IndexSettingsTranslator,
} from "@/lib/indexing/types";
import { DOCS_ADMINS_PATH } from "@/lib/constants";
// ═══════════════════════════════════════════════════════════════════════════
// Embedding
// ═══════════════════════════════════════════════════════════════════════════
export const CLOUD_BASED_PROVIDERS: EmbeddingProvider[] = [
{
providerName: EmbeddingProviderName.COHERE,
displayName: "Cohere",
icon: SvgCohere,
docsLink: `${DOCS_ADMINS_PATH}/advanced_configs/search_configs`,
apiLink: "https://dashboard.cohere.ai/api-keys",
costslink: "https://cohere.com/pricing",
embeddingModels: [
{
modelName: "embed-english-v3.0",
modelDim: 1024,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.cohereEmbedEnglishV3",
},
{
modelName: "embed-english-light-v3.0",
modelDim: 384,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.cohereEmbedEnglishLightV3",
},
{
modelName: "embed-v4.0",
modelDim: 1536,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.cohereEmbedV4",
},
],
},
{
providerName: EmbeddingProviderName.OPENAI,
displayName: "OpenAI",
icon: SvgOpenai,
docsLink: `${DOCS_ADMINS_PATH}/advanced_configs/search_configs`,
apiLink: "https://platform.openai.com/api-keys",
costslink: "https://openai.com/pricing",
embeddingModels: [
{
modelName: "text-embedding-3-large",
modelDim: 3072,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.openaiTextEmbedding3Large",
},
{
modelName: "text-embedding-3-small",
modelDim: 1536,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.openaiTextEmbedding3Small",
},
],
},
{
providerName: EmbeddingProviderName.GOOGLE,
displayName: "Google",
icon: SvgGoogle,
docsLink: `${DOCS_ADMINS_PATH}/advanced_configs/search_configs`,
apiLink: "https://console.cloud.google.com/apis/credentials",
costslink: "https://cloud.google.com/vertex-ai/pricing",
embeddingModels: [
{
modelName: "gemini-embedding-001",
modelDim: 3072,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.googleGeminiEmbedding001",
},
{
modelName: "text-embedding-005",
modelDim: 768,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.googleTextEmbedding005",
},
{
modelName: "gemini-embedding-2",
modelDim: 3072,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.googleGeminiEmbedding2",
},
{
modelName: "gemini-embedding-2-preview",
modelDim: 3072,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.googleGeminiEmbedding2Preview",
},
],
},
{
providerName: EmbeddingProviderName.VOYAGE,
displayName: "Voyage",
icon: SvgVoyage,
docsLink: `${DOCS_ADMINS_PATH}/advanced_configs/search_configs`,
apiLink: "https://www.voyageai.com/dashboard",
costslink: "https://www.voyageai.com/pricing",
deprecated: true,
embeddingModels: [
{
modelName: "voyage-large-2-instruct",
modelDim: 1024,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.voyageLarge2Instruct",
},
{
modelName: "voyage-light-2-instruct",
modelDim: 1024,
normalize: false,
queryPrefix: "",
passagePrefix: "",
descriptionKey: "modelDescriptions.voyageLight2Instruct",
},
],
},
{
providerName: EmbeddingProviderName.LITELLM,
displayName: "LiteLLM",
icon: SvgLitellm,
apiLink: "https://docs.litellm.ai/docs/proxy/quick_start",
embeddingModels: [],
},
{
providerName: EmbeddingProviderName.AZURE,
displayName: "Azure",
icon: SvgAzure,
apiLink:
"https://docs.microsoft.com/en-us/azure/ai-services/openai/how-to/create-resource",
costslink:
"https://azure.microsoft.com/en-us/pricing/details/cognitive-services/openai/",
embeddingModels: [],
},
];
export const SELF_HOSTED_PROVIDERS: EmbeddingProvider[] = [
{
providerName: EmbeddingProviderName.NOMIC,
displayName: "Nomic",
icon: SvgNomic,
docsLink: "https://huggingface.co/nomic-ai",
embeddingModels: [
{
modelName: "nomic-ai/nomic-embed-text-v1",
modelDim: 768,
normalize: true,
queryPrefix: "search_query: ",
passagePrefix: "search_document: ",
descriptionKey: "modelDescriptions.nomicEmbedTextV1",
},
],
},
{
providerName: EmbeddingProviderName.MICROSOFT,
displayName: "Microsoft",
icon: SvgMicrosoft,
docsLink: "https://huggingface.co/intfloat",
embeddingModels: [
{
modelName: "intfloat/e5-base-v2",
modelDim: 768,
normalize: true,
queryPrefix: "query: ",
passagePrefix: "passage: ",
descriptionKey: "modelDescriptions.e5BaseV2",
},
{
modelName: "intfloat/e5-small-v2",
modelDim: 384,
normalize: true,
queryPrefix: "query: ",
passagePrefix: "passage: ",
descriptionKey: "modelDescriptions.e5SmallV2",
},
{
modelName: "intfloat/multilingual-e5-base",
modelDim: 768,
normalize: true,
queryPrefix: "query: ",
passagePrefix: "passage: ",
descriptionKey: "modelDescriptions.multilingualE5Base",
},
{
modelName: "intfloat/multilingual-e5-small",
modelDim: 384,
normalize: true,
queryPrefix: "query: ",
passagePrefix: "passage: ",
descriptionKey: "modelDescriptions.multilingualE5Small",
},
],
},
];
/**
* Synthetic provider used by the "Add Custom Model" flow. Not a real provider —
* its `providerName` never reaches the backend (custom self-hosted models are
* persisted with `provider_type=null` like other self-hosted models). Exists so
* the modal can be dispatched through `ProviderCredentialsModal` like every
* other provider.
*/
export const CUSTOM_PROVIDER: EmbeddingProvider = {
providerName: EmbeddingProviderName.CUSTOM,
displayName: "Custom Model",
icon: SvgHardDrive,
embeddingModels: [],
};
} from "@/lib/searchSettings/types";
/**
* Total lookup of an {@link EmbeddingProvider} by its `providerName`.
@@ -412,9 +179,3 @@ export function resolveProviderName(
}
return EmbeddingProviderName.CUSTOM;
}
// ═══════════════════════════════════════════════════════════════════════════
// Image processing
// ═══════════════════════════════════════════════════════════════════════════
export const MAX_IMAGE_SIZE_OPTIONS = ["5", "10", "20", "50", "100"];
@@ -2,11 +2,11 @@ import {
isSameModelSelection,
resolveModelForApply,
savedModelSelection,
} from "@/lib/indexing/utils";
} from "@/lib/searchSettings/utils";
import {
EmbeddingModelSpec,
EmbeddingProviderName,
} from "@/lib/indexing/types";
} from "@/lib/searchSettings/types";
/** A deployment the static registry has never heard of, which is the whole point. */
function deployment(modelName: string): EmbeddingModelSpec {
@@ -4,11 +4,12 @@ import { SWR_KEYS } from "@/lib/swr-keys";
import {
EmbeddingModelSpec,
EmbeddingProviderName,
ImageProcessingSettings,
ReindexErrorRow,
SavedSearchSettings,
SwitchoverType,
} from "@/lib/indexing/types";
import { isCloudBased } from "@/lib/indexing";
} from "@/lib/searchSettings/types";
import { isCloudBased } from "@/lib/searchSettings";
interface TestEmbeddingArgs {
provider_type: string;
@@ -238,3 +239,71 @@ export async function updateInferenceSettings(
body: JSON.stringify(settings),
});
}
// ═══════════════════════════════════════════════════════════════════════════
// Image processing
// ═══════════════════════════════════════════════════════════════════════════
interface EnableImageProcessingArgs {
modelConfigurationId: number;
maxSizeMb: number;
}
/**
* A failed image processing request. `detail` is the server's reason when
* the body carried one, else null; the caller chooses a translated fallback.
*/
export class ImageProcessingRequestError extends Error {
constructor(
readonly status: number,
readonly detail: string | null
) {
super(detail ?? `Image processing request failed with status ${status}`);
this.name = "ImageProcessingRequestError";
}
}
async function throwOnError(response: Response): Promise<void> {
if (response.ok) return;
let detail: string | null = null;
try {
const body: unknown = await response.json();
if (
typeof body === "object" &&
body !== null &&
"detail" in body &&
typeof body.detail === "string"
) {
detail = body.detail;
}
} catch (error) {
// A non-JSON body (a proxy page, a truncated response) is worth a trace.
console.error("Image processing error response was not JSON:", error);
}
throw new ImageProcessingRequestError(response.status, detail);
}
/** Turns image processing on with this model, or repoints it. */
export async function enableImageProcessing({
modelConfigurationId,
maxSizeMb,
}: EnableImageProcessingArgs): Promise<ImageProcessingSettings> {
const response = await fetch(SWR_KEYS.imageProcessingSettings, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model_configuration_id: modelConfigurationId,
max_size_mb: maxSizeMb,
}),
});
await throwOnError(response);
return (await response.json()) as ImageProcessingSettings;
}
/** Turns image processing off. */
export async function disableImageProcessing(): Promise<void> {
const response = await fetch(SWR_KEYS.imageProcessingSettings, {
method: "DELETE",
});
await throwOnError(response);
}
@@ -212,3 +212,16 @@ export interface ReindexErrorRow {
error_msg: string | null;
paused: boolean;
}
// ---------------------------------------------------------------------------
// Image processing
// ---------------------------------------------------------------------------
/**
* The tenant's image processing (captioning) configuration. `null` from the
* API means the feature is off; a value means it is on with that model.
*/
export interface ImageProcessingSettings {
model_configuration_id: number;
max_size_mb: number;
}
@@ -1,10 +1,10 @@
import { findRegistryModel, resolveProviderName } from "@/lib/indexing";
import { findRegistryModel, resolveProviderName } from "@/lib/searchSettings";
import type {
EmbeddingModelSelection,
EmbeddingModelSpec,
EmbeddingProviderName,
ResolvedEmbeddingModelForApply,
} from "@/lib/indexing/types";
} from "@/lib/searchSettings/types";
export function savedModelSelection(
currentModel: EmbeddingModelSpec | null,
+1
View File
@@ -83,6 +83,7 @@ export const SWR_KEYS = {
// ── Search Settings ───────────────────────────────────────────────────────
currentSearchSettings: "/api/search-settings/get-current-search-settings",
imageProcessingSettings: "/api/admin/image-processing",
secondarySearchSettings: "/api/search-settings/get-secondary-search-settings",
reindexProgress: "/api/search-settings/reindex-progress",
reindexErrors: "/api/search-settings/reindex-errors",
@@ -10,10 +10,10 @@ import {
createTableColumns,
} from "@opal/components";
import { SvgAlertCircle, SvgPauseCircle, SvgPlayCircle } from "@opal/icons";
import { useReindexErrors } from "@/lib/indexing/hooks";
import { resumePausedPort } from "@/lib/indexing/svc";
import { useReindexErrors } from "@/lib/searchSettings/hooks";
import { resumePausedPort } from "@/lib/searchSettings/svc";
import { SWR_KEYS } from "@/lib/swr-keys";
import type { ReindexErrorRow } from "@/lib/indexing/types";
import type { ReindexErrorRow } from "@/lib/searchSettings/types";
function ResumeButton({ row }: { row: ReindexErrorRow }) {
const t = useTranslations("admin.indexSettings");
@@ -14,7 +14,7 @@ import {
SvgPauseCircle,
} from "@opal/icons";
import ReindexErrorsModal from "@/views/admin/IndexSettingsPage/ReindexErrorsModal";
import { useReindexProgress } from "@/lib/indexing/hooks";
import { useReindexProgress } from "@/lib/searchSettings/hooks";
interface ReindexProgressBannerProps {
secondaryModelName?: string;
@@ -62,30 +62,32 @@ import {
type EmbeddingModelSelection,
type EmbeddingModelState,
type EmbeddingProvider,
} from "@/lib/indexing/types";
} from "@/lib/searchSettings/types";
import {
CLOUD_BASED_PROVIDERS,
CUSTOM_PROVIDER,
MAX_IMAGE_SIZE_OPTIONS,
SELF_HOSTED_PROVIDERS,
} from "@/lib/searchSettings/constants";
import {
embeddingModelDescription,
findProvider,
findRegistryModel,
isCloudBased,
MAX_IMAGE_SIZE_OPTIONS,
resolveProviderName,
} from "@/lib/indexing";
} from "@/lib/searchSettings";
import {
isSameModelSelection,
resolveModelForApply,
savedModelSelection,
} from "@/lib/indexing/utils";
} from "@/lib/searchSettings/utils";
import {
saveAdminSettings,
cancelNewEmbedding,
disconnectEmbeddingProvider,
setNewSearchSettings,
updateInferenceSettings,
} from "@/lib/indexing/svc";
} from "@/lib/searchSettings/svc";
import { useCreateModal } from "@opal/components";
import { ContentAction } from "@opal/layouts";
import { ConfirmationModalLayout } from "@opal/layouts";
@@ -98,7 +100,7 @@ import {
useCurrentSearchSettings,
useReindexProgress,
useSecondarySearchSettings,
} from "@/lib/indexing/hooks";
} from "@/lib/searchSettings/hooks";
import { useLlmDefaults } from "@/lib/languageModels/hooks";
import useFilter from "@/hooks/useFilter";
import ModelSelector from "@/sections/model-selector/ModelSelector";
@@ -15,8 +15,11 @@ import {
type ConfiguredEmbeddingProvider,
type EmbeddingModel,
type EmbeddingProvider,
} from "@/lib/indexing/types";
import { connectEmbeddingProvider, testEmbedding } from "@/lib/indexing/svc";
} from "@/lib/searchSettings/types";
import {
connectEmbeddingProvider,
testEmbedding,
} from "@/lib/searchSettings/svc";
import {
ApiKeyField,
ApiUrlField,
@@ -11,7 +11,7 @@ import { InputHorizontal, InputVertical } from "@opal/layouts";
import type {
EmbeddingProvider,
IndexSettingsTranslator,
} from "@/lib/indexing/types";
} from "@/lib/searchSettings/types";
import SwitchField from "@/refresh-components/form/SwitchField";
import InputTypeInField from "@/refresh-components/form/InputTypeInField";
import PasswordInputTypeInField from "@/refresh-components/form/PasswordInputTypeInField";