chore: update model handlers on the new frontend (#5011)
* chore: provide model handlers to new frontend * chore: add API server function to the new front end
This commit is contained in:
parent
74c2c59c90
commit
2345ff172d
@ -5,12 +5,15 @@ import {
|
||||
} from '@/components/ui/popover'
|
||||
import { Progress } from '@/components/ui/progress'
|
||||
import { useDownloadStore } from '@/hooks/useDownloadStore'
|
||||
import { useModelProvider } from '@/hooks/useModelProvider'
|
||||
import { abortDownload } from '@/services/models'
|
||||
import { getProviders } from '@/services/providers'
|
||||
import { DownloadEvent, DownloadState, events } from '@janhq/core'
|
||||
import { IconX } from '@tabler/icons-react'
|
||||
import { useCallback, useEffect, useMemo } from 'react'
|
||||
|
||||
export function DownloadManagement() {
|
||||
const { setProviders } = useModelProvider()
|
||||
const { downloads, updateProgress, removeDownload } = useDownloadStore()
|
||||
const downloadCount = useMemo(
|
||||
() => Object.keys(downloads).length,
|
||||
@ -72,8 +75,9 @@ export function DownloadManagement() {
|
||||
async (state: DownloadState) => {
|
||||
console.debug('onFileDownloadSuccess', state)
|
||||
removeDownload(state.modelId)
|
||||
getProviders().then(setProviders)
|
||||
},
|
||||
[removeDownload]
|
||||
[removeDownload, setProviders]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@ -9,22 +9,37 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@/components/ui/dialog'
|
||||
import { useModelProvider } from '@/hooks/useModelProvider'
|
||||
import { deleteModel } from '@/services/models'
|
||||
import { getProviders } from '@/services/providers'
|
||||
|
||||
import { IconTrash } from '@tabler/icons-react'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
type DialoDeleteModelProps = {
|
||||
type DialogDeleteModelProps = {
|
||||
provider: ModelProvider
|
||||
modelId?: string
|
||||
}
|
||||
|
||||
export const DialoDeleteModel = ({
|
||||
export const DialogDeleteModel = ({
|
||||
provider,
|
||||
modelId,
|
||||
}: DialoDeleteModelProps) => {
|
||||
}: DialogDeleteModelProps) => {
|
||||
const [selectedModelId, setSelectedModelId] = useState<string>('')
|
||||
const { setProviders, deleteModel: deleteModelCache } = useModelProvider()
|
||||
|
||||
const removeModel = async () => {
|
||||
deleteModelCache(selectedModelId)
|
||||
deleteModel(selectedModelId).then(() => {
|
||||
getProviders().then(setProviders)
|
||||
toast.success('Delete Model', {
|
||||
id: `delete-model-${selectedModel?.id}`,
|
||||
description: `Model ${selectedModel?.id} has been permanently deleted.`,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Initialize with the provided model ID or the first model if available
|
||||
useEffect(() => {
|
||||
@ -68,16 +83,7 @@ export const DialoDeleteModel = ({
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
toast.success('Delete Model', {
|
||||
id: `delete-model-${selectedModel.id}`,
|
||||
description: `Model ${selectedModel.id} has been permanently deleted.`,
|
||||
})
|
||||
}}
|
||||
>
|
||||
<Button variant="destructive" size="sm" onClick={removeModel}>
|
||||
Delete
|
||||
</Button>
|
||||
</DialogClose>
|
||||
|
||||
@ -21,6 +21,9 @@ type LocalApiServerState = {
|
||||
// Verbose server logs
|
||||
verboseLogs: boolean
|
||||
setVerboseLogs: (value: boolean) => void
|
||||
// Server status
|
||||
serverStatus: 'running' | 'stopped' | 'pending'
|
||||
setServerStatus: (value: 'running' | 'stopped' | 'pending') => void
|
||||
}
|
||||
|
||||
export const useLocalApiServer = create<LocalApiServerState>()(
|
||||
@ -38,6 +41,8 @@ export const useLocalApiServer = create<LocalApiServerState>()(
|
||||
setCorsEnabled: (value) => set({ corsEnabled: value }),
|
||||
verboseLogs: true,
|
||||
setVerboseLogs: (value) => set({ verboseLogs: value }),
|
||||
serverStatus: 'stopped',
|
||||
setServerStatus: (value) => set({ serverStatus: value }),
|
||||
}),
|
||||
{
|
||||
name: localStoregeKey.settingLocalApiServer,
|
||||
|
||||
@ -13,6 +13,7 @@ type ModelProviderState = {
|
||||
providerName: string,
|
||||
modelName: string
|
||||
) => Model | undefined
|
||||
deleteModel: (modelId: string) => void
|
||||
}
|
||||
|
||||
export const useModelProvider = create<ModelProviderState>()(
|
||||
@ -31,7 +32,9 @@ export const useModelProvider = create<ModelProviderState>()(
|
||||
const models = existingProvider?.models || []
|
||||
const mergedModels = [
|
||||
...(provider?.models ?? []),
|
||||
...models.filter((e) => !provider?.models.some((m) => m.id === e.id)),
|
||||
...models.filter(
|
||||
(e) => !provider?.models.some((m) => m.id === e.id)
|
||||
),
|
||||
]
|
||||
return {
|
||||
...provider,
|
||||
@ -98,6 +101,19 @@ export const useModelProvider = create<ModelProviderState>()(
|
||||
|
||||
return modelObject
|
||||
},
|
||||
deleteModel: (modelId: string) => {
|
||||
set((state) => ({
|
||||
providers: state.providers.map((provider) => {
|
||||
const models = provider.models.filter(
|
||||
(model) => model.id !== modelId
|
||||
)
|
||||
return {
|
||||
...provider,
|
||||
models,
|
||||
}
|
||||
}),
|
||||
}))
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: localStoregeKey.modelProvider,
|
||||
|
||||
@ -19,8 +19,44 @@ export const Route = createFileRoute(route.settings.local_api_server as any)({
|
||||
|
||||
function LocalAPIServer() {
|
||||
const { t } = useTranslation()
|
||||
const { corsEnabled, setCorsEnabled, verboseLogs, setVerboseLogs } =
|
||||
useLocalApiServer()
|
||||
const {
|
||||
corsEnabled,
|
||||
setCorsEnabled,
|
||||
verboseLogs,
|
||||
setVerboseLogs,
|
||||
serverHost,
|
||||
serverPort,
|
||||
apiPrefix,
|
||||
serverStatus,
|
||||
setServerStatus,
|
||||
} = useLocalApiServer()
|
||||
|
||||
const toggleAPIServer = async () => {
|
||||
setServerStatus('pending')
|
||||
if (serverStatus === 'stopped') {
|
||||
window.core?.api
|
||||
?.startServer({
|
||||
host: serverHost,
|
||||
port: serverPort,
|
||||
prefix: apiPrefix,
|
||||
isCorsEnabled: corsEnabled,
|
||||
isVerboseEnabled: verboseLogs,
|
||||
})
|
||||
.then(() => {
|
||||
setServerStatus('running')
|
||||
})
|
||||
} else {
|
||||
window.core?.api
|
||||
?.stopServer()
|
||||
.then(() => {
|
||||
setServerStatus('stopped')
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
console.error('Error stopping server:', error)
|
||||
setServerStatus('stopped')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleOpenLogs = async () => {
|
||||
try {
|
||||
@ -78,7 +114,10 @@ function LocalAPIServer() {
|
||||
Start an OpenAI-compatible local HTTP server.
|
||||
</p>
|
||||
</div>
|
||||
<Button>Start Server</Button>
|
||||
<Button onClick={toggleAPIServer}>
|
||||
{`${serverStatus === 'running' ? 'Stop' : 'Start'}`}{' '}
|
||||
Server
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
|
||||
@ -18,7 +18,7 @@ import { RenderMarkdown } from '@/containers/RenderMarkdown'
|
||||
import { DialogEditModel } from '@/containers/dialogs/EditModel'
|
||||
import { DialogAddModel } from '@/containers/dialogs/AddModel'
|
||||
import { ModelSetting } from '@/containers/ModelSetting'
|
||||
import { DialoDeleteModel } from '@/containers/dialogs/DeleteModel'
|
||||
import { DialogDeleteModel } from '@/containers/dialogs/DeleteModel'
|
||||
import Joyride, { CallBackProps, STATUS } from 'react-joyride'
|
||||
import { CustomTooltipJoyRide } from '@/containers/CustomeTooltipJoyRide'
|
||||
import { route } from '@/constants/routes'
|
||||
@ -250,7 +250,7 @@ function ProviderDetail() {
|
||||
{model.settings && (
|
||||
<ModelSetting provider={provider} model={model} />
|
||||
)}
|
||||
<DialoDeleteModel
|
||||
<DialogDeleteModel
|
||||
provider={provider}
|
||||
modelId={model.id}
|
||||
/>
|
||||
|
||||
@ -35,6 +35,16 @@ export const fetchModelSources = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the model hub.
|
||||
* @returns A promise that resolves to the model hub.
|
||||
*/
|
||||
export const fetchModelHub = async () => {
|
||||
return ExtensionManager.getInstance()
|
||||
.get<ModelExtension>(ExtensionTypeEnum.Model)
|
||||
?.fetchModelsHub()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new model source.
|
||||
* @param source The source to add.
|
||||
@ -137,3 +147,23 @@ export const abortDownload = async (id: string) => {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a model.
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
export const deleteModel = async (id: string) => {
|
||||
const extension = ExtensionManager.getInstance().get<ModelExtension>(
|
||||
ExtensionTypeEnum.Model
|
||||
)
|
||||
|
||||
if (!extension) throw new Error('Model extension not found')
|
||||
|
||||
try {
|
||||
return await extension.deleteModel(id)
|
||||
} catch (error) {
|
||||
console.error('Failed to delete model:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { models as providerModels } from 'token.js'
|
||||
import { mockModelProvider } from '@/mock/data'
|
||||
import { EngineManager, ModelManager } from '@janhq/core'
|
||||
import { EngineManager } from '@janhq/core'
|
||||
import { ModelCapabilities } from '@/types/models'
|
||||
import { modelSettings } from '@/lib/predefined'
|
||||
import { fetchModels } from './models'
|
||||
|
||||
export const getProviders = async (): Promise<ModelProvider[]> => {
|
||||
const builtinProviders = mockModelProvider.map((provider) => {
|
||||
@ -42,8 +43,9 @@ export const getProviders = async (): Promise<ModelProvider[]> => {
|
||||
for (const [key, value] of EngineManager.instance().engines) {
|
||||
// TODO: Remove this when the cortex extension is removed
|
||||
const providerName = key === 'cortex' ? 'llama.cpp' : key
|
||||
|
||||
const models =
|
||||
Array.from(ModelManager.instance().models.values()).filter(
|
||||
((await fetchModels()) ?? []).filter(
|
||||
(model) =>
|
||||
(model.engine === 'llama-cpp' ? 'llama.cpp' : model.engine) ===
|
||||
providerName &&
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user