Added loader starting and stopping model
This commit is contained in:
parent
e0dd07c0f8
commit
bd72e4348e
@ -1,6 +1,9 @@
|
||||
import React from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import { Button } from '@uikit'
|
||||
import ModelActionMenu from '../ModelActionMenu'
|
||||
import { useAtomValue } from 'jotai'
|
||||
|
||||
import { stateModel } from '@helpers/atoms/Model.atom'
|
||||
|
||||
export enum ModelActionType {
|
||||
Start = 'Start',
|
||||
@ -32,10 +35,14 @@ const ModelActionButton: React.FC<Props> = ({
|
||||
onDeleteClick,
|
||||
}) => {
|
||||
const styles = modelActionMapper[type]
|
||||
// const { startingModel } = useStartStopModel()
|
||||
|
||||
const onClick = () => {
|
||||
onActionClick(type)
|
||||
}
|
||||
|
||||
const state = useAtomValue(stateModel)
|
||||
|
||||
return (
|
||||
<td className="whitespace-nowrap px-3 py-2 text-right">
|
||||
<div className="flex items-center justify-end gap-x-4">
|
||||
@ -43,7 +50,8 @@ const ModelActionButton: React.FC<Props> = ({
|
||||
<Button
|
||||
size="sm"
|
||||
themes={styles.title === 'Start' ? 'accent' : 'default'}
|
||||
onClick={onClick}
|
||||
onClick={() => onClick()}
|
||||
loading={state.loading}
|
||||
>
|
||||
{styles.title} Model
|
||||
</Button>
|
||||
|
||||
@ -40,20 +40,20 @@ const ModelRow: React.FC<Props> = ({ model }) => {
|
||||
}, [model])
|
||||
|
||||
return (
|
||||
<tr className="bg-background/50 border-border border-b last:rounded-lg last:border-b-0">
|
||||
<td className="text-muted-foreground whitespace-nowrap px-3 font-semibold">
|
||||
<tr className="border-b border-border bg-background/50 last:rounded-lg last:border-b-0">
|
||||
<td className="whitespace-nowrap px-3 font-semibold text-muted-foreground">
|
||||
{model.name}
|
||||
<span className="ml-2 font-semibold">v{model.version}</span>
|
||||
</td>
|
||||
<td className="text-muted-foreground whitespace-nowrap px-3">
|
||||
<td className="whitespace-nowrap px-3 text-muted-foreground">
|
||||
<div className="flex flex-col justify-start">
|
||||
<span>GGUF</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-muted-foreground whitespace-nowrap px-3">
|
||||
<td className="whitespace-nowrap px-3 text-muted-foreground">
|
||||
{toGigabytes(model.size)}
|
||||
</td>
|
||||
<td className="text-muted-foreground whitespace-nowrap px-3">
|
||||
<td className="whitespace-nowrap px-3 text-muted-foreground">
|
||||
<ModelStatusComponent status={status} />
|
||||
</td>
|
||||
<ModelActionButton
|
||||
|
||||
@ -21,12 +21,12 @@ export const ModelStatusMapper: Record<ModelStatus, ModelStatusType> = {
|
||||
[ModelStatus.Active]: {
|
||||
title: 'Active',
|
||||
textColor: 'text-green-800',
|
||||
backgroundColor: 'bg-green-100 dark:bg-green-300',
|
||||
backgroundColor: 'bg-green-100 dark:bg-green-300 text-green-700',
|
||||
},
|
||||
[ModelStatus.RunningInNitro]: {
|
||||
title: 'Running in Nitro',
|
||||
textColor: 'text-green-800',
|
||||
backgroundColor: 'bg-green-100 dark:bg-green-300',
|
||||
backgroundColor: 'bg-green-100 dark:bg-green-300 text-green-700',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -4,10 +4,11 @@ import useGetSystemResources from '@hooks/useGetSystemResources'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { modelDownloadStateAtom } from '@helpers/atoms/DownloadState.atom'
|
||||
import { formatDownloadPercentage } from '@utils/converter'
|
||||
import { activeAssistantModelAtom } from '@helpers/atoms/Model.atom'
|
||||
import { activeAssistantModelAtom, stateModel } from '@helpers/atoms/Model.atom'
|
||||
|
||||
const BottomBar = () => {
|
||||
const activeModel = useAtomValue(activeAssistantModelAtom)
|
||||
const stateModelStartStop = useAtomValue(stateModel)
|
||||
const { ram, cpu } = useGetSystemResources()
|
||||
const modelDownloadStates = useAtomValue(modelDownloadStateAtom)
|
||||
|
||||
@ -16,10 +17,28 @@ const BottomBar = () => {
|
||||
downloadStates.push(value)
|
||||
}
|
||||
|
||||
console.log(stateModelStartStop)
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-0 left-0 z-20 flex h-8 w-full items-center justify-between border-t border-border bg-background/50 px-4">
|
||||
<div className="flex gap-x-2">
|
||||
<SystemItem name="Active model:" value={activeModel?.name || '-'} />
|
||||
{stateModelStartStop.state === 'start' &&
|
||||
stateModelStartStop.loading && (
|
||||
<SystemItem
|
||||
name="Starting:"
|
||||
value={stateModelStartStop.model || '-'}
|
||||
/>
|
||||
)}
|
||||
{stateModelStartStop.state === 'stop' &&
|
||||
stateModelStartStop.loading && (
|
||||
<SystemItem
|
||||
name="Stopping:"
|
||||
value={stateModelStartStop.model || '-'}
|
||||
/>
|
||||
)}
|
||||
{!stateModelStartStop.loading && (
|
||||
<SystemItem name="Active model:" value={activeModel?.name || '-'} />
|
||||
)}
|
||||
{downloadStates.length > 0 && (
|
||||
<SystemItem
|
||||
name="Downloading:"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { atom } from 'jotai'
|
||||
|
||||
export const stateModel = atom({ state: 'start', loading: false, model: '' })
|
||||
export const selectedModelAtom = atom<AssistantModel | undefined>(undefined)
|
||||
|
||||
export const activeAssistantModelAtom = atom<AssistantModel | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
@ -2,27 +2,35 @@ import { executeSerial } from '@services/pluginService'
|
||||
import { ModelManagementService, InferenceService } from '@janhq/core'
|
||||
import useInitModel from './useInitModel'
|
||||
import { useSetAtom } from 'jotai'
|
||||
import { activeAssistantModelAtom } from '@helpers/atoms/Model.atom'
|
||||
import { activeAssistantModelAtom, stateModel } from '@helpers/atoms/Model.atom'
|
||||
|
||||
export default function useStartStopModel() {
|
||||
const { initModel } = useInitModel()
|
||||
const setActiveModel = useSetAtom(activeAssistantModelAtom)
|
||||
const setStateModel = useSetAtom(stateModel)
|
||||
|
||||
const startModel = async (modelId: string) => {
|
||||
setStateModel({ state: 'start', loading: true, model: modelId })
|
||||
const model = await executeSerial(
|
||||
ModelManagementService.GetModelById,
|
||||
modelId
|
||||
)
|
||||
if (!model) {
|
||||
alert(`Model ${modelId} not found! Please re-download the model first.`)
|
||||
setStateModel((prev) => ({ ...prev, loading: false }))
|
||||
} else {
|
||||
await initModel(model)
|
||||
setStateModel((prev) => ({ ...prev, loading: false }))
|
||||
}
|
||||
}
|
||||
|
||||
const stopModel = async (modelId: string) => {
|
||||
await executeSerial(InferenceService.StopModel, modelId)
|
||||
setActiveModel(undefined)
|
||||
setStateModel({ state: 'stop', loading: true, model: modelId })
|
||||
setTimeout(async () => {
|
||||
await executeSerial(InferenceService.StopModel, modelId)
|
||||
setActiveModel(undefined)
|
||||
setStateModel({ state: 'stop', loading: false, model: modelId })
|
||||
}, 500)
|
||||
}
|
||||
|
||||
return { startModel, stopModel }
|
||||
|
||||
@ -18,10 +18,14 @@ const buttonVariants = cva(
|
||||
sm: 'h-6 px-2 text-xs rounded-md',
|
||||
default: 'h-8 px-3',
|
||||
},
|
||||
loading: {
|
||||
true: 'pointer-events-none opacity-70',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
themes: 'default',
|
||||
size: 'default',
|
||||
loading: false,
|
||||
},
|
||||
}
|
||||
)
|
||||
@ -33,14 +37,49 @@ export interface ButtonProps
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, themes, size, asChild = false, ...props }, ref) => {
|
||||
(
|
||||
{ className, themes, size, loading, asChild = false, children, ...props },
|
||||
ref
|
||||
) => {
|
||||
const Comp = asChild ? Slot : 'button'
|
||||
return (
|
||||
<Comp
|
||||
className={twMerge(buttonVariants({ themes, size, className }))}
|
||||
className={twMerge(
|
||||
buttonVariants({ themes, size, loading, className })
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
role="status"
|
||||
className="mr-2 h-4 animate-spin"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
></circle>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
</svg>
|
||||
{children}
|
||||
</>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</Comp>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user