Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: local engine management #4334

Merged
merged 23 commits into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2915af5
feat: local engine management
urmauur Dec 22, 2024
cde2508
chore: move remote engine into engine page instead extension page
urmauur Dec 23, 2024
69ebe32
chore: set default engine from extension
urmauur Dec 23, 2024
c9b9de7
chore: update endpoint update engine
urmauur Dec 23, 2024
b0626c0
chore: update event onEngineUpdate
urmauur Dec 23, 2024
e1ce9d8
chore: filter out engine download
louis-menlo Dec 24, 2024
3f2f622
chore: update version env
urmauur Dec 26, 2024
3f91a08
chore: select default engine variant base on user device specs
louis-menlo Dec 26, 2024
46355d9
chore: symlink engine variants
louis-menlo Dec 26, 2024
52af575
chore: rolldown.config in mjs format
louis-menlo Dec 27, 2024
1cdedc5
chore: binary codesign
louis-menlo Dec 27, 2024
8b5bd89
fix: download state in footer bar and variant status
louis-menlo Dec 27, 2024
b4eab38
chore: update yarn.lock
louis-menlo Dec 29, 2024
196a256
fix: rimraf failure
louis-menlo Dec 29, 2024
0ccbfe5
fix: setup-node@v3 for built-in cache
louis-menlo Dec 29, 2024
8e9cef8
fix: cov pipeline
louis-menlo Dec 29, 2024
4f9d167
fix: build syntax
louis-menlo Dec 29, 2024
73f45f8
chore: fix build step
louis-menlo Dec 29, 2024
aea5bee
fix: create engines folder on launch
louis-menlo Dec 29, 2024
47b0a1f
chore: update ui delete engine variant with modal confirmation
urmauur Dec 29, 2024
871f298
chore: fix linter
urmauur Dec 29, 2024
8115862
chore: add installing progress for Local Engine download
louis-menlo Dec 30, 2024
aa47be4
chore: wording
louis-menlo Dec 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/jan-electron-linter-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ jobs:
- uses: actions/checkout@v3
with:
ref: ${{ github.base_ref }}
- name: Use Node.js v20.9.0
- name: Use Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: v20.9.0
node-version: 20

- name: Install dependencies
run: |
yarn
make build-joi
yarn build:core
yarn build:joi
yarn

- name: Run test coverage
run: yarn test:coverage
Expand Down Expand Up @@ -187,7 +187,7 @@ jobs:
fetch-depth: 0

- name: Installing node
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: 20

Expand Down
1 change: 1 addition & 0 deletions core/src/browser/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
Model = 'model',
SystemMonitoring = 'systemMonitoring',
HuggingFace = 'huggingFace',
Engine = 'engine',
}

export interface ExtensionType {
Expand Down Expand Up @@ -102,7 +103,7 @@
* @property {Array} platform
*/
compatibility(): Compatibility | undefined {
return undefined

Check warning on line 106 in core/src/browser/extension.ts

View workflow job for this annotation

GitHub Actions / coverage-check

106 line is not covered with tests
}

/**
Expand All @@ -110,8 +111,8 @@
* @param models
*/
async registerModels(models: Model[]): Promise<void> {
for (const model of models) {
ModelManager.instance().register(model)

Check warning on line 115 in core/src/browser/extension.ts

View workflow job for this annotation

GitHub Actions / coverage-check

114-115 lines are not covered with tests
}
}

Expand All @@ -122,8 +123,8 @@
*/
async registerSettings(settings: SettingComponentProps[]): Promise<void> {
if (!this.name) {
console.error('Extension name is not defined')
return

Check warning on line 127 in core/src/browser/extension.ts

View workflow job for this annotation

GitHub Actions / coverage-check

126-127 lines are not covered with tests
}

const extensionSettingFolderPath = await joinPath([
Expand All @@ -141,18 +142,18 @@

// Persists new settings
if (await fs.existsSync(settingFilePath)) {
const oldSettings = JSON.parse(await fs.readFileSync(settingFilePath, 'utf-8'))
settings.forEach((setting) => {

Check warning on line 146 in core/src/browser/extension.ts

View workflow job for this annotation

GitHub Actions / coverage-check

145-146 lines are not covered with tests
// Keep setting value
if (setting.controllerProps && Array.isArray(oldSettings))
setting.controllerProps.value = oldSettings.find(
(e: any) => e.key === setting.key

Check warning on line 150 in core/src/browser/extension.ts

View workflow job for this annotation

GitHub Actions / coverage-check

148-150 lines are not covered with tests
)?.controllerProps?.value
})
}
await fs.writeFileSync(settingFilePath, JSON.stringify(settings, null, 2))
} catch (err) {
console.error(err)

Check warning on line 156 in core/src/browser/extension.ts

View workflow job for this annotation

GitHub Actions / coverage-check

156 line is not covered with tests
}
}

Expand Down Expand Up @@ -196,23 +197,23 @@
* @returns
*/
async getSettings(): Promise<SettingComponentProps[]> {
if (!this.name) return []

Check warning on line 200 in core/src/browser/extension.ts

View workflow job for this annotation

GitHub Actions / coverage-check

200 line is not covered with tests

const settingPath = await joinPath([

Check warning on line 202 in core/src/browser/extension.ts

View workflow job for this annotation

GitHub Actions / coverage-check

202 line is not covered with tests
await getJanDataFolderPath(),
this.settingFolderName,
this.name,
this.settingFileName,
])

try {
if (!(await fs.existsSync(settingPath))) return []
const content = await fs.readFileSync(settingPath, 'utf-8')
const settings: SettingComponentProps[] = JSON.parse(content)
return settings

Check warning on line 213 in core/src/browser/extension.ts

View workflow job for this annotation

GitHub Actions / coverage-check

209-213 lines are not covered with tests
} catch (err) {
console.warn(err)
return []

Check warning on line 216 in core/src/browser/extension.ts

View workflow job for this annotation

GitHub Actions / coverage-check

215-216 lines are not covered with tests
}
}

Expand Down
91 changes: 91 additions & 0 deletions core/src/browser/extensions/enginesManagement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import {
InferenceEngine,
Engines,
EngineVariant,
EngineReleased,
DefaultEngineVariant,
} from '../../types'
import { BaseExtension, ExtensionTypeEnum } from '../extension'

/**
* Engine management extension. Persists and retrieves engine management.
* @abstract
* @extends BaseExtension
*/
export abstract class EngineManagementExtension extends BaseExtension {
type(): ExtensionTypeEnum | undefined {
return ExtensionTypeEnum.Engine
}

/**
* @returns A Promise that resolves to an object of list engines.
*/
abstract getEngines(): Promise<Engines>

/**
* @param name - Inference engine name.
* @returns A Promise that resolves to an array of installed engine.
*/
abstract getInstalledEngines(name: InferenceEngine): Promise<EngineVariant[]>

/**
* @param name - Inference engine name.
* @param version - Version of the engine.
* @param platform - Optional to sort by operating system. macOS, linux, windows.
* @returns A Promise that resolves to an array of latest released engine by version.
*/
abstract getReleasedEnginesByVersion(
name: InferenceEngine,
version: string,
platform?: string
): Promise<EngineReleased[]>

/**
* @param name - Inference engine name.
* @param platform - Optional to sort by operating system. macOS, linux, windows.
* @returns A Promise that resolves to an array of latest released engine.
*/
abstract getLatestReleasedEngine(
name: InferenceEngine,
platform?: string
): Promise<EngineReleased[]>

/**
* @param name - Inference engine name.
* @returns A Promise that resolves to intall of engine.
*/
abstract installEngine(
name: InferenceEngine,
engineConfig: { variant: string; version?: string }
): Promise<{ messages: string }>

/**
* @param name - Inference engine name.
* @returns A Promise that resolves to unintall of engine.
*/
abstract uninstallEngine(
name: InferenceEngine,
engineConfig: { variant: string; version: string }
): Promise<{ messages: string }>

/**
* @param name - Inference engine name.
* @returns A Promise that resolves to an object of default engine.
*/
abstract getDefaultEngineVariant(name: InferenceEngine): Promise<DefaultEngineVariant>

/**
* @body variant - string
* @body version - string
* @returns A Promise that resolves to set default engine.
*/
abstract setDefaultEngineVariant(
name: InferenceEngine,
engineConfig: { variant: string; version: string }
): Promise<{ messages: string }>

/**
* @returns A Promise that resolves to update engine.
*/
abstract updateEngine(name: InferenceEngine): Promise<{ messages: string }>
}
5 changes: 5 additions & 0 deletions core/src/browser/extensions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,8 @@ export { ModelExtension } from './model'
* Base AI Engines.
*/
export * from './engines'

/**
* Engines Management
*/
export * from './enginesManagement'
28 changes: 28 additions & 0 deletions core/src/types/engine/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { InferenceEngine } from '../../types'

export type Engines = {
[key in InferenceEngine]: EngineVariant[]
}

export type EngineVariant = {
engine: InferenceEngine
name: string
version: string
}

export type DefaultEngineVariant = {
engine: InferenceEngine
variant: string
version: string
}

export type EngineReleased = {
created_at: string
download_count: number
name: string
size: number
}

export enum EngineEvent {
OnEngineUpdate = 'OnEngineUpdate',
}
1 change: 1 addition & 0 deletions core/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from './huggingface'
export * from './miscellaneous'
export * from './api'
export * from './setting'
export * from './engine'
5 changes: 5 additions & 0 deletions extensions/engine-management-extension/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
}
47 changes: 47 additions & 0 deletions extensions/engine-management-extension/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "@janhq/engine-management-extension",
"productName": "Engine Management",
"version": "1.0.0",
"description": "Extension for managing engines and their configurations",
"main": "dist/index.js",
"node": "dist/node/index.cjs.js",
"author": "Jan <[email protected]>",
"license": "MIT",
"scripts": {
"test": "jest",
"build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob || true && yarn build && ../../.github/scripts/auto-sign.sh && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
},
"devDependencies": {
"@rollup/plugin-replace": "^6.0.2",
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"rolldown": "^1.0.0-beta.1",
"ts-loader": "^9.5.0",
"typescript": "^5.3.3",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4"
},
"dependencies": {
"@janhq/core": "../../core/package.tgz",
"cpu-instructions": "^0.0.13",
"ky": "^1.7.2",
"p-queue": "^8.0.1"
},
"bundledDependencies": [
"cpu-instructions",
"@janhq/core"
],
"engines": {
"node": ">=18.0.0"
},
"files": [
"dist/*",
"package.json",
"README.md"
]
}
45 changes: 45 additions & 0 deletions extensions/engine-management-extension/rolldown.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { defineConfig } from 'rolldown'
import replace from '@rollup/plugin-replace'
import pkgJson from './package.json' with { type: 'json' }

export default defineConfig([
{
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
plugins: [
replace({
NODE: JSON.stringify(`${pkgJson.name}/${pkgJson.node}`),
API_URL: JSON.stringify('http://127.0.0.1:39291'),
SOCKET_URL: JSON.stringify('ws://127.0.0.1:39291'),
CORTEX_ENGINE_VERSION: JSON.stringify('v0.1.42'),
}),
],
},
{
input: 'src/node/index.ts',
external: ['@janhq/core/node'],
output: {
format: 'cjs',
file: 'dist/node/index.cjs.js',
},
plugins: [
replace({
CORTEX_ENGINE_VERSION: JSON.stringify('v0.1.42'),
}),
],
},
{
input: 'src/node/cpuInfo.ts',
output: {
format: 'cjs',
file: 'dist/node/cpuInfo.js',
},
external: ['cpu-instructions'],
resolve: {
extensions: ['.ts', '.js', '.svg'],
},
},
])
16 changes: 16 additions & 0 deletions extensions/engine-management-extension/src/@types/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export {}
declare global {
declare const API_URL: string
declare const CORTEX_ENGINE_VERSION: string
declare const SOCKET_URL: string
declare const NODE: string

interface Core {
api: APIFunctions
events: EventEmitter
}
interface Window {
core?: Core | undefined
electronAPI?: any | undefined
}
}
10 changes: 10 additions & 0 deletions extensions/engine-management-extension/src/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Custom Engine Error
*/
export class EngineError extends Error {
message: string
constructor(message: string) {
super()
this.message = message
}
}
Loading
Loading