* feat: integrating cortex * Temporary prevent crash Signed-off-by: James <namnh0122@gmail.com> * fix yarn lint Signed-off-by: James <namnh0122@gmail.com> * refactor: remove core node module - fs - extensions and so on (#3151) * add migration script for threads, messages and models Signed-off-by: James <namnh0122@gmail.com> * remove freq_penalty and presence_penalty if model not supported Signed-off-by: James <namnh0122@gmail.com> * add back models in my models Signed-off-by: James <namnh0122@gmail.com> * fix api-url for setup API key popup Signed-off-by: James <namnh0122@gmail.com> * fix using model name for dropdown model Signed-off-by: James <namnh0122@gmail.com> * fix can't click to hotkey Signed-off-by: James <namnh0122@gmail.com> * fix: disable some UIs Signed-off-by: James <namnh0122@gmail.com> * fix build Signed-off-by: James <namnh0122@gmail.com> * reduce calling HF api Signed-off-by: James <namnh0122@gmail.com> * some ui update Signed-off-by: James <namnh0122@gmail.com> * feat: modal migration UI (#3153) * feat: handle popup migration * chore: update loader * chore: integrate script migration * chore: cleanup import * chore: moving out spinner loader * chore: update check thread message success migrate * chore: add handle script into retry button * remove warning from joi Signed-off-by: James <namnh0122@gmail.com> * chore: fix duplicate children * fix: path after migrating model Signed-off-by: James <namnh0122@gmail.com> * chore: apply mutation for config * chore: prevent calling too many create assistant api Signed-off-by: James <namnh0122@gmail.com> * using cortexso Signed-off-by: James <namnh0122@gmail.com> * update download api Signed-off-by: James <namnh0122@gmail.com> * fix use on slider item Signed-off-by: James <namnh0122@gmail.com> * fix: ui no download model or simple onboarding (#3166) * fix download huggingface model match with slider item Signed-off-by: James <namnh0122@gmail.com> * update owner_logo to logo and author Signed-off-by: James <namnh0122@gmail.com> * update new cortexso Signed-off-by: James <namnh0122@gmail.com> * Add install python step for macos * add engine table Signed-off-by: James <namnh0122@gmail.com> * fix local icons Signed-off-by: James <namnh0122@gmail.com> * feat: add search feature for model hub Signed-off-by: James <namnh0122@gmail.com> * fix misalign switch Signed-off-by: James <namnh0122@gmail.com> * fix: delete thread not focus on other thread Signed-off-by: James <namnh0122@gmail.com> * add get model from hugging face Signed-off-by: James <namnh0122@gmail.com> * fix download from hugging face Signed-off-by: James <namnh0122@gmail.com> * small update Signed-off-by: James <namnh0122@gmail.com> * update Signed-off-by: James <namnh0122@gmail.com> * fix system monitor rounded only on the left Signed-off-by: James <namnh0122@gmail.com> * chore: update ui new hub screen (#3174) * chore: update ui new hub screen * chore: update layout centerpanel thread and hub screen * chore: update detail model by group * update cortexso 0.1.13 Signed-off-by: James <namnh0122@gmail.com> * chore: add file size Signed-off-by: James <namnh0122@gmail.com> * chore: put engine to experimental feature Signed-off-by: James <namnh0122@gmail.com> * chore: open cortex folder Signed-off-by: James <namnh0122@gmail.com> * chore: add back user avatar Signed-off-by: James <namnh0122@gmail.com> * chore: minor UI hub (#3182) * chore: add back right click thread list and update 3 dots are overlapping with the text * chore: update position dropdown list my models * chore: make on-device tab showing 6 items instead of 4 * chore: update style description modals detail model * chore: update isGeneration loader and author name on modal * feat: integrate cortex single executable Signed-off-by: James <namnh0122@gmail.com> * fix build Signed-off-by: James <namnh0122@gmail.com> * chore: added blank state * chore: update ui component blank state * bump cortex binary version * fix: logic show modal migration (#3165) * fix: logic show modal migration * chore: fixed logic * chore: read contain format gguf local models * chore: change return hasLocalModel * chore: intiial skipmigration state * chore: filter embedding model * fix: delete top thread not focus on any other thread * chore: added UI no result component search models group (#3188) * fix: remote model should show all when user config that engine Signed-off-by: James <namnh0122@gmail.com> * chore: set state thread and models migration using getOnInit (#3189) * chore: set state thread and models migration using getOnInit * chore: add state as dependecies hooks * chore: system monitor panel show engine model (#3192) * fix: remove config api, replace with engine Signed-off-by: James <namnh0122@gmail.com> * update Signed-off-by: James <namnh0122@gmail.com> * update reactquery Signed-off-by: James <namnh0122@gmail.com> * bump cortex 0.4.35 * feat: add waiting for cortex popup Signed-off-by: James <namnh0122@gmail.com> * chore: add loader detail model popup (#3195) * chore: model start loader (#3197) * chore: added model loader when user starting chat without model active * chore: update copies loader * fix: select min file size if recommended quant does not exist Signed-off-by: James <namnh0122@gmail.com> * chore: temporary hide gpu config * fix: tensorrt not shown Signed-off-by: James <namnh0122@gmail.com> * fix lint Signed-off-by: James <namnh0122@gmail.com> * fix tests Signed-off-by: James <namnh0122@gmail.com> * fix e2e tests (wip) Signed-off-by: James <namnh0122@gmail.com> * update Signed-off-by: James <namnh0122@gmail.com> * fix: adding element and correct test to adapt new UI * fix: temp skip unstable part * fix: only show models which can be supported Signed-off-by: James <namnh0122@gmail.com> * Update version.txt * update send message Signed-off-by: James <namnh0122@gmail.com> * fix: not allow user send message when is generating Signed-off-by: James <namnh0122@gmail.com> * chore: temp skip Playwright test due to env issue * chore: temp skip Playwright test due to env issue * update Signed-off-by: James <namnh0122@gmail.com> * chore: minor-ui-feedback (#3202) --------- Signed-off-by: James <namnh0122@gmail.com> Co-authored-by: Louis <louis@jan.ai> Co-authored-by: Faisal Amir <urmauur@gmail.com> Co-authored-by: Hien To <tominhhien97@gmail.com> Co-authored-by: Van Pham <64197333+Van-QA@users.noreply.github.com> Co-authored-by: Van-QA <van@jan.ai>
402 lines
11 KiB
TypeScript
402 lines
11 KiB
TypeScript
import 'cortexso-node/shims/web'
|
|
import { useCallback } from 'react'
|
|
|
|
import {
|
|
Assistant,
|
|
Model,
|
|
Message,
|
|
Thread,
|
|
ChatCompletionCreateParamsNonStreaming,
|
|
ChatCompletionCreateParamsStreaming,
|
|
AssistantCreateParams,
|
|
AssistantUpdateParams,
|
|
LlmEngine,
|
|
} from '@janhq/core'
|
|
|
|
import { Cortex } from 'cortexso-node'
|
|
|
|
import { useAtomValue } from 'jotai'
|
|
|
|
import { UpdateConfigMutationVariables } from './useEngineMutation'
|
|
import { MessageCreateMutationVariables } from './useMessageCreateMutation'
|
|
import { MessageDeleteMutationVariables } from './useMessageDeleteMutation'
|
|
import { MessageUpdateMutationVariables } from './useMessageUpdateMutation'
|
|
|
|
import { hostAtom } from '@/helpers/atoms/AppConfig.atom'
|
|
|
|
const EngineInitStatuses = [
|
|
'ready',
|
|
'not_initialized',
|
|
'missing_configuration',
|
|
'not_supported',
|
|
] as const
|
|
export type EngineInitStatus = (typeof EngineInitStatuses)[number]
|
|
|
|
export type EngineStatus = {
|
|
name: LlmEngine
|
|
description: string
|
|
version: string
|
|
productName: string
|
|
status: EngineInitStatus
|
|
}
|
|
|
|
const useCortex = () => {
|
|
const host = useAtomValue(hostAtom)
|
|
|
|
const cortex = new Cortex({
|
|
baseURL: host,
|
|
apiKey: '',
|
|
dangerouslyAllowBrowser: true,
|
|
})
|
|
|
|
// TODO: put in to cortexso-node?
|
|
const getEngineStatuses = useCallback(async (): Promise<EngineStatus[]> => {
|
|
const response = await fetch(`${host}/engines`, {
|
|
method: 'GET',
|
|
})
|
|
const data = await response.json()
|
|
const engineStatuses: EngineStatus[] = []
|
|
data.data.forEach((engineStatus: EngineStatus) => {
|
|
engineStatuses.push(engineStatus)
|
|
})
|
|
return engineStatuses
|
|
}, [host])
|
|
|
|
// TODO: put in to cortexso-node?
|
|
const getEngineStatus = useCallback(
|
|
async (engine: LlmEngine): Promise<EngineStatus | undefined> => {
|
|
try {
|
|
const response = await fetch(`${host}/engines/${engine}`, {
|
|
method: 'GET',
|
|
})
|
|
const data = (await response.json()) as EngineStatus
|
|
return data
|
|
} catch (err) {
|
|
console.error(err)
|
|
}
|
|
},
|
|
[host]
|
|
)
|
|
|
|
// TODO: put in to cortexso-node?
|
|
const initializeEngine = useCallback(
|
|
async (engine: LlmEngine) => {
|
|
try {
|
|
await fetch(`${host}/engines/${engine}/init/`, {
|
|
method: 'POST',
|
|
headers: {
|
|
accept: 'application/json',
|
|
},
|
|
})
|
|
} catch (err) {
|
|
console.error(err)
|
|
}
|
|
},
|
|
[host]
|
|
)
|
|
|
|
const fetchAssistants = useCallback(async () => {
|
|
const assistants: Assistant[] = []
|
|
const response = await cortex.beta.assistants.list()
|
|
response.data.forEach((assistant) => {
|
|
assistants.push(assistant)
|
|
})
|
|
return assistants
|
|
}, [cortex.beta.assistants])
|
|
|
|
const fetchThreads = useCallback(async () => {
|
|
const threads: Thread[] = []
|
|
for await (const thread of cortex.beta.threads.list()) {
|
|
// @ts-expect-error each thread must have associated assistants
|
|
const assistants = thread['assistants'] as Assistant[]
|
|
if (!assistants || assistants.length === 0) continue
|
|
|
|
// @ts-expect-error each thread must have a title, else default to 'New Thread'
|
|
const title: string = thread['title'] ?? 'New Thread'
|
|
|
|
threads.push({
|
|
...thread,
|
|
title: title,
|
|
assistants: assistants,
|
|
})
|
|
}
|
|
return threads
|
|
}, [cortex.beta.threads])
|
|
|
|
const fetchModels = useCallback(async () => {
|
|
const models: Model[] = []
|
|
for await (const model of cortex.models.list()) {
|
|
// @ts-expect-error model should not be empty
|
|
const modelId = model.model
|
|
if (!modelId || modelId.length === 0) {
|
|
console.debug('Model id is empty, skipping', model)
|
|
continue
|
|
}
|
|
models.push({
|
|
...model,
|
|
model: modelId,
|
|
// @ts-expect-error each model must have associated files
|
|
files: model['files'],
|
|
})
|
|
}
|
|
return models
|
|
}, [cortex.models])
|
|
|
|
const fetchMessages = useCallback(
|
|
async (threadId: string) => {
|
|
try {
|
|
const messages: Message[] = []
|
|
const response = await cortex.beta.threads.messages.list(threadId)
|
|
response.data.forEach((message) => {
|
|
messages.push(message)
|
|
})
|
|
return messages
|
|
} catch (error) {
|
|
return []
|
|
}
|
|
},
|
|
[cortex.beta.threads.messages]
|
|
)
|
|
|
|
const startModel = useCallback(
|
|
async (modelId: string, options?: Record<string, unknown>) => {
|
|
await cortex.models.start(modelId, options ?? {})
|
|
},
|
|
[cortex.models]
|
|
)
|
|
|
|
const stopModel = useCallback(
|
|
async (modelId: string, options?: Record<string, unknown>) => {
|
|
await cortex.models.stop(modelId, options ?? {})
|
|
},
|
|
[cortex.models]
|
|
)
|
|
|
|
const chatCompletionNonStreaming = useCallback(
|
|
async (
|
|
chatCompletionCreateParams: ChatCompletionCreateParamsNonStreaming,
|
|
options?: Record<string, unknown>
|
|
// @ts-expect-error incompatible types
|
|
) => cortex.chat.completions.create(chatCompletionCreateParams, options),
|
|
[cortex.chat.completions]
|
|
)
|
|
|
|
const chatCompletionStreaming = useCallback(
|
|
async (
|
|
chatCompletionCreateParams: ChatCompletionCreateParamsStreaming,
|
|
options?: Record<string, unknown>
|
|
// @ts-expect-error incompatible types
|
|
) => cortex.chat.completions.create(chatCompletionCreateParams, options),
|
|
[cortex.chat.completions]
|
|
)
|
|
|
|
const deleteModel = useCallback(
|
|
async (modelId: string) => {
|
|
await cortex.models.del(modelId)
|
|
},
|
|
[cortex.models]
|
|
)
|
|
|
|
const cleanThread = useCallback(
|
|
async (threadId: string) => cortex.beta.threads.clean(threadId),
|
|
[cortex.beta.threads]
|
|
)
|
|
|
|
const deleteThread = useCallback(
|
|
async (threadId: string) => {
|
|
await cortex.beta.threads.del(threadId)
|
|
},
|
|
[cortex.beta.threads]
|
|
)
|
|
|
|
const updateThread = useCallback(
|
|
async (thread: Thread) => {
|
|
const result = await cortex.beta.threads.update(thread.id, thread)
|
|
console.debug(
|
|
`Update thread ${thread.id}, result: ${JSON.stringify(result, null, 2)}`
|
|
)
|
|
},
|
|
[cortex.beta.threads]
|
|
)
|
|
|
|
const deleteMessage = useCallback(
|
|
async (params: MessageDeleteMutationVariables) => {
|
|
const { threadId, messageId } = params
|
|
return cortex.beta.threads.messages.del(threadId, messageId)
|
|
},
|
|
[cortex.beta.threads]
|
|
)
|
|
|
|
const createMessage = useCallback(
|
|
async (params: MessageCreateMutationVariables) => {
|
|
const { threadId, createMessageParams } = params
|
|
return cortex.beta.threads.messages.create(threadId, createMessageParams)
|
|
},
|
|
[cortex.beta.threads]
|
|
)
|
|
|
|
const updateMessage = useCallback(
|
|
async (params: MessageUpdateMutationVariables) => {
|
|
const { threadId, messageId, data } = params
|
|
return cortex.beta.threads.messages.update(threadId, messageId, data)
|
|
},
|
|
[cortex.beta.threads]
|
|
)
|
|
|
|
const createThread = useCallback(
|
|
async (assistant: Assistant) => {
|
|
const createThreadResponse = await cortex.beta.threads.create({
|
|
// @ts-expect-error customize so that each thread will have an assistant
|
|
assistants: [assistant],
|
|
})
|
|
const thread: Thread = {
|
|
...createThreadResponse,
|
|
// @ts-expect-error each thread will have a title, else default to 'New Thread'
|
|
title: createThreadResponse.title ?? 'New Thread',
|
|
assistants: [assistant],
|
|
}
|
|
return thread
|
|
},
|
|
[cortex.beta.threads]
|
|
)
|
|
|
|
const updateModel = useCallback(
|
|
async (modelId: string, options: Record<string, unknown>) => {
|
|
try {
|
|
return await fetch(`${host}/models/${modelId}`, {
|
|
method: 'PATCH',
|
|
headers: {
|
|
'accept': 'application/json',
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(options),
|
|
})
|
|
} catch (err) {
|
|
console.error(err)
|
|
}
|
|
},
|
|
[host]
|
|
)
|
|
|
|
// TODO: put this into cortexso-node
|
|
const downloadModel = useCallback(
|
|
async (modelId: string, fileName?: string, persistedModelId?: string) => {
|
|
try {
|
|
return await fetch(`${host}/models/${modelId}/pull`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'accept': 'application/json',
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
fileName: fileName,
|
|
persistedModelId: persistedModelId,
|
|
}),
|
|
})
|
|
} catch (err) {
|
|
console.error(err)
|
|
}
|
|
},
|
|
[host]
|
|
)
|
|
|
|
const abortDownload = useCallback(
|
|
async (downloadId: string) => {
|
|
try {
|
|
return await fetch(`${host}/models/${downloadId}/pull`, {
|
|
method: 'DELETE',
|
|
headers: {
|
|
'accept': 'application/json',
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
'Content-Type': 'application/json',
|
|
},
|
|
})
|
|
} catch (err) {
|
|
console.error(err)
|
|
}
|
|
},
|
|
[host]
|
|
)
|
|
|
|
const createAssistant = useCallback(
|
|
async (createParams: AssistantCreateParams) =>
|
|
cortex.beta.assistants.create(createParams),
|
|
[cortex.beta.assistants]
|
|
)
|
|
|
|
const updateAssistant = useCallback(
|
|
async (assistantId: string, updateParams: AssistantUpdateParams) =>
|
|
cortex.beta.assistants.update(assistantId, updateParams),
|
|
[cortex.beta.assistants]
|
|
)
|
|
|
|
// TODO: add this to cortex-node
|
|
const registerEngineConfig = useCallback(
|
|
async (variables: UpdateConfigMutationVariables) => {
|
|
try {
|
|
const { engine, config } = variables
|
|
await fetch(`${host}/engines/${engine}`, {
|
|
method: 'PATCH',
|
|
headers: {
|
|
'accept': 'application/json',
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(config),
|
|
})
|
|
} catch (err) {
|
|
console.error(err)
|
|
}
|
|
},
|
|
[host]
|
|
)
|
|
|
|
// add this to cortex-node?
|
|
const createModel = useCallback(
|
|
(model: Model) =>
|
|
fetch(`${host}/models`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'accept': 'application/json',
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(model),
|
|
}),
|
|
[host]
|
|
)
|
|
|
|
return {
|
|
fetchAssistants,
|
|
fetchThreads,
|
|
fetchModels,
|
|
fetchMessages,
|
|
startModel,
|
|
stopModel,
|
|
chatCompletionStreaming,
|
|
deleteModel,
|
|
deleteThread,
|
|
deleteMessage,
|
|
cleanThread,
|
|
updateThread,
|
|
createMessage,
|
|
updateMessage,
|
|
createThread,
|
|
downloadModel,
|
|
abortDownload,
|
|
createAssistant,
|
|
updateAssistant,
|
|
updateModel,
|
|
chatCompletionNonStreaming,
|
|
registerEngineConfig,
|
|
createModel,
|
|
getEngineStatus,
|
|
initializeEngine,
|
|
getEngineStatuses,
|
|
}
|
|
}
|
|
|
|
export default useCortex
|