diff --git a/web/app/_components/ModelActionButton/index.tsx b/web/app/_components/ModelActionButton/index.tsx index 9bf0147bcb..4f97072cc8 100644 --- a/web/app/_components/ModelActionButton/index.tsx +++ b/web/app/_components/ModelActionButton/index.tsx @@ -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 = ({ onDeleteClick, }) => { const styles = modelActionMapper[type] + // const { startingModel } = useStartStopModel() + const onClick = () => { onActionClick(type) } + const state = useAtomValue(stateModel) + return (
@@ -43,7 +50,8 @@ const ModelActionButton: React.FC = ({ diff --git a/web/app/_components/ModelRow/index.tsx b/web/app/_components/ModelRow/index.tsx index ae972747b8..80e5bd6f29 100644 --- a/web/app/_components/ModelRow/index.tsx +++ b/web/app/_components/ModelRow/index.tsx @@ -40,20 +40,20 @@ const ModelRow: React.FC = ({ model }) => { }, [model]) return ( - - + + {model.name} v{model.version} - +
GGUF
- + {toGigabytes(model.size)} - + = { [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', }, } diff --git a/web/containers/BottomBar/index.tsx b/web/containers/BottomBar/index.tsx index a69a0de4b6..6526b71372 100644 --- a/web/containers/BottomBar/index.tsx +++ b/web/containers/BottomBar/index.tsx @@ -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 (
- + {stateModelStartStop.state === 'start' && + stateModelStartStop.loading && ( + + )} + {stateModelStartStop.state === 'stop' && + stateModelStartStop.loading && ( + + )} + {!stateModelStartStop.loading && ( + + )} {downloadStates.length > 0 && ( (undefined) - export const activeAssistantModelAtom = atom( undefined ) diff --git a/web/hooks/useStartStopModel.ts b/web/hooks/useStartStopModel.ts index a35a35e8a8..829dc0906a 100644 --- a/web/hooks/useStartStopModel.ts +++ b/web/hooks/useStartStopModel.ts @@ -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 } diff --git a/web/uikit/button/index.tsx b/web/uikit/button/index.tsx index 6cbf41af20..8035b2e1bd 100644 --- a/web/uikit/button/index.tsx +++ b/web/uikit/button/index.tsx @@ -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( - ({ className, themes, size, asChild = false, ...props }, ref) => { + ( + { className, themes, size, loading, asChild = false, children, ...props }, + ref + ) => { const Comp = asChild ? Slot : 'button' return ( + > + {loading ? ( + <> + + {children} + + ) : ( + children + )} + ) } )