Skip to content
This repository was archived by the owner on Jul 4, 2025. It is now read-only.

Commit 7201807

Browse files
committed
refactor: init usecases
1 parent 367a698 commit 7201807

File tree

5 files changed

+248
-220
lines changed

5 files changed

+248
-220
lines changed

cortex-js/src/command.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { ModelGetCommand } from './infrastructure/commanders/models/model-get.co
2020
import { ModelRemoveCommand } from './infrastructure/commanders/models/model-remove.command';
2121
import { RunCommand } from './infrastructure/commanders/shortcuts/run.command';
2222
import { InitCudaQuestions } from './infrastructure/commanders/inquirer/cuda.questions';
23+
import { CliUsecasesModule } from './infrastructure/commanders/usecases/cli.usecases.module';
2324

2425
@Module({
2526
imports: [
@@ -34,6 +35,7 @@ import { InitCudaQuestions } from './infrastructure/commanders/inquirer/cuda.que
3435
ChatModule,
3536
ExtensionModule,
3637
HttpModule,
38+
CliUsecasesModule
3739
],
3840
providers: [
3941
CortexCommand,
Lines changed: 9 additions & 220 deletions
Original file line numberDiff line numberDiff line change
@@ -1,248 +1,37 @@
1-
import { createWriteStream, existsSync, rmSync } from 'fs';
2-
import { CommandRunner, SubCommand, InquirerService } from 'nest-commander';
3-
import { resolve, delimiter, join } from 'path';
4-
import { HttpService } from '@nestjs/axios';
5-
import { Presets, SingleBar } from 'cli-progress';
6-
import decompress from 'decompress';
7-
import { exit } from 'node:process';
81

9-
interface InitOptions {
10-
runMode?: 'CPU' | 'GPU';
11-
gpuType?: 'Nvidia' | 'Others (Vulkan)';
12-
instructions?: 'AVX' | 'AVX2' | 'AVX512' | undefined;
13-
cudaVersion?: '11' | '12';
14-
installCuda?: 'Yes' | string
15-
}
2+
import { CommandRunner, InquirerService, SubCommand } from 'nest-commander';
3+
import { InitCliUsecases } from './usecases/init.cli.usecases';
4+
import { InitOptions } from './types/init-options.interface';
5+
166

177
@SubCommand({
188
name: 'init',
199
aliases: ['setup'],
2010
description: "Init settings and download cortex's dependencies",
2111
})
2212
export class InitCommand extends CommandRunner {
23-
CORTEX_RELEASES_URL = 'https://api.github.com/repos/janhq/cortex/releases';
24-
CUDA_DOWNLOAD_URL = 'https://catalog.jan.ai/dist/cuda-dependencies/<version>/<platform>/cuda.tar.gz'
2513

2614
constructor(
27-
private readonly httpService: HttpService,
2815
private readonly inquirerService: InquirerService,
16+
private readonly initUsecases: InitCliUsecases,
2917
) {
3018
super();
3119
}
3220

3321
async run(input: string[], options?: InitOptions): Promise<void> {
3422
options = await this.inquirerService.ask('create-init-questions', options);
3523

36-
if (options.runMode === 'GPU' && !(await this.cudaVersion())) {
24+
if (options.runMode === 'GPU' && !(await this.initUsecases.cudaVersion())) {
3725
options = await this.inquirerService.ask('init-cuda-questions', options);
3826
}
3927

4028
const version = input[0] ?? 'latest';
4129

42-
await this.installEngine(this.parseEngineFileName(options), version);
30+
const engineFileName = this.initUsecases.parseEngineFileName(options)
31+
await this.initUsecases.installEngine(engineFileName, version);
4332

4433
if (options.installCuda === 'Yes') {
45-
await this.installCudaToolkitDependency(options);
46-
}
47-
}
48-
49-
installEngine = async (
50-
engineFileName: string,
51-
version: string = 'latest',
52-
): Promise<any> => {
53-
const res = await this.httpService
54-
.get(
55-
this.CORTEX_RELEASES_URL + `${version === 'latest' ? '/latest' : ''}`,
56-
{
57-
headers: {
58-
'X-GitHub-Api-Version': '2022-11-28',
59-
Accept: 'application/vnd.github+json',
60-
},
61-
},
62-
)
63-
.toPromise();
64-
65-
if (!res?.data) {
66-
console.log('Failed to fetch releases');
67-
exit(1);
68-
}
69-
70-
let release = res?.data;
71-
if (Array.isArray(res?.data)) {
72-
release = Array(res?.data)[0].find(
73-
(e) => e.name === version.replace('v', ''),
74-
);
75-
}
76-
const toDownloadAsset = release.assets.find((s: any) =>
77-
s.name.includes(engineFileName),
78-
);
79-
80-
if (!toDownloadAsset) {
81-
console.log(`Could not find engine file ${engineFileName}`);
82-
exit(1);
83-
}
84-
85-
console.log(`Downloading engine file ${engineFileName}`);
86-
const engineDir = resolve(this.rootDir(), 'cortex-cpp');
87-
if (existsSync(engineDir)) rmSync(engineDir, { recursive: true });
88-
89-
const download = await this.httpService
90-
.get(toDownloadAsset.browser_download_url, {
91-
responseType: 'stream',
92-
})
93-
.toPromise();
94-
if (!download) {
95-
console.log('Failed to download model');
96-
process.exit(1)
97-
}
98-
99-
const destination = resolve(this.rootDir(), toDownloadAsset.name);
100-
101-
await new Promise((resolve, reject) => {
102-
const writer = createWriteStream(destination);
103-
let receivedBytes = 0;
104-
const totalBytes = download.headers['content-length'];
105-
106-
writer.on('finish', () => {
107-
bar.stop();
108-
resolve(true);
109-
});
110-
111-
writer.on('error', (error) => {
112-
bar.stop();
113-
reject(error);
114-
});
115-
116-
const bar = new SingleBar({}, Presets.shades_classic);
117-
bar.start(100, 0);
118-
119-
download.data.on('data', (chunk: any) => {
120-
receivedBytes += chunk.length;
121-
bar.update(Math.floor((receivedBytes / totalBytes) * 100));
122-
});
123-
124-
download.data.pipe(writer);
125-
});
126-
127-
try {
128-
await decompress(
129-
resolve(this.rootDir(), destination),
130-
resolve(this.rootDir()),
131-
);
132-
} catch (e) {
133-
console.log(e);
134-
exit(1);
135-
}
136-
};
137-
138-
parseEngineFileName = (options: InitOptions) => {
139-
const platform =
140-
process.platform === 'win32'
141-
? 'windows'
142-
: process.platform === 'darwin'
143-
? 'mac'
144-
: process.platform;
145-
const arch = process.arch === 'arm64' ? process.arch : 'amd64';
146-
const cudaVersion =
147-
options.runMode === 'GPU'
148-
? options.gpuType === 'Nvidia'
149-
? '-cuda-' + (options.cudaVersion === '11' ? '11-7' : '12-0')
150-
: '-vulkan'
151-
: '';
152-
const instructions = options.instructions ? `-${options.instructions}` : '';
153-
const engineName = `${platform}-${arch}${instructions.toLowerCase()}${cudaVersion}`;
154-
return `${engineName}.tar.gz`;
155-
};
156-
157-
rootDir = () => resolve(__dirname, `../../../`);
158-
159-
cudaVersion = async () => {
160-
let filesCuda12: string[]
161-
let filesCuda11: string[]
162-
let paths: string[]
163-
164-
if (process.platform === 'win32') {
165-
filesCuda12 = ['cublas64_12.dll', 'cudart64_12.dll', 'cublasLt64_12.dll']
166-
filesCuda11 = ['cublas64_11.dll', 'cudart64_110.dll', 'cublasLt64_11.dll']
167-
paths = process.env.PATH ? process.env.PATH.split(delimiter) : []
168-
} else {
169-
filesCuda12 = ['libcudart.so.12', 'libcublas.so.12', 'libcublasLt.so.12']
170-
filesCuda11 = ['libcudart.so.11.0', 'libcublas.so.11', 'libcublasLt.so.11']
171-
paths = process.env.LD_LIBRARY_PATH
172-
? process.env.LD_LIBRARY_PATH.split(delimiter)
173-
: []
174-
paths.push('/usr/lib/x86_64-linux-gnu/')
175-
}
176-
177-
if (filesCuda12.every(
178-
(file) => existsSync(file) || this.checkFileExistenceInPaths(file, paths)
179-
)) return '12'
180-
181-
182-
if (filesCuda11.every(
183-
(file) => existsSync(file) || this.checkFileExistenceInPaths(file, paths)
184-
)) return '11'
185-
186-
return undefined // No CUDA Toolkit found
187-
}
188-
189-
checkFileExistenceInPaths = (file: string, paths: string[]): boolean => {
190-
return paths.some((p) => existsSync(join(p, file)))
191-
}
192-
193-
installCudaToolkitDependency = async (options: InitOptions) => {
194-
const platform = process.platform === 'win32' ? 'windows' : 'linux'
195-
196-
const url = this.CUDA_DOWNLOAD_URL
197-
.replace('<version>', options.cudaVersion === '11' ? '11.7' : '12.0')
198-
.replace('<platform>', platform)
199-
const destination = resolve(this.rootDir(), 'cuda-toolkit.tar.gz');
200-
201-
const download = await this.httpService
202-
.get(url, {
203-
responseType: 'stream',
204-
})
205-
.toPromise();
206-
207-
if (!download) {
208-
console.log('Failed to download dependency');
209-
process.exit(1)
210-
}
211-
212-
await new Promise((resolve, reject) => {
213-
const writer = createWriteStream(destination);
214-
let receivedBytes = 0;
215-
const totalBytes = download.headers['content-length'];
216-
217-
writer.on('finish', () => {
218-
bar.stop();
219-
resolve(true);
220-
});
221-
222-
writer.on('error', (error) => {
223-
bar.stop();
224-
reject(error);
225-
});
226-
227-
const bar = new SingleBar({}, Presets.shades_classic);
228-
bar.start(100, 0);
229-
230-
download.data.on('data', (chunk: any) => {
231-
receivedBytes += chunk.length;
232-
bar.update(Math.floor((receivedBytes / totalBytes) * 100));
233-
});
234-
235-
download.data.pipe(writer);
236-
});
237-
238-
try {
239-
await decompress(
240-
resolve(this.rootDir(), destination),
241-
resolve(this.rootDir(), 'cortex-cpp'),
242-
);
243-
} catch (e) {
244-
console.log(e);
245-
exit(1);
34+
await this.initUsecases.installCudaToolkitDependency(options);
24635
}
24736
}
24837
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export interface InitOptions {
2+
runMode?: 'CPU' | 'GPU';
3+
gpuType?: 'Nvidia' | 'Others (Vulkan)';
4+
instructions?: 'AVX' | 'AVX2' | 'AVX512' | undefined;
5+
cudaVersion?: '11' | '12';
6+
installCuda?: 'Yes' | string
7+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Module } from "@nestjs/common";
2+
import { InitCliUsecases } from "./init.cli.usecases";
3+
import { HttpModule } from "@nestjs/axios";
4+
5+
@Module({
6+
imports: [HttpModule],
7+
controllers: [],
8+
providers: [InitCliUsecases],
9+
exports: [InitCliUsecases],
10+
})
11+
export class CliUsecasesModule {}

0 commit comments

Comments
 (0)