chore: add functional use button when download complete

This commit is contained in:
Faisal Amir 2025-05-19 12:35:18 +07:00
parent 53f5729674
commit 1435cd3162
3 changed files with 103 additions and 30 deletions

View File

@ -125,7 +125,7 @@ export function DownloadManagement() {
<div className="mt-2 flex items-center justify-between space-x-2">
<Progress value={overallProgress * 100} />
<span className="text-xs font-medium text-main-view-fg/80 shrink-0">
{overallProgress.toFixed(2)}%
{Math.round(overallProgress * 100)}%
</span>
</div>
</div>
@ -175,7 +175,7 @@ export function DownloadManagement() {
/>
<p className="text-main-view-fg/60 text-xs">
{`${renderGB(download.current)} / ${renderGB(download.total)}`}{' '}
GB ({download.progress.toFixed(2)}%)
GB ({Math.round(download.progress * 100)}%)
</p>
</div>
))}

View File

@ -1,9 +1,10 @@
import { createFileRoute, Link } from '@tanstack/react-router'
import { createFileRoute, Link, useNavigate } from '@tanstack/react-router'
import { route } from '@/constants/routes'
import { useModelSources } from '@/hooks/useModelSources'
import { cn, fuzzySearch, toGigabytes } from '@/lib/utils'
import { useState, useMemo, useEffect, ChangeEvent } from 'react'
import { useState, useMemo, useEffect, ChangeEvent, useCallback } from 'react'
import { Button } from '@/components/ui/button'
import { useModelProvider } from '@/hooks/useModelProvider'
import { Card, CardItem } from '@/containers/Card'
import { RenderMarkdown } from '@/containers/RenderMarkdown'
import { extractModelName, extractDescription } from '@/lib/models'
@ -19,6 +20,15 @@ import { downloadModel } from '@/services/models'
import { useDownloadStore } from '@/hooks/useDownloadStore'
import { Progress } from '@/components/ui/progress'
type ModelProps = {
model: {
id: string
models: {
id: string
}[]
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const Route = createFileRoute(route.hub as any)({
component: Hub,
@ -93,14 +103,26 @@ function Hub() {
[downloads]
)
interface ModelProps {
model: {
id: string
models: {
id: string
}[]
}
}
const { getProviderByName } = useModelProvider()
const llamaProvider = getProviderByName('llama.cpp')
const navigate = useNavigate()
const handleUseModel = useCallback(
(modelId: string) => {
navigate({
to: route.home,
params: {},
search: {
model: {
id: modelId,
provider: 'llama.cpp',
},
},
})
},
[navigate]
)
const DownloadButtonPlaceholder = useMemo(() => {
return ({ model }: ModelProps) => {
@ -108,6 +130,9 @@ function Hub() {
const isDownloading = downloadProcesses.some((e) => e.id === modelId)
const downloadProgress =
downloadProcesses.find((e) => e.id === modelId)?.progress || 0
const isDownloaded = llamaProvider?.models.some(
(m: { id: string }) => m.id === modelId
)
return (
<>
@ -118,13 +143,19 @@ function Hub() {
{Math.round(downloadProgress * 100)}%
</span>
</div>
) : isDownloaded ? (
<Button size="sm" onClick={() => handleUseModel(modelId)}>
Use
</Button>
) : (
<Button onClick={() => downloadModel(modelId)}>Download</Button>
<Button size="sm" onClick={() => downloadModel(modelId)}>
Download
</Button>
)}
</>
)
}
}, [downloadProcesses])
}, [downloadProcesses, llamaProvider?.models, handleUseModel])
return (
<div className="flex h-full w-full">
@ -282,20 +313,50 @@ function Hub() {
downloadProcesses.find(
(e) => e.id === variant.id
)?.progress || 0
const isDownloaded =
llamaProvider?.models.some(
(m: { id: string }) =>
m.id === variant.id
)
return isDownloading ? (
<>
<div className="flex items-center gap-2 w-20">
<Progress
value={downloadProgress * 100}
/>
<span className="text-xs text-center text-main-view-fg/70">
{Math.round(downloadProgress * 100)}
%
</span>
if (isDownloading) {
return (
<>
<div className="flex items-center gap-2 w-20">
<Progress
value={downloadProgress * 100}
/>
<span className="text-xs text-center text-main-view-fg/70">
{Math.round(
downloadProgress * 100
)}
%
</span>
</div>
</>
)
}
if (isDownloaded) {
return (
<div
className="flex items-center justify-center rounded bg-main-view-fg/10"
title="Use this model"
>
<Button
variant="link"
size="sm"
onClick={() =>
handleUseModel(variant.id)
}
>
Use
</Button>
</div>
</>
) : (
)
}
return (
<div
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
title="Download model"

View File

@ -1,20 +1,32 @@
import { createFileRoute } from '@tanstack/react-router'
import { route } from '@/constants/routes'
/* eslint-disable @typescript-eslint/no-explicit-any */
import { createFileRoute, useSearch } from '@tanstack/react-router'
import ChatInput from '@/containers/ChatInput'
import HeaderPage from '@/containers/HeaderPage'
import { useTranslation } from 'react-i18next'
import DropdownModelProvider from '@/containers/DropdownModelProvider'
import { useModelProvider } from '@/hooks/useModelProvider'
import SetupScreen from '@/containers/SetupScreen'
import { route } from '@/constants/routes'
type SearchParams = {
model?: {
id: string
provider: string
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const Route = createFileRoute(route.home as any)({
component: Index,
validateSearch: (search: Record<string, unknown>): SearchParams => ({
model: search.model as SearchParams['model'],
}),
})
function Index() {
const { t } = useTranslation()
const { providers } = useModelProvider()
const search = useSearch({ from: route.home as any })
const selectedModel = search.model
// Conditional to check if there are any valid providers
// required min 1 api_key or 1 model in llama.cpp
@ -31,7 +43,7 @@ function Index() {
return (
<div className="flex h-full flex-col flex-justify-center">
<HeaderPage>
<DropdownModelProvider />
<DropdownModelProvider model={selectedModel} />
</HeaderPage>
<div className="h-full px-8 overflow-y-auto flex flex-col gap-2 justify-center">
<div className="w-4/6 mx-auto">