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 4.43 kB
import path from 'node:path'; import fs from 'node:fs/promises'; import readline from 'node:readline/promises'; import chalk from 'chalk'; import micromatch from 'micromatch'; import { indexModelCache } from '../cli/lib/indexModelCache.js'; import { loadConfig } from '../cli/lib/loadConfig.js'; import { getCacheDirPath } from '../lib/getCacheDirPath.js'; import { renderTreeView } from '../cli/lib/renderTreeView.js'; import prettyBytes from 'pretty-bytes'; function matchCachedModels(cacheInfo, pattern) { const matches = []; const isMatch = micromatch.matcher(pattern); const visit = (node, nodePath) => { if (isMatch(nodePath)) { matches.push(node); } if (node.type === 'directory') { for (const child of node.children) { visit(child, nodePath + '/' + child.name); } } }; for (const node of cacheInfo.fileTree) { visit(node, node.name); } return matches; } function calculateTreeAggs(models) { let totalSize = 0; let fileCount = 0; const visit = (node) => { if (node.type === 'directory') { for (const child of node.children) { visit(child); } } else { fileCount++; totalSize += node.size; } }; for (const node of models) { visit(node); } return { totalSize, fileCount }; } async function deleteFiles(files) { for (const file of files) { if (file.type === 'directory') { await fs.rm(file.absPath, { recursive: true }); } if (file.type === 'file') { await fs.unlink(file.absPath); } } } async function promptConfirmation(message) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); try { const answer = await rl.question(`${message} (y/N): `); return answer.toLowerCase() === 'y'; } finally { rl.close(); } } async function removeModels(pattern, skipPrompt) { const config = await loadConfig(); let modelsCachePath = getCacheDirPath('models'); if (config?.options.cachePath) { modelsCachePath = path.join(config.options.cachePath, 'models'); } const cacheInfo = await indexModelCache(modelsCachePath, { includeFiles: true, includeUnused: true, }); const matches = matchCachedModels(cacheInfo, pattern); if (matches.length === 0) { console.error(chalk.red(`No models found matching the given pattern`)); return; } if (!skipPrompt) { const treeLines = renderTreeView(matches); console.log(treeLines.join('\n')); const { totalSize, fileCount } = calculateTreeAggs(matches); // console.log(chalk.cyan(`Total size: ${prettyBytes(totalSize)} bytes`)) const fileText = fileCount === 1 ? `one file` : `${fileCount} files`; const modelText = matches.length === 1 ? chalk.bold(matches[0].relPath) : `${matches.length} models`; console.log(`\nThis will remove ${fileText} freeing ${prettyBytes(totalSize)} total.`); const confirmed = await promptConfirmation(`Delete ${modelText} from disk?`); if (!confirmed) { console.log('Aborted'); return; } } try { // const subject = matches.length === 1 ? 'model' : 'models' const modelText = matches.length === 1 ? matches[0].name : `${matches.length} models`; console.log(`Deleting ${modelText} ...`); await deleteFiles(matches); console.log(chalk.green('Done')); } catch (error) { console.error(chalk.red(`Error during removal: ${error.message}`)); } } export const removeCommand = { command: 'remove <pattern>', aliases: ['rm', 'del'], describe: 'Delete models matching the pattern', builder: (yargs) => { return yargs .positional('pattern', { type: 'string', describe: 'Glob pattern to match model paths', }) .demandOption('pattern') .option('yes', { type: 'boolean', alias: 'y', describe: 'Skip confirmation prompt', default: false, }); }, handler: async (argv) => { await removeModels(argv.pattern, argv.yes); }, }; //# sourceMappingURL=removeCommand.js.map