-
Notifications
You must be signed in to change notification settings - Fork 181
[janhq/jan#1635] feat: decouple nitro engine into a library #367
Changes from all commits
7758eda
ffcd05d
81ee8f3
85e3189
55c540d
8ba9202
08657a1
6f625d9
8c742cf
5f46220
9e2dd61
33293ec
d703f74
60063bd
e8e7752
f7ca9c8
152f4b2
c81ff90
75d8907
029a142
869470b
fb7cb5c
c60e4f4
6a42350
3697335
9761294
f026da5
1133759
506d277
b4aa567
ae1d4dd
80dcc55
7c75c7b
0516440
e427816
7b2c846
ff2cf08
b2b749d
91e2c24
049ef1d
f5bc098
cdbd4a1
b6727a0
d10bbbb
142a60d
21e3026
c6a2656
9bd5af3
8a309a3
1d79084
81246f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| .vscode | ||
| .env | ||
|
|
||
| # Jan inference | ||
| .yarn | ||
| node_modules | ||
| *.tgz | ||
| yarn.lock | ||
| dist | ||
| build | ||
| .DS_Store | ||
| package-lock.json | ||
|
|
||
| *.log | ||
|
|
||
| # Nitro binary directory | ||
| bin/ | ||
| # Locally downloaded model for testing | ||
| test/test_assets/*.gguf |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| scripts-prepend-node-path=true | ||
| engine-strict=true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| nodeLinker: node-modules |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # Makefile for Nitro-node - Build and Clean | ||
|
|
||
| # Default target, build all | ||
| .PHONY: all | ||
|
|
||
| all: publish | ||
|
|
||
| # Installs yarn dependencies | ||
| #install: build-core | ||
| install: | ||
| ifeq ($(OS),Windows_NT) | ||
| yarn config set network-timeout 300000 | ||
| endif | ||
| yarn install | ||
|
|
||
| # Build | ||
| build: install | ||
| yarn run build | ||
|
|
||
| # Download Nitro | ||
| download-nitro: install | ||
| yarn run downloadnitro | ||
|
|
||
| test-ci: install | ||
| yarn test | ||
|
|
||
| # Note, this make target is just for testing on *NIX systems | ||
| test: install | ||
| @test -e test/test_assets/*.gguf && echo "test/test_assets/*.gguf is already downloaded" || (mkdir -p test/test_assets && cd test/test_assets/ && curl -JLO "https://huggingface.co/TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF/resolve/main/tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf") | ||
| yarn test | ||
|
|
||
| # Builds and pack | ||
| pack: build | ||
| yarn run build:publish | ||
|
|
||
| # Test that installation will also download nitro binaries | ||
| test-e2e-installation: pack | ||
| ifeq ($(OS),Windows_NT) | ||
| $$env:NITRO_NODE_VERSION=(npm version --json | jq '.["@janhq/nitro-node"]' | foreach {$$_.replace('"','')}) $$env:NITRO_NODE_PKG=(Resolve-Path -Path "janhq-nitro-node$$NITRO_NODE_VERSION.tgz") node ..\.github\scripts\e2e-test-install-nitro-node.js | ||
| else | ||
| NITRO_NODE_VERSION=$$(npm version --json | jq '.["@janhq/nitro-node"]' | tr -d '"') NITRO_NODE_PKG=$$(realpath "janhq-nitro-node-$${NITRO_NODE_VERSION}.tgz") node ../.github/scripts/e2e-test-install-nitro-node.js | ||
| endif | ||
|
|
||
| clean: | ||
| ifeq ($(OS),Windows_NT) | ||
| powershell -Command "Remove-Item -Recurse -Force -Path *.tgz, .yarn, yarn.lock, package-lock.json, bin, dist" | ||
| powershell -Command "Get-ChildItem -Path . -Include node_modules -Recurse -Directory | Remove-Item -Recurse -Force" | ||
| else | ||
| rm -rf *.tgz .yarn yarn.lock package-lock.json bin dist | ||
| find . -name "node_modules" -type d -prune -exec rm -rf '{}' + | ||
| endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # NodeJS wrapper for Nitro | ||
|
|
||
| **TODO** Documenting on usage |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import type { JestConfigWithTsJest } from "ts-jest"; | ||
|
|
||
| const jestConfig: JestConfigWithTsJest = { | ||
| preset: "ts-jest", | ||
| testEnvironment: "node", | ||
| transformIgnorePatterns: ["/node_modules/"], | ||
| globals: { | ||
| RELEASE_URL_PREFIX: "https://api.github.com/repos/janhq/nitro/releases/", | ||
| TAGGED_RELEASE_URL_PREFIX: | ||
| "https://api.github.com/repos/janhq/nitro/releases/tags", | ||
| }, | ||
| }; | ||
|
|
||
| export default jestConfig; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| { | ||
| "name": "@janhq/nitro-node", | ||
| "version": "1.0.0", | ||
| "description": "This NodeJS library is a wrapper for Nitro, a lightweight (3mb) inference engine written in C++. See nitro.jan.ai", | ||
| "main": "./dist/index", | ||
| "module": "./dist/index.esm.js", | ||
| "types": "./dist/types/index", | ||
| "author": "Jan <service@jan.ai>", | ||
| "license": "AGPL-3.0", | ||
| "scripts": { | ||
| "test": "jest --verbose --detectOpenHandles", | ||
| "build": "tsc --module commonjs && rollup -c rollup.config.ts", | ||
| "predownloadnitro": "npm run build", | ||
| "downloadnitro": "node dist/scripts/index.cjs", | ||
| "build:publish": "npm pack", | ||
| "postinstall": "node -r @janhq/nitro-node/postinstall" | ||
| }, | ||
| "exports": { | ||
| ".": { | ||
| "import": "./dist/index.esm.js", | ||
| "require": "./dist/index.cjs", | ||
| "types": "./dist/types/index.d.ts" | ||
| }, | ||
| "./scripts": { | ||
| "import": "./dist/scripts/index.esm.js", | ||
| "require": "./dist/scripts/index.cjs", | ||
| "types": "./dist/types/scripts/index.d.ts" | ||
| }, | ||
| "./postinstall": "./postinstall.js" | ||
| }, | ||
| "typesVersions": { | ||
| "*": { | ||
| ".": [ | ||
| "./dist/index.esm.js.map", | ||
| "./dist/types/index.d.ts" | ||
| ], | ||
| "scripts": [ | ||
| "./dist/scripts/index.esm.js.map", | ||
| "./dist/types/scripts/index.d.ts" | ||
| ] | ||
| } | ||
| }, | ||
| "devDependencies": { | ||
| "@rollup/plugin-commonjs": "^25.0.7", | ||
| "@rollup/plugin-json": "^6.1.0", | ||
| "@rollup/plugin-node-resolve": "^15.2.3", | ||
| "@rollup/plugin-replace": "^5.0.5", | ||
| "@types/download": "^8.0.5", | ||
| "@types/jest": "^29.5.11", | ||
| "@types/node": "^20.11.4", | ||
| "@types/os-utils": "^0.0.4", | ||
| "@types/tcp-port-used": "^1.0.4", | ||
| "jest": "^29.7.0", | ||
| "rollup": "^2.38.5", | ||
| "rollup-plugin-sourcemaps": "^0.6.3", | ||
| "rollup-plugin-typescript2": "^0.36.0", | ||
| "ts-jest": "^29.1.2", | ||
| "ts-node": "^10.9.2", | ||
| "typescript": "^5.3.3" | ||
| }, | ||
| "dependencies": { | ||
| "cross-fetch": "^4.0.0", | ||
| "download": "^8.0.0", | ||
| "fetch-retry": "^5.0.6", | ||
| "os-utils": "^0.0.14", | ||
| "tcp-port-used": "^1.0.2" | ||
| }, | ||
| "engines": { | ||
| "node": ">=18.0.0" | ||
| }, | ||
| "files": [ | ||
| "postinstall.js", | ||
| "dist", | ||
| "package.json", | ||
| "tsconfig.json", | ||
| "README.md" | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| // Only run if this package is installed as dependency | ||
| if (process.env.INIT_CWD === process.cwd()) process.exit(); | ||
|
|
||
| const path = require("node:path"); | ||
| const { downloadNitro } = require("@janhq/nitro-node/scripts"); | ||
| downloadNitro(path.join(__dirname, "bin")); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| import resolve from "@rollup/plugin-node-resolve"; | ||
| import commonjs from "@rollup/plugin-commonjs"; | ||
| import sourceMaps from "rollup-plugin-sourcemaps"; | ||
| import typescript from "rollup-plugin-typescript2"; | ||
| import json from "@rollup/plugin-json"; | ||
| import replace from "@rollup/plugin-replace"; | ||
|
|
||
| export default [ | ||
| { | ||
| input: `src/index.ts`, | ||
| output: [ | ||
| { file: "dist/index.cjs", format: "cjs", sourcemap: true }, | ||
| { file: "dist/index.esm.js", format: "es", sourcemap: true }, | ||
| ], | ||
| // Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash') | ||
| external: [ | ||
| // `download@8.0.0` requires `got@^8.3.1` which then optionally requires `electron`, result in wrong dependency | ||
| // Ref: https://github.com/kubernetes-client/javascript/issues/350#issue-500860208 | ||
| // Ref: https://github.com/kubernetes-client/javascript/issues/350#issuecomment-553644659 | ||
| "got", | ||
| ], | ||
| watch: { | ||
| include: "src/**", | ||
| }, | ||
| plugins: [ | ||
| replace({ | ||
| RELEASE_URL_PREFIX: JSON.stringify( | ||
| "https://api.github.com/repos/janhq/nitro/releases/", | ||
| ), | ||
| TAGGED_RELEASE_URL_PREFIX: JSON.stringify( | ||
| "https://api.github.com/repos/janhq/nitro/releases/tags", | ||
| ), | ||
| }), | ||
| // Allow json resolution | ||
| json(), | ||
| // Allow node_modules resolution, so you can use 'external' to control | ||
| // which external modules to include in the bundle | ||
| // https://github.com/rollup/rollup-plugin-node-resolve#usage | ||
| resolve({ | ||
| extensions: [".ts", ".js", ".json"], | ||
| }), | ||
| // Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs) | ||
| // This should be after resolve() plugin | ||
| commonjs(), | ||
| // Compile TypeScript files | ||
| typescript({ | ||
| useTsconfigDeclarationDir: true, | ||
| }), | ||
|
|
||
| // Resolve source maps to the original source | ||
| sourceMaps(), | ||
| ], | ||
| }, | ||
| { | ||
| input: `src/scripts/index.ts`, | ||
| output: [ | ||
| { | ||
| file: "dist/scripts/index.cjs", | ||
| format: "cjs", | ||
| sourcemap: true, | ||
| }, | ||
| { | ||
| file: "dist/scripts/index.esm.js", | ||
| format: "es", | ||
| sourcemap: true, | ||
| }, | ||
| ], | ||
| // Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash') | ||
| external: [ | ||
| // `download@8.0.0` requires `got@^8.3.1` which then optionally requires `electron`, result in wrong dependency | ||
| // Ref: https://github.com/kubernetes-client/javascript/issues/350#issue-500860208 | ||
| // Ref: https://github.com/kubernetes-client/javascript/issues/350#issuecomment-553644659 | ||
| "got", | ||
| ], | ||
| watch: { | ||
| include: "src/scripts/**", | ||
| }, | ||
| plugins: [ | ||
| replace({ | ||
| RELEASE_URL_PREFIX: JSON.stringify( | ||
| "https://api.github.com/repos/janhq/nitro/releases/", | ||
| ), | ||
| TAGGED_RELEASE_URL_PREFIX: JSON.stringify( | ||
| "https://api.github.com/repos/janhq/nitro/releases/tags", | ||
| ), | ||
| }), | ||
| // Allow json resolution | ||
| json(), | ||
|
|
||
| // Allow node_modules resolution, so you can use 'external' to control | ||
| // which external modules to include in the bundle | ||
| // https://github.com/rollup/rollup-plugin-node-resolve#usage | ||
| resolve({ | ||
| extensions: [".ts", ".js", ".json"], | ||
| }), | ||
|
|
||
| // Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs) | ||
| // This should be after resolve() plugin | ||
| commonjs(), | ||
| // Compile TypeScript files | ||
| typescript({ | ||
| useTsconfigDeclarationDir: true, | ||
| }), | ||
|
|
||
| // Resolve source maps to the original source | ||
| sourceMaps(), | ||
| ], | ||
| }, | ||
| ]; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| import path from "node:path"; | ||
| import { getNvidiaConfig } from "./nvidia"; | ||
|
|
||
| export interface NitroExecutableOptions { | ||
| executablePath: string; | ||
| cudaVisibleDevices: string; | ||
| } | ||
|
|
||
| /** | ||
| * Find which executable file to run based on the current platform. | ||
| * @returns The name of the executable file to run. | ||
| */ | ||
| export const executableNitroFile = ( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I'm seeing here is that this function expects
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Hope you understand. Thank you
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For your suggestions, I'm considering and thinking about the best ways to adapt for now with minimal effort possible. But for things in the future, please share the roadmap link of the mentioned point and a defined plan so I can understand what are the steps to iteratively deliver it. I'm not a team member at the moment so I don't know well about your plans so pardon if I'm not understanding your points correctly...😅
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Sorry, misunderstood the third point. I already exposed the error code and exit signals upon exit of nitro subprocess in the recent commits. But to handle core dump and crash then I'm not yet sure how node handles those cases, let me check and have the appropriate solution for the mentioned case. Initially, my assumption is that if nitro crashes or core dumped then no callback for error code or signal but a disconnect callback will be called, then we detect that and get dump information from the system...🤔 |
||
| binaryFolder: string, | ||
| // Default to GPU if CUDA is available when calling | ||
| runMode: "cpu" | "gpu" = getNvidiaConfig().cuda.exist ? "gpu" : "cpu", | ||
| ): NitroExecutableOptions => { | ||
| const nvidiaSettings = getNvidiaConfig(); | ||
| let cudaVisibleDevices = ""; | ||
| let binaryName = "nitro"; | ||
| /** | ||
| * The binary folder is different for each platform. | ||
| */ | ||
| if (process.platform === "win32") { | ||
| /** | ||
| * For Windows: win-cpu, win-cuda-11-7, win-cuda-12-0 | ||
| */ | ||
| if (runMode === "cpu") { | ||
| binaryFolder = path.join(binaryFolder, "win-cpu"); | ||
| } else { | ||
| if (nvidiaSettings["cuda"].version === "12") { | ||
| binaryFolder = path.join(binaryFolder, "win-cuda-12-0"); | ||
| } else { | ||
| binaryFolder = path.join(binaryFolder, "win-cuda-11-7"); | ||
| } | ||
| cudaVisibleDevices = nvidiaSettings["gpu_highest_vram"]; | ||
| } | ||
| binaryName = "nitro.exe"; | ||
| } else if (process.platform === "darwin") { | ||
| /** | ||
| * For MacOS: mac-arm64 (Silicon), mac-x64 (InteL) | ||
| */ | ||
| if (process.arch === "arm64") { | ||
| binaryFolder = path.join(binaryFolder, "mac-arm64"); | ||
| } else { | ||
| binaryFolder = path.join(binaryFolder, "mac-x64"); | ||
| } | ||
| } else { | ||
| if (runMode === "cpu") { | ||
| binaryFolder = path.join(binaryFolder, "linux-cpu"); | ||
| } else { | ||
| if (nvidiaSettings["cuda"].version === "12") { | ||
| binaryFolder = path.join(binaryFolder, "linux-cuda-12-0"); | ||
| } else { | ||
| binaryFolder = path.join(binaryFolder, "linux-cuda-11-7"); | ||
| } | ||
| cudaVisibleDevices = nvidiaSettings["gpu_highest_vram"]; | ||
| } | ||
| } | ||
| return { | ||
| executablePath: path.join(binaryFolder, binaryName), | ||
| cudaVisibleDevices, | ||
| }; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| export * from "./types"; | ||
| export * from "./nitro"; | ||
| export { getNvidiaConfig, setNvidiaConfig } from "./nvidia"; | ||
| export { setLogger } from "./logger"; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import os from "node:os"; | ||
| import { NitroLogger } from "./types"; | ||
|
|
||
| // The logger to use, default to stdout | ||
| export let log: NitroLogger = (message, ..._) => | ||
| process.stdout.write(message + os.EOL); | ||
|
|
||
| /** | ||
| * Set logger before running nitro | ||
| * @param {NitroLogger} logger The logger to use | ||
| */ | ||
| export async function setLogger(logger: NitroLogger): Promise<void> { | ||
| log = logger; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.