chore: hub UI tooltip filter, max model size and search result (#4753)
* chore: fix hub ui tooltip, max-filter, and search result * chore: fix linter
This commit is contained in:
parent
f586c19951
commit
250d30d73a
@ -26,7 +26,7 @@ export default function ContextLengthFilter() {
|
|||||||
className="flex-shrink-0 text-[hsl(var(--text-secondary))]"
|
className="flex-shrink-0 text-[hsl(var(--text-secondary))]"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
content={''}
|
content="Controls how much text the model can consider at once. Longer context allows the model to handle more input but uses more memory and runs slower."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-x-4">
|
<div className="flex items-center gap-x-4">
|
||||||
|
|||||||
@ -8,29 +8,20 @@ import { InfoIcon } from 'lucide-react'
|
|||||||
export const hubModelSizeMinAtom = atom(0)
|
export const hubModelSizeMinAtom = atom(0)
|
||||||
export const hubModelSizeMaxAtom = atom(100)
|
export const hubModelSizeMaxAtom = atom(100)
|
||||||
|
|
||||||
export default function ModelSizeFilter() {
|
export default function ModelSizeFilter({ max }: { max: number }) {
|
||||||
const [value, setValue] = useAtom(hubModelSizeMinAtom)
|
const [value, setValue] = useAtom(hubModelSizeMinAtom)
|
||||||
const [valueMax, setValueMax] = useAtom(hubModelSizeMaxAtom)
|
const [valueMax, setValueMax] = useAtom(hubModelSizeMaxAtom)
|
||||||
const [inputingMinValue, setInputingMinValue] = useState(false)
|
const [inputingMinValue, setInputingMinValue] = useState(false)
|
||||||
const [inputingMaxValue, setInputingMaxValue] = useState(false)
|
const [inputingMaxValue, setInputingMaxValue] = useState(false)
|
||||||
|
|
||||||
const normalizeTextValue = (value: number) => {
|
const normalizeTextValue = (value: number) => {
|
||||||
return value === 100 ? '100GB' : value === 0 ? 0 : `${value}GB`
|
return value === 0 ? 0 : `${value}GB`
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div className="mb-3 flex items-center gap-x-2">
|
<div className="mb-3 flex items-center gap-x-2">
|
||||||
<p className="font-semibold">Model size</p>
|
<p className="font-semibold">Model size</p>
|
||||||
<Tooltip
|
|
||||||
trigger={
|
|
||||||
<InfoIcon
|
|
||||||
size={16}
|
|
||||||
className="flex-shrink-0 text-[hsl(var(--text-secondary))]"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
content={''}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-x-4">
|
<div className="flex items-center gap-x-4">
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
@ -41,7 +32,7 @@ export default function ModelSizeFilter() {
|
|||||||
setValueMax(Number(e[1]))
|
setValueMax(Number(e[1]))
|
||||||
}}
|
}}
|
||||||
min={0}
|
min={0}
|
||||||
max={100}
|
max={max}
|
||||||
step={1}
|
step={1}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -55,7 +46,7 @@ export default function ModelSizeFilter() {
|
|||||||
type="text"
|
type="text"
|
||||||
className="mt-1 h-8 w-[60px] p-2"
|
className="mt-1 h-8 w-[60px] p-2"
|
||||||
min={0}
|
min={0}
|
||||||
max={100}
|
max={max}
|
||||||
value={inputingMinValue ? value : normalizeTextValue(value)}
|
value={inputingMinValue ? value : normalizeTextValue(value)}
|
||||||
textAlign="left"
|
textAlign="left"
|
||||||
onFocus={(e) => setInputingMinValue(true)}
|
onFocus={(e) => setInputingMinValue(true)}
|
||||||
@ -75,7 +66,7 @@ export default function ModelSizeFilter() {
|
|||||||
// E.g. anything changes that trigger onValueChanged
|
// E.g. anything changes that trigger onValueChanged
|
||||||
// Which is incorrect
|
// Which is incorrect
|
||||||
if (
|
if (
|
||||||
Number(e.target.value) > 100 ||
|
Number(e.target.value) > max ||
|
||||||
Number(e.target.value) < 0 ||
|
Number(e.target.value) < 0 ||
|
||||||
Number.isNaN(Number(e.target.value))
|
Number.isNaN(Number(e.target.value))
|
||||||
)
|
)
|
||||||
@ -91,7 +82,7 @@ export default function ModelSizeFilter() {
|
|||||||
type="text"
|
type="text"
|
||||||
className="mt-1 h-8 w-[60px] p-2"
|
className="mt-1 h-8 w-[60px] p-2"
|
||||||
min={0}
|
min={0}
|
||||||
max={100}
|
max={max}
|
||||||
value={inputingMaxValue ? valueMax : normalizeTextValue(valueMax)}
|
value={inputingMaxValue ? valueMax : normalizeTextValue(valueMax)}
|
||||||
textAlign="left"
|
textAlign="left"
|
||||||
onFocus={(e) => setInputingMaxValue(true)}
|
onFocus={(e) => setInputingMaxValue(true)}
|
||||||
@ -99,7 +90,7 @@ export default function ModelSizeFilter() {
|
|||||||
setInputingMaxValue(false)
|
setInputingMaxValue(false)
|
||||||
const numericValue = e.target.value.replace(/\D/g, '')
|
const numericValue = e.target.value.replace(/\D/g, '')
|
||||||
const value = Number(numericValue)
|
const value = Number(numericValue)
|
||||||
setValueMax(value > 100 ? 100 : value)
|
setValueMax(value > max ? max : value)
|
||||||
}}
|
}}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
// Passthru since it validates again onBlur
|
// Passthru since it validates again onBlur
|
||||||
@ -111,7 +102,7 @@ export default function ModelSizeFilter() {
|
|||||||
// E.g. anything changes that trigger onValueChanged
|
// E.g. anything changes that trigger onValueChanged
|
||||||
// Which is incorrect
|
// Which is incorrect
|
||||||
if (
|
if (
|
||||||
Number(e.target.value) > 100 ||
|
Number(e.target.value) > max ||
|
||||||
Number(e.target.value) < 0 ||
|
Number(e.target.value) < 0 ||
|
||||||
Number.isNaN(Number(e.target.value))
|
Number.isNaN(Number(e.target.value))
|
||||||
)
|
)
|
||||||
|
|||||||
@ -35,6 +35,7 @@ import {
|
|||||||
|
|
||||||
import ModelList from '@/screens/Hub/ModelList'
|
import ModelList from '@/screens/Hub/ModelList'
|
||||||
|
|
||||||
|
import { toGigabytes } from '@/utils/converter'
|
||||||
import { extractModelRepo } from '@/utils/modelSource'
|
import { extractModelRepo } from '@/utils/modelSource'
|
||||||
import { fuzzySearch } from '@/utils/search'
|
import { fuzzySearch } from '@/utils/search'
|
||||||
|
|
||||||
@ -110,6 +111,14 @@ const HubScreen = () => {
|
|||||||
const [maxModelSizeFilter, setMaxModelSizeFilter] =
|
const [maxModelSizeFilter, setMaxModelSizeFilter] =
|
||||||
useAtom(hubModelSizeMaxAtom)
|
useAtom(hubModelSizeMaxAtom)
|
||||||
|
|
||||||
|
const largestModel =
|
||||||
|
sources &&
|
||||||
|
sources
|
||||||
|
.flatMap((model) => model.models)
|
||||||
|
.reduce((max, model) => (model.size > max.size ? model : max), {
|
||||||
|
size: 0,
|
||||||
|
})
|
||||||
|
|
||||||
const searchedModels = useMemo(
|
const searchedModels = useMemo(
|
||||||
() =>
|
() =>
|
||||||
searchValue.length
|
searchValue.length
|
||||||
@ -135,7 +144,7 @@ const HubScreen = () => {
|
|||||||
!minModelSizeFilter ||
|
!minModelSizeFilter ||
|
||||||
model.models.some((e) => e.size >= minModelSizeFilter * (1 << 30))
|
model.models.some((e) => e.size >= minModelSizeFilter * (1 << 30))
|
||||||
const matchesMaxSize =
|
const matchesMaxSize =
|
||||||
maxModelSizeFilter === 100 ||
|
maxModelSizeFilter === largestModel?.size ||
|
||||||
model.models.some((e) => e.size <= maxModelSizeFilter * (1 << 30))
|
model.models.some((e) => e.size <= maxModelSizeFilter * (1 << 30))
|
||||||
|
|
||||||
return isCompatible && matchesCtxLen && matchesMinSize && matchesMaxSize
|
return isCompatible && matchesCtxLen && matchesMinSize && matchesMaxSize
|
||||||
@ -169,6 +178,19 @@ const HubScreen = () => {
|
|||||||
}
|
}
|
||||||
}, [modelDetail, sources, setModelDetail, addModelSource])
|
}, [modelDetail, sources, setModelDetail, addModelSource])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (largestModel) {
|
||||||
|
setMaxModelSizeFilter(
|
||||||
|
Number(
|
||||||
|
toGigabytes(Number(largestModel?.size), {
|
||||||
|
hideUnit: true,
|
||||||
|
toFixed: 0,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, [largestModel])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedModel) {
|
if (selectedModel) {
|
||||||
// Try add the model source again to update it's data
|
// Try add the model source again to update it's data
|
||||||
@ -403,7 +425,7 @@ const HubScreen = () => {
|
|||||||
<ModelSearch onSearchLocal={onSearchUpdate} />
|
<ModelSearch onSearchLocal={onSearchUpdate} />
|
||||||
<div
|
<div
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'invisible absolute mt-2 w-full overflow-hidden rounded-lg border border-[hsla(var(--app-border))] bg-[hsla(var(--app-bg))] shadow-lg',
|
'invisible absolute mt-2 max-h-[400px] w-full overflow-hidden rounded-lg border border-[hsla(var(--app-border))] bg-[hsla(var(--app-bg))] shadow-lg',
|
||||||
searchValue.length > 0 && 'visible'
|
searchValue.length > 0 && 'visible'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@ -414,7 +436,10 @@ const HubScreen = () => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<ScrollArea
|
||||||
|
type={showScrollBar ? 'always' : 'scroll'}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
{searchedModels.map((model) => (
|
{searchedModels.map((model) => (
|
||||||
<div
|
<div
|
||||||
key={model.id}
|
key={model.id}
|
||||||
@ -440,7 +465,7 @@ const HubScreen = () => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</>
|
</ScrollArea>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -468,7 +493,7 @@ const HubScreen = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCtxLenFilter(0)
|
setCtxLenFilter(0)
|
||||||
setMinModelSizeFilter(0)
|
setMinModelSizeFilter(0)
|
||||||
setMaxModelSizeFilter(100)
|
setMaxModelSizeFilter(Number(largestModel?.size))
|
||||||
setCompatible(false)
|
setCompatible(false)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -487,7 +512,14 @@ const HubScreen = () => {
|
|||||||
<ContextLengthFilter />
|
<ContextLengthFilter />
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-12">
|
<div className="mt-12">
|
||||||
<ModelSizeFilter />
|
<ModelSizeFilter
|
||||||
|
max={Number(
|
||||||
|
toGigabytes(Number(largestModel?.size), {
|
||||||
|
hideUnit: true,
|
||||||
|
toFixed: 0,
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -70,8 +70,9 @@ const MessageContainer: React.FC<
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'group relative mx-auto p-4',
|
'group relative mx-auto px-4 py-2',
|
||||||
chatWidth === 'compact' && 'max-w-[700px]'
|
chatWidth === 'compact' && 'max-w-[700px]',
|
||||||
|
isUser && 'pb-4 pt-0'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -109,11 +110,9 @@ const MessageContainer: React.FC<
|
|||||||
<div
|
<div
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'absolute right-0 order-1 mt-2 flex cursor-pointer items-center justify-start gap-x-2 transition-all',
|
'absolute right-0 order-1 mt-2 flex cursor-pointer items-center justify-start gap-x-2 transition-all',
|
||||||
isUser &&
|
isUser
|
||||||
'hidden group-hover:absolute group-hover:right-4 group-hover:top-4 group-hover:flex',
|
? 'hidden group-hover:absolute group-hover:right-4 group-hover:top-4 group-hover:flex'
|
||||||
props.isCurrentMessage && !isUser
|
: 'relative left-0 order-2 -mt-1 flex w-full justify-between opacity-0 group-hover:opacity-100'
|
||||||
? 'relative left-0 order-2 flex w-full justify-between'
|
|
||||||
: 'relative left-0 order-2 hidden w-full justify-between group-hover:flex'
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -1,14 +1,23 @@
|
|||||||
export const toGigabytes = (
|
export const toGigabytes = (
|
||||||
input: number,
|
input: number,
|
||||||
options?: { hideUnit?: boolean }
|
options?: { hideUnit?: boolean; toFixed?: number }
|
||||||
) => {
|
) => {
|
||||||
if (!input) return ''
|
if (!input) return ''
|
||||||
if (input > 1024 ** 3) {
|
if (input > 1024 ** 3) {
|
||||||
return (input / 1024 ** 3).toFixed(2) + (options?.hideUnit ? '' : 'GB')
|
return (
|
||||||
|
(input / 1024 ** 3).toFixed(options?.toFixed ?? 2) +
|
||||||
|
(options?.hideUnit ? '' : 'GB')
|
||||||
|
)
|
||||||
} else if (input > 1024 ** 2) {
|
} else if (input > 1024 ** 2) {
|
||||||
return (input / 1024 ** 2).toFixed(2) + (options?.hideUnit ? '' : 'MB')
|
return (
|
||||||
|
(input / 1024 ** 2).toFixed(options?.toFixed ?? 2) +
|
||||||
|
(options?.hideUnit ? '' : 'MB')
|
||||||
|
)
|
||||||
} else if (input > 1024) {
|
} else if (input > 1024) {
|
||||||
return (input / 1024).toFixed(2) + (options?.hideUnit ? '' : 'KB')
|
return (
|
||||||
|
(input / 1024).toFixed(options?.toFixed ?? 2) +
|
||||||
|
(options?.hideUnit ? '' : 'KB')
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
return input + (options?.hideUnit ? '' : 'B')
|
return input + (options?.hideUnit ? '' : 'B')
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user