UNPKG

inference-server

Version:

Libraries and server to build AI applications. Adapters to various native bindings allowing local inference. Integrate it with your application, or use as a microservice.

133 lines (125 loc) 4.31 kB
import type { CommandModule } from 'yargs' import path from 'node:path' import chalk from 'chalk' import { InferenceServerOptions } from '#package/server.js' import { ModelStore } from '#package/store.js' import { BuiltInModelOptions, ModelConfigBase, ModelEngine } from '#package/types/index.js' import { builtInEngineNames } from '#package/engines/index.js' import { validateModelOptions } from '#package/lib/validateModelOptions.js' import { resolveModelFileLocation } from '#package/lib/resolveModelFileLocation.js' import { getCacheDirPath } from '#package/lib/getCacheDirPath.js' import { LogLevels } from '#package/lib/logger.js' import { loadConfig } from '#package/cli/lib/loadConfig.js' interface PrepareCommandArgs { configPath?: string concurrency?: number } async function prepareAllModels(options: InferenceServerOptions, concurrency?: number): Promise<void> { let modelsCachePath = getCacheDirPath('models') if (options.cachePath) { modelsCachePath = path.join(options.cachePath, 'models') } const modelsWithDefaults: Record<string, ModelConfigBase> = {} const usedEngines: Array<{ model: string; engine: string }> = [] for (const modelId in options.models) { const modelOptions = options.models[modelId] const isBuiltIn = builtInEngineNames.includes(modelOptions.engine) if (isBuiltIn) { const builtInModelOptions = modelOptions as BuiltInModelOptions // can validate and resolve location of model files if a built-in engine is used validateModelOptions(modelId, builtInModelOptions) modelsWithDefaults[modelId] = { id: modelId, minInstances: 0, maxInstances: 1, modelsCachePath, prepare: 'blocking', location: resolveModelFileLocation({ url: builtInModelOptions.url, filePath: builtInModelOptions.location, modelsCachePath, }), ...builtInModelOptions, } } } const customEngines = Object.keys(options.engines ?? {}) const loadedEngines: Record<string, ModelEngine> = {} for (const ref of usedEngines) { const isBuiltIn = builtInEngineNames.includes(ref.engine) const isCustom = customEngines.includes(ref.engine) if (!isBuiltIn && !isCustom) { throw new Error(`Engine "${ref.engine}" used by model "${ref.model}" does not exist`) } if (isCustom) { loadedEngines[ref.engine] = options.engines![ref.engine] } } const store = new ModelStore({ log: LogLevels.info, prepareConcurrency: concurrency, models: modelsWithDefaults, modelsCachePath, }) const importPromises = [] for (const key of builtInEngineNames) { // skip unused engines const modelUsingEngine = Object.keys(store.models).find((modelId) => store.models[modelId].engine === key) if (!modelUsingEngine) { continue } importPromises.push( new Promise(async (resolve, reject) => { try { const engine = await import(`../engines/${key}/engine.js`) loadedEngines[key] = engine resolve({ key, engine, }) } catch (err) { reject(err) } }), ) } await Promise.all(importPromises) await store.init(loadedEngines) } async function prepareModels(configPath?: string, concurrency?: number): Promise<void> { try { const config = await loadConfig(configPath) if (!config) { throw new Error( 'No configuration file found. Please provide a config file path or create one of: infs.config.js, infs.config.mjs, infs.config.json, or add an "infs" key to package.json', ) } console.log(chalk.blue(`Using config from: ${configPath}`)) await prepareAllModels(config.options, concurrency) console.log(chalk.green('\nModel preparation complete!')) } catch (error) { console.error(chalk.red(`Error: ${(error as Error).message}`)) process.exit(1) } } export const prepareCommand: CommandModule<{}, PrepareCommandArgs> = { command: 'prepare <configPath>', aliases: ['prep', 'download'], describe: 'Prepare models defined in configuration', builder: (yargs) => { return yargs .positional('configPath', { type: 'string', describe: 'Path to config file (defaults to infs.config.js)', }) .option('concurrency', { alias: 'c', type: 'number', describe: 'Number of models to prepare concurrently', default: 1, }) }, handler: async (argv) => { await prepareModels(argv.configPath, argv.concurrency) }, }