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