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.
117 lines • 4.49 kB
JavaScript
import path from 'node:path';
import chalk from 'chalk';
import { ModelStore } from '../store.js';
import { builtInEngineNames } from '../engines/index.js';
import { validateModelOptions } from '../lib/validateModelOptions.js';
import { resolveModelFileLocation } from '../lib/resolveModelFileLocation.js';
import { getCacheDirPath } from '../lib/getCacheDirPath.js';
import { LogLevels } from '../lib/logger.js';
import { loadConfig } from '../cli/lib/loadConfig.js';
async function prepareAllModels(options, concurrency) {
let modelsCachePath = getCacheDirPath('models');
if (options.cachePath) {
modelsCachePath = path.join(options.cachePath, 'models');
}
const modelsWithDefaults = {};
const usedEngines = [];
for (const modelId in options.models) {
const modelOptions = options.models[modelId];
const isBuiltIn = builtInEngineNames.includes(modelOptions.engine);
if (isBuiltIn) {
const builtInModelOptions = modelOptions;
// 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 = {};
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, concurrency) {
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.message}`));
process.exit(1);
}
}
export const prepareCommand = {
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);
},
};
//# sourceMappingURL=prepareCommand.js.map