Skip to content

Commit

Permalink
fix: set cortex data folder path when starting jan (janhq#3252)
Browse files Browse the repository at this point in the history
* fix: set cortex data folder path when starting jan

* fix: change port to 1338

* fix: add migration in advanced setting

* update

* update new cortex

* feat: add import model error handler

Signed-off-by: James <[email protected]>

---------

Signed-off-by: James <[email protected]>
  • Loading branch information
namchuai authored Aug 6, 2024
1 parent 224ca3f commit 91c77ed
Show file tree
Hide file tree
Showing 14 changed files with 328 additions and 288 deletions.
1 change: 1 addition & 0 deletions core/src/types/file/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,5 @@ export interface DownloadStateEvent {
export enum DownloadType2 {
Model = 'model',
Miscelanous = 'miscelanous',
Engine = 'engine',
}
64 changes: 35 additions & 29 deletions electron/handlers/native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@ import {
} from '@janhq/core/node'
import { menu } from '../utils/menu'
import { join } from 'path'
import { getJanDataFolderPath } from './../utils/path'
import { getAppConfigurations, getJanDataFolderPath } from './../utils/path'
import {
readdirSync,
writeFileSync,
readFileSync,
existsSync,
mkdirSync
mkdirSync,
} from 'fs'
import { dump } from 'js-yaml'
import os from 'os'

const isMac = process.platform === 'darwin'

Expand Down Expand Up @@ -178,7 +177,7 @@ export function handleAppIPCs() {
}
)

ipcMain.handle(NativeRoute.showOpenMenu, function (e, args) {
ipcMain.handle(NativeRoute.showOpenMenu, function (_e, args) {
if (!isMac && windowManager.mainWindow) {
menu.popup({
window: windowManager.mainWindow,
Expand Down Expand Up @@ -209,10 +208,11 @@ export function handleAppIPCs() {
})

ipcMain.handle(NativeRoute.openAppLog, async (_event): Promise<void> => {
const cortexHomeDir = join(os.homedir(), 'cortex')
const configuration = getAppConfigurations()
const dataFolder = configuration.data_folder

try {
const errorMessage = await shell.openPath(join(cortexHomeDir))
const errorMessage = await shell.openPath(join(dataFolder))
if (errorMessage) {
console.error(`An error occurred: ${errorMessage}`)
} else {
Expand All @@ -227,21 +227,19 @@ export function handleAppIPCs() {
const janModelFolderPath = join(getJanDataFolderPath(), 'models')
const allModelFolders = readdirSync(janModelFolderPath)

const cortexHomeDir = join(os.homedir(), 'cortex')
const cortexModelFolderPath = join(cortexHomeDir, 'models')
const configration = getAppConfigurations()
const destinationFolderPath = join(configration.data_folder, 'models')

if(!existsSync(cortexModelFolderPath))
mkdirSync(cortexModelFolderPath)
console.log('cortexModelFolderPath', cortexModelFolderPath)
if (!existsSync(destinationFolderPath)) mkdirSync(destinationFolderPath)
console.log('destinationFolderPath', destinationFolderPath)
const reflect = require('@alumna/reflect')

for (const modelName of allModelFolders) {
const modelFolderPath = join(janModelFolderPath, modelName)
try {

const filesInModelFolder = readdirSync(modelFolderPath)

const destinationPath = join(cortexModelFolderPath, modelName)
const destinationPath = join(destinationFolderPath, modelName)

const modelJsonFullPath = join(
janModelFolderPath,
Expand All @@ -253,23 +251,29 @@ export function handleAppIPCs() {
const fileNames: string[] = model.sources.map((x: any) => x.filename)
let files: string[] = []

if(filesInModelFolder.length > 1) {
// prepend fileNames with cortexModelFolderPath
if (filesInModelFolder.length > 1) {
// prepend fileNames with model folder path
files = fileNames.map((x: string) =>
join(cortexModelFolderPath, model.id, x)
join(destinationFolderPath, model.id, x)
)
} else if(model.sources.length && !/^(http|https):\/\/[^/]+\/.*/.test(model.sources[0].url)) {
} else if (
model.sources.length &&
!/^(http|https):\/\/[^/]+\/.*/.test(model.sources[0].url)
) {
// Symlink case
files = [ model.sources[0].url ]
} else continue;
files = [model.sources[0].url]
} else continue

// create folder if not exist
// only for local model files
if (!existsSync(destinationPath) && filesInModelFolder.length > 1) {
mkdirSync(destinationPath, { recursive: true })
}

const engine = (model.engine === 'nitro' || model.engine === 'cortex') ? 'cortex.llamacpp' : (model.engine ?? 'cortex.llamacpp')
const engine =
model.engine === 'nitro' || model.engine === 'cortex'
? 'cortex.llamacpp'
: (model.engine ?? 'cortex.llamacpp')

const updatedModelFormat = {
id: model.id,
Expand All @@ -296,7 +300,7 @@ export function handleAppIPCs() {
max_tokens: model.parameters?.max_tokens ?? 2048,
stream: model.parameters?.stream ?? true,
}
if(filesInModelFolder.length > 1 ) {
if (filesInModelFolder.length > 1) {
const { err } = await reflect({
src: modelFolderPath,
dest: destinationPath,
Expand All @@ -307,14 +311,14 @@ export function handleAppIPCs() {
errorOnExist: false,
})

if (err) {
console.error(err);
continue;
if (err) {
console.error(err)
continue
}
}
// create the model.yml file
const modelYamlData = dump(updatedModelFormat)
const modelYamlPath = join(cortexModelFolderPath, `${modelName}.yaml`)
const modelYamlPath = join(destinationFolderPath, `${modelName}.yaml`)

writeFileSync(modelYamlPath, modelYamlData)
} catch (err) {
Expand Down Expand Up @@ -354,11 +358,11 @@ export function handleAppIPCs() {
'messages.jsonl'
)

if(!existsSync(messageFullPath)) continue;
if (!existsSync(messageFullPath)) continue
const lines = readFileSync(messageFullPath, 'utf-8')
.toString()
.split('\n')
.filter((line: any) => line !== '')
.toString()
.split('\n')
.filter((line: any) => line !== '')
for (const line of lines) {
messages.push(JSON.parse(line))
}
Expand All @@ -379,8 +383,10 @@ export function handleAppIPCs() {
const janModelsFolderPath = join(getJanDataFolderPath(), 'models')

if (!existsSync(janModelsFolderPath)) {
console.debug('No local models found')
return false
}

// get children of thread folder
const allModelsFolders = readdirSync(janModelsFolderPath)
let hasLocalModels = false
Expand Down
29 changes: 24 additions & 5 deletions electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { handleAppIPCs } from './handlers/native'
* Utils
**/
import { setupMenu } from './utils/menu'
import { createUserSpace } from './utils/path'
import { createUserSpace, getAppConfigurations } from './utils/path'
import { migrate } from './utils/migration'
import { cleanUpAndQuit } from './utils/clean'
import { setupCore } from './utils/setup'
Expand Down Expand Up @@ -58,12 +58,31 @@ Object.assign(console, log.functions)

let cortexService: ChildProcess | undefined = undefined

const cortexJsPort = 1338
const cortexCppPort = 3940
const host = '127.0.0.1'

app
.whenReady()
.then(() => killProcessesOnPort(3929))
.then(() => killProcessesOnPort(1337))
.then(() => killProcessesOnPort(cortexCppPort))
.then(() => killProcessesOnPort(cortexJsPort))
.then(() => {
const command = `${cortexPath} -a 127.0.0.1 -p 1337`
const appConfiguration = getAppConfigurations()
const janDataFolder = appConfiguration.data_folder

const cortexParams: Record<string, string> = {
'-n': 'jan',
'-a': host,
'-p': cortexJsPort.toString(),
'-ep': cortexCppPort.toString(),
'--dataFolder': janDataFolder,
}

// add cortex parameters to the command
const command = Object.entries(cortexParams).reduce(
(acc, [key, value]) => `${acc} ${key} ${value}`,
`${cortexPath}`
)

log.info('Starting cortex with command:', command)
// init cortex
Expand Down Expand Up @@ -154,7 +173,7 @@ async function stopCortexService() {
async function stopApiServer() {
// this function is not meant to be success. It will throw an error.
try {
await fetch('http://localhost:1337/v1/system', {
await fetch(`http://${host}:${cortexJsPort}/v1/system`, {
method: 'DELETE',
})
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion electron/resources/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.5.0-27
0.5.0-29
9 changes: 7 additions & 2 deletions web/containers/Layout/BottomPanel/DownloadingStatus/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,21 @@ const DownloadStatus: React.FC = () => {
? ((totalTransfferedSize / totalDownloadSize) * 100).toFixed(2)
: 0

const downloadTitle = `Downloading ${downloadStates
.map((state) => state.type)
.join(', ')
.trim()}`

return (
<Fragment>
{Object.values(downloadStates)?.length > 0 && (
<Modal
title="Downloading model"
title={downloadTitle}
trigger={
<div className="flex cursor-pointer items-center gap-2">
<Button size="small" theme="ghost">
<span className="font-medium">
Downloading model{' '}
{downloadTitle}{' '}
{Object.values(downloadStates).length > 1 &&
`1/${Object.values(downloadStates).length}`}
</span>
Expand Down
33 changes: 33 additions & 0 deletions web/containers/Layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import TopPanel from '@/containers/Layout/TopPanel'

import { getImportModelStageAtom } from '@/hooks/useImportModel'

import useMigratingData from '@/hooks/useMigratingData'

import DownloadLocalModelModal from '@/screens/HubScreen2/components/DownloadLocalModelModal'
import InferenceErrorModal from '@/screens/HubScreen2/components/InferenceErrorModal'
import SetUpApiKeyModal from '@/screens/HubScreen2/components/SetUpApiKeyModal'
Expand All @@ -33,24 +35,54 @@ import LoadingModal from '../LoadingModal'

import MainViewContainer from '../MainViewContainer'

import ModalMigrations, {
showMigrationModalAtom,
} from '../Providers/ModalMigrations'
import WaitingForCortexModal from '../WaitingCortexModal'

import InstallingExtensionModal from './BottomPanel/InstallingExtension/InstallingExtensionModal'

import { MainViewState, mainViewStateAtom } from '@/helpers/atoms/App.atom'
import { didShowMigrationWarningAtom } from '@/helpers/atoms/AppConfig.atom'
import { reduceTransparentAtom } from '@/helpers/atoms/Setting.atom'

const BaseLayout = () => {
const didShowMigrationWarning = useAtomValue(didShowMigrationWarningAtom)
const setShowMigrationModal = useSetAtom(showMigrationModalAtom)
const setMainViewState = useSetAtom(mainViewStateAtom)
const importModelStage = useAtomValue(getImportModelStageAtom)
const reduceTransparent = useAtomValue(reduceTransparentAtom)
const { getJanThreadsAndMessages, getJanLocalModels } = useMigratingData()

useEffect(() => {
if (localStorage.getItem(SUCCESS_SET_NEW_DESTINATION) === 'true') {
setMainViewState(MainViewState.Settings)
}
}, [setMainViewState])

useEffect(() => {
if (didShowMigrationWarning) return

const isUserHaveData = async (): Promise<boolean> => {
const threadAndMessageData = await getJanThreadsAndMessages()
const isUserHaveAnyModel = await getJanLocalModels()
return threadAndMessageData.threads.length > 0 || isUserHaveAnyModel
}

isUserHaveData()
.then((isUserHaveData) => {
if (isUserHaveData === true) {
setShowMigrationModal(true)
}
})
.catch((e) => console.error('Error checking user data', e))
}, [
didShowMigrationWarning,
getJanThreadsAndMessages,
getJanLocalModels,
setShowMigrationModal,
])

return (
<div
className={twMerge(
Expand Down Expand Up @@ -92,6 +124,7 @@ const BaseLayout = () => {
<ChooseWhatToImportModal />
<InstallingExtensionModal />
<HuggingFaceRepoDetailModal />
<ModalMigrations />
</div>
<BottomPanel />
</div>
Expand Down
Loading

0 comments on commit 91c77ed

Please sign in to comment.