refactor: remove JS server package (#5192)

* refactor: remove js server package

* chore: migrate HF token data
This commit is contained in:
Louis 2025-06-04 15:33:35 +07:00 committed by GitHub
parent 30acc6f493
commit 6faca3e732
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 35 additions and 7042 deletions

View File

@ -148,6 +148,23 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
window.addEventListener('beforeunload', () => {
this.clean()
})
// Migrate configs
if (!localStorage.getItem('cortex_migration_completed')) {
const config = await this.getCortexConfig()
console.log('Start cortex.cpp migration', config)
if (config && config.huggingface_token) {
this.updateSettings([
{
key: Settings.huggingfaceToken,
controllerProps: {
value: config.huggingface_token,
},
},
])
localStorage.setItem('cortex_migration_completed', 'true')
}
}
}
async onUnload() {
@ -313,6 +330,16 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
.catch((e) => console.debug(e))
}
/**
* Get cortex config
* @param body
*/
private async getCortexConfig(): Promise<any> {
return this.apiInstance()
.then((api) => api.get('v1/configs').json())
.catch((e) => console.debug(e))
}
/**
* Subscribe to cortex.cpp websocket events
*/

1
server/.gitignore vendored
View File

@ -1 +0,0 @@
data

File diff suppressed because it is too large Load Diff

1
server/global.d.ts vendored
View File

@ -1 +0,0 @@
declare const CORTEX_API_URL: string

View File

@ -1,58 +0,0 @@
import { log } from '@janhq/core/node'
import { FastifyBaseLogger } from 'fastify'
import { ChildLoggerOptions } from 'fastify/types/logger'
import pino from 'pino'
export class Logger implements FastifyBaseLogger {
child(
bindings: pino.Bindings,
options?: ChildLoggerOptions | undefined
): FastifyBaseLogger {
return new Logger()
}
level = 'info'
silent = () => {}
info = (obj?: any, msg?: string, ...args: any[]) => {
if (obj?.res?.raw?.statusCode || obj?.req?.url) {
log(
`[SERVER]::${JSON.stringify({
level: obj?.level,
time: obj?.time,
hostname: obj?.hostname,
reqId: obj?.req?.id ?? obj?.res?.request?.id,
res: {
statusCode: obj?.res?.raw?.statusCode,
},
req: {
method: obj?.req?.method,
url: obj?.req?.url,
path: obj?.req?.path,
hostname: obj?.req?.hostname,
remoteAddress: obj?.req?.remoteAddress,
remotePort: obj?.req?.remotePort,
},
msg,
responseTime: obj?.responseTime,
...args,
})}`
)
}
}
error = function (message: any) {
log(`[SERVER]::${JSON.stringify(message)}`)
}
debug = function (message: any) {
log(`[SERVER]::${JSON.stringify(message)}`)
}
fatal = function (message: any) {
log(`[SERVER]::${JSON.stringify(message)}`)
}
warn = function (message: any) {
log(`[SERVER]::${JSON.stringify(message)}`)
}
trace = function (message: any) {
log(`[SERVER]::${JSON.stringify(message)}`)
}
}

View File

@ -1,73 +0,0 @@
import { join, extname } from 'path'
import { existsSync, readdirSync, writeFileSync, mkdirSync } from 'fs'
import { init, installExtensions } from '@janhq/core/node'
export async function setup() {
/**
* Setup Jan Data Directory
*/
const appDir = process.env.JAN_DATA_DIRECTORY ?? join(__dirname, '..', 'jan')
console.debug(`Create app data directory at ${appDir}...`)
if (!existsSync(appDir)) mkdirSync(appDir)
//@ts-ignore
global.core = {
// Define appPath function for app to retrieve app path globally
appPath: () => appDir,
}
init({
extensionsPath: join(appDir, 'extensions'),
})
/**
* Write app configurations. See #1619
*/
console.debug('Writing config file...')
writeFileSync(
join(appDir, 'settings.json'),
JSON.stringify({
data_folder: appDir,
}),
'utf-8'
)
if (!existsSync(join(appDir, 'settings'))) {
console.debug('Writing nvidia config file...')
mkdirSync(join(appDir, 'settings'))
writeFileSync(
join(appDir, 'settings', 'settings.json'),
JSON.stringify(
{
notify: true,
run_mode: 'cpu',
nvidia_driver: {
exist: false,
version: '',
},
cuda: {
exist: false,
version: '',
},
gpus: [],
gpu_highest_vram: '',
gpus_in_use: [],
is_initial: true,
}),
'utf-8'
)
}
/**
* Install extensions
*/
console.debug('Installing extensions...')
const baseExtensionPath = join(__dirname, '../../..', 'pre-install')
const extensions = readdirSync(baseExtensionPath)
.filter((file) => extname(file) === '.tgz')
.map((file) => join(baseExtensionPath, file))
await installExtensions(extensions)
console.debug('Extensions installed')
}

View File

@ -1,180 +0,0 @@
import fastify from 'fastify'
import dotenv from 'dotenv'
import { log } from '@janhq/core/node'
import tcpPortUsed from 'tcp-port-used'
import { Logger } from './helpers/logger'
import CORTEX_SCHEMA from './cortex.json'
// Load environment variables
dotenv.config()
// Define default settings
const JAN_API_HOST = process.env.JAN_API_HOST || '127.0.0.1'
const JAN_API_PORT = Number.parseInt(process.env.JAN_API_PORT || '1337')
// Initialize server settings
let server: any | undefined = undefined
let hostSetting: string = JAN_API_HOST
let portSetting: number = JAN_API_PORT
let corsEnabled: boolean = true
let isVerbose: boolean = true
/**
* Server configurations
* @param host - The host address for the server
* @param port - The port number for the server
* @param isCorsEnabled - Flag to enable or disable CORS
* @param isVerboseEnabled - Flag to enable or disable verbose logging
* @param schemaPath - Path to the OpenAPI schema file
* @param baseDir - Base directory for the OpenAPI schema file
*/
export interface ServerConfig {
host?: string
port?: number
isCorsEnabled?: boolean
isVerboseEnabled?: boolean
schemaPath?: string
baseDir?: string
prefix?: string
storageAdataper?: any
}
/**
* Function to start the server
* @param configs - Server configurations
*/
export const startServer = async (configs?: ServerConfig): Promise<boolean> => {
if (configs?.port && configs?.host) {
const inUse = await tcpPortUsed.check(Number(configs.port), configs.host)
if (inUse) {
const errorMessage = `Port ${configs.port} is already in use.`
log(errorMessage, '[SERVER]')
throw new Error(errorMessage)
}
}
// Update server settings
isVerbose = configs?.isVerboseEnabled ?? true
hostSetting = configs?.host ?? JAN_API_HOST
portSetting = configs?.port ?? JAN_API_PORT
corsEnabled = configs?.isCorsEnabled ?? true
// Start the server
try {
// Log server start
if (isVerbose) log(`Debug: Starting JAN API server...`, '[SERVER]')
// Initialize Fastify server with logging
server = fastify({
loggerInstance: new Logger(),
// Set body limit to 100MB - Default is 1MB
// According to OpenAI - a batch input file can be up to 100 MB in size
// Whisper endpoints accept up to 25MB
// Vision endpoints accept up to 4MB
bodyLimit: 104_857_600,
})
// Register CORS if enabled
if (corsEnabled) await server.register(require('@fastify/cors'), {})
CORTEX_SCHEMA.servers[0].url = configs?.prefix ?? '/v1'
// Register Swagger for API documentation
await server.register(require('@fastify/swagger'), {
mode: 'static',
specification: {
document: CORTEX_SCHEMA,
},
})
const rewriteRequestHeaders = (req: any, headers: any) => {
if (req.url.includes('/configs')) return headers
return {
...headers,
authorization: `Bearer ${process.env.appToken}`, // Add or modify Authorization header
}
}
// Register Swagger UI
await server.register(require('@fastify/swagger-ui'), {
routePrefix: '/',
uiConfig: {
docExpansion: 'full',
deepLinking: false,
},
staticCSP: false,
transformSpecificationClone: true,
})
const proxy = require('@fastify/http-proxy')
server.register(proxy, {
upstream: `${CORTEX_API_URL}/v1`,
prefix: configs?.prefix ?? '/v1',
http2: false,
replyOptions: {
rewriteRequestHeaders,
},
})
server.register(proxy, {
upstream: `${CORTEX_API_URL}/processManager`,
prefix: '/processManager',
http2: false,
replyOptions: {
rewriteRequestHeaders,
},
})
server.register(proxy, {
upstream: `${CORTEX_API_URL}/system`,
prefix: '/system',
http2: false,
replyOptions: {
rewriteRequestHeaders,
},
})
server.register(proxy, {
upstream: `${CORTEX_API_URL}/healthz`,
prefix: '/healthz',
http2: false,
replyOptions: {
rewriteRequestHeaders,
},
})
// Start listening for requests
await server
.listen({
port: portSetting,
host: hostSetting,
})
.then(() => {
// Log server listening
if (isVerbose)
log(
`Debug: JAN API listening at: http://${hostSetting}:${portSetting}`,
'[SERVER]'
)
})
return true
} catch (e) {
// Log any errors
if (isVerbose) log(`Error: ${e}`, '[SERVER]')
}
return false
}
/**
* Function to stop the server
*/
export const stopServer = async () => {
try {
// Log server stop
if (isVerbose) log(`Debug: Server stopped`, '[SERVER]')
// Stop the server
await server?.close()
} catch (e) {
// Log any errors
if (isVerbose) log(`Error: ${e}`, '[SERVER]')
}
}

View File

@ -1,43 +0,0 @@
{
"name": "@janhq/server",
"version": "0.1.3",
"main": "dist/index.js",
"author": "Jan <service@jan.ai>",
"license": "AGPL-3.0",
"homepage": "https://jan.ai",
"description": "Jan API Server proxies route all requests to cortex.cpp server with customized configurations.",
"files": [
"build/**",
"cortex.json"
],
"scripts": {
"lint": "eslint . --ext \".js,.jsx,.ts,.tsx\"",
"build": "rolldown -c rolldown.config.mjs"
},
"dependencies": {
"@fastify/cors": "^10.0.1",
"@fastify/http-proxy": "^10.0.0",
"@fastify/static": "^6.12.0",
"@fastify/swagger": "^9.4.0",
"@fastify/swagger-ui": "5.2.0",
"@janhq/core": "link:../core",
"dotenv": "^16.3.1",
"fastify": "^5.2.0",
"tcp-port-used": "^1.0.2"
},
"devDependencies": {
"@types/body-parser": "^1.19.5",
"@types/npmcli__arborist": "^5.6.4",
"@types/tcp-port-used": "^1.0.4",
"@typescript-eslint/eslint-plugin": "^6.7.3",
"@typescript-eslint/parser": "^6.7.3",
"eslint-plugin-react": "^7.34.0",
"rolldown": "1.0.0-beta.1",
"run-script-os": "^1.1.6",
"typescript": "^5.3.3"
},
"bundleDependencies": [
"@fastify/swagger-ui"
],
"packageManager": "yarn@4.5.3"
}

View File

@ -1,21 +0,0 @@
import { defineConfig } from 'rolldown'
export default defineConfig([
{
input: 'index.ts',
output: {
format: 'cjs',
file: 'dist/index.js',
sourcemap: true,
inlineDynamicImports: true,
},
resolve: {
extensions: ['.js', '.ts'],
},
external: ['@fastify/swagger-ui'],
platform: 'node',
define: {
CORTEX_API_URL: JSON.stringify(`http://127.0.0.1:${process.env.CORTEX_API_PORT ?? "39291"}`),
}
},
])

View File

@ -1,25 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"noImplicitAny": true,
"sourceMap": true,
"strict": false,
"outDir": "./dist",
"rootDir": "./",
"noEmitOnError": true,
"esModuleInterop": true,
"baseUrl": ".",
"allowJs": true,
"skipLibCheck": true,
"paths": { "*": ["node_modules/*"] },
"typeRoots": ["node_modules/@types"],
"ignoreDeprecations": "5.0",
"declaration": true,
"resolveJsonModule": true
},
// "sourceMap": true,
"include": ["./**/*.ts"],
"exclude": ["core", "build", "dist", "tests", "node_modules", "extensions"]
}

View File

@ -50,9 +50,11 @@ export const useModelProvider = create<ModelProviderState>()(
...provider,
models: mergedModels,
settings: provider.settings.map((setting) => {
const existingSetting = existingProvider?.settings?.find(
(x) => x.key === setting.key
)
const existingSetting = provider.persist
? undefined
: existingProvider?.settings?.find(
(x) => x.key === setting.key
)
return {
...setting,
controller_props: {

View File

@ -55,6 +55,7 @@ export const getProviders = async (): Promise<ModelProvider[]> => {
) ?? []
const provider: ModelProvider = {
active: false,
persist: true,
provider: providerName,
base_url:
'inferenceUrl' in value

View File

@ -45,6 +45,7 @@ type ProviderObject = {
base_url?: string
settings: ProviderSetting[]
models: Model[]
persist?: boolean
}
/**
@ -67,4 +68,4 @@ type ProxyOptions = {
verifyPeerSSL: boolean
verifyHostSSL: boolean
noProxy: string
}
}