Models filter
This commit is contained in:
parent
ae0d232331
commit
7eb8e5b870
|
|
@ -116,6 +116,7 @@
|
||||||
.formGroup {
|
.formGroup {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.formGroupFill {
|
.formGroupFill {
|
||||||
|
|
@ -128,6 +129,20 @@
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selectMultiline {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectMultiline optgroup {
|
||||||
|
padding-block: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectMultiline option {
|
||||||
|
padding-block: 4px;
|
||||||
|
padding-inline-start: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.input,
|
.input,
|
||||||
.select,
|
.select,
|
||||||
.textarea {
|
.textarea {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { useBool } from "@common/hooks/useBool";
|
||||||
import { useQuery } from "@common/hooks/useAsyncState";
|
import { useQuery } from "@common/hooks/useAsyncState";
|
||||||
import { useInputState } from "@common/hooks/useInputState";
|
import { useInputState } from "@common/hooks/useInputState";
|
||||||
import { useUpdate } from "@common/hooks/useUpdate";
|
import { useUpdate } from "@common/hooks/useUpdate";
|
||||||
|
import clsx from "clsx";
|
||||||
import { useMemo, useRef } from "preact/hooks";
|
import { useMemo, useRef } from "preact/hooks";
|
||||||
import styles from "../../assets/settings-modal.module.css";
|
import styles from "../../assets/settings-modal.module.css";
|
||||||
import { useAppState } from "../../contexts/state";
|
import { useAppState } from "../../contexts/state";
|
||||||
|
|
@ -36,6 +37,8 @@ export const ConnectionSettings = () => {
|
||||||
const modelsData = useQuery(fetchModels, connectionToFetch);
|
const modelsData = useQuery(fetchModels, connectionToFetch);
|
||||||
const isLoadingModels = connectionToFetch != null && modelsData == undefined;
|
const isLoadingModels = connectionToFetch != null && modelsData == undefined;
|
||||||
|
|
||||||
|
const [modelFilter, setModelFilter] = useInputState("");
|
||||||
|
|
||||||
const groupedModels = useMemo(() => {
|
const groupedModels = useMemo(() => {
|
||||||
const sorted = (modelsData ?? []).sort((a, b) => {
|
const sorted = (modelsData ?? []).sort((a, b) => {
|
||||||
const aWeight = Number(a.support_tools) * 2 + Number(a.support_thinking);
|
const aWeight = Number(a.support_tools) * 2 + Number(a.support_thinking);
|
||||||
|
|
@ -52,6 +55,25 @@ export const ConnectionSettings = () => {
|
||||||
.map(([context, models]) => ({ context, models }));
|
.map(([context, models]) => ({ context, models }));
|
||||||
}, [modelsData]);
|
}, [modelsData]);
|
||||||
|
|
||||||
|
const filteredGroupedModels = useMemo(() => {
|
||||||
|
if (!modelFilter) return groupedModels;
|
||||||
|
const query = modelFilter.toLowerCase();
|
||||||
|
const fuzzyMatch = (target: string) => {
|
||||||
|
const t = target.toLowerCase();
|
||||||
|
let qi = 0;
|
||||||
|
for (let ti = 0; ti < t.length && qi < query.length; ti++) {
|
||||||
|
if (t[ti] === query[qi]) qi++;
|
||||||
|
}
|
||||||
|
return qi === query.length;
|
||||||
|
};
|
||||||
|
return groupedModels
|
||||||
|
.map(({ context, models }) => ({
|
||||||
|
context,
|
||||||
|
models: models.filter(m => m.id === selectedModel || fuzzyMatch(m.id)),
|
||||||
|
}))
|
||||||
|
.filter(({ models }) => models.length > 0);
|
||||||
|
}, [groupedModels, modelFilter, selectedModel]);
|
||||||
|
|
||||||
const handleBlur = () => {
|
const handleBlur = () => {
|
||||||
if (url && apiKey) {
|
if (url && apiKey) {
|
||||||
dispatch({ type: "SET_CONNECTION", connection: { url, apiKey } });
|
dispatch({ type: "SET_CONNECTION", connection: { url, apiKey } });
|
||||||
|
|
@ -115,19 +137,27 @@ export const ConnectionSettings = () => {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class={styles.formGroup}>
|
<div class={clsx(styles.formGroup, styles.formGroupFill)}>
|
||||||
<label class={styles.label}>Model</label>
|
<label class={styles.label}>Model</label>
|
||||||
{connectionToTest ? (
|
{connectionToTest ? (
|
||||||
isLoadingModels ? (
|
isLoadingModels ? (
|
||||||
<p>Loading models...</p>
|
<p>Loading models...</p>
|
||||||
) : groupedModels.length > 0 ? (
|
) : groupedModels.length > 0 ? (
|
||||||
|
<>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={modelFilter}
|
||||||
|
onInput={setModelFilter}
|
||||||
|
placeholder="Filter models..."
|
||||||
|
class={styles.input}
|
||||||
|
/>
|
||||||
<select
|
<select
|
||||||
value={selectedModel}
|
value={selectedModel}
|
||||||
onChange={handleModelChange}
|
onChange={handleModelChange}
|
||||||
class={styles.select}
|
class={clsx(styles.select, styles.selectMultiline)}
|
||||||
|
size={8}
|
||||||
>
|
>
|
||||||
<option value="">Select a model</option>
|
{filteredGroupedModels.map(({ context, models }) => (
|
||||||
{groupedModels.map(({ context, models }) => (
|
|
||||||
<optgroup key={context} label={`${context} context`}>
|
<optgroup key={context} label={`${context} context`}>
|
||||||
{models.map(m => (
|
{models.map(m => (
|
||||||
<option key={m.id} value={m.id}>
|
<option key={m.id} value={m.id}>
|
||||||
|
|
@ -137,6 +167,7 @@ export const ConnectionSettings = () => {
|
||||||
</optgroup>
|
</optgroup>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<p>No models available</p>
|
<p>No models available</p>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue