cli-ai-skills 1.0.0 ā 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -0
- package/lib/commands/doctor.js +52 -0
- package/lib/commands/install.js +64 -0
- package/lib/commands/list.js +18 -1
- package/lib/core/requirements-installer.js +202 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ npx cli-ai-skills install
|
|
|
14
14
|
- š **Global or Local** - Install globally or per-repository
|
|
15
15
|
- š **Symlink Support** - Auto-updates with repository changes
|
|
16
16
|
- š **Progress Gauge** - Visual progress tracking
|
|
17
|
+
- š **Python Requirements** - Auto-installs Python dependencies for skills that need them
|
|
17
18
|
- š„ **Doctor Command** - Diagnose installation issues
|
|
18
19
|
|
|
19
20
|
## š Quick Start
|
|
@@ -46,6 +47,9 @@ You'll be prompted to select:
|
|
|
46
47
|
- **prompt-engineer** - Transform prompts using 11 established frameworks
|
|
47
48
|
- **skill-creator** - Create new skills interactively
|
|
48
49
|
- **youtube-summarizer** - Extract and summarize YouTube videos
|
|
50
|
+
- **audio-transcriber** š - Transcribe audio to text with meeting minutes and summaries
|
|
51
|
+
|
|
52
|
+
> š = Requires Python dependencies (auto-installed during setup)
|
|
49
53
|
|
|
50
54
|
## š Commands
|
|
51
55
|
|
|
@@ -126,6 +130,53 @@ Checks:
|
|
|
126
130
|
- ā
Platform installations (Copilot/Claude)
|
|
127
131
|
- ā
Directory permissions
|
|
128
132
|
- ā
Network connectivity
|
|
133
|
+
- ā
Python environment (for audio-transcriber skill)
|
|
134
|
+
- ā
Whisper and ffmpeg installation
|
|
135
|
+
|
|
136
|
+
## š Python Requirements
|
|
137
|
+
|
|
138
|
+
Some skills (like **audio-transcriber**) require Python dependencies. The installer handles this automatically:
|
|
139
|
+
|
|
140
|
+
### Automatic Installation
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
$ npx cli-ai-skills install audio-transcriber
|
|
144
|
+
|
|
145
|
+
š¦ Downloading audio-transcriber v1.0.0...
|
|
146
|
+
ā
Installed successfully
|
|
147
|
+
|
|
148
|
+
š¦ This skill requires Python dependencies
|
|
149
|
+
ā
Python detected: 3.11.7
|
|
150
|
+
? Install Python requirements now? (Y/n) Y
|
|
151
|
+
|
|
152
|
+
š§ Running install-requirements.sh...
|
|
153
|
+
ā
pkg-config installed
|
|
154
|
+
ā
ffmpeg installed
|
|
155
|
+
ā
openai-whisper installed
|
|
156
|
+
|
|
157
|
+
š audio-transcriber ready to use!
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Manual Installation
|
|
161
|
+
|
|
162
|
+
If you skip auto-install, you can run it later:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# Using the skill's install script
|
|
166
|
+
bash ~/.copilot/skills/audio-transcriber/scripts/install-requirements.sh
|
|
167
|
+
|
|
168
|
+
# Or manually with pip
|
|
169
|
+
pip install --user openai-whisper
|
|
170
|
+
brew install ffmpeg # macOS
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Checking Python Status
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
npx cli-ai-skills doctor
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Shows Python version, Whisper, and ffmpeg status.
|
|
129
180
|
|
|
130
181
|
## šØ Example Usage
|
|
131
182
|
|
package/lib/commands/doctor.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const PlatformDetector = require('../core/detector');
|
|
3
|
+
const RequirementsInstaller = require('../core/requirements-installer');
|
|
3
4
|
const { execSync } = require('child_process');
|
|
4
5
|
|
|
5
6
|
async function doctorCommand() {
|
|
@@ -80,6 +81,57 @@ async function doctorCommand() {
|
|
|
80
81
|
console.log(chalk.dim(` Install: https://claude.ai/code`));
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
console.log(chalk.cyan('\n' + 'ā'.repeat(60)));
|
|
85
|
+
console.log(chalk.bold('\nPython Environment (for audio-transcriber):\n'));
|
|
86
|
+
|
|
87
|
+
const requirementsInstaller = new RequirementsInstaller();
|
|
88
|
+
|
|
89
|
+
// Check Python
|
|
90
|
+
console.log(chalk.bold('Python:'));
|
|
91
|
+
const pythonCheck = await requirementsInstaller.verifyPython();
|
|
92
|
+
if (pythonCheck.available) {
|
|
93
|
+
console.log(chalk.green(` ā
${pythonCheck.version}`));
|
|
94
|
+
} else {
|
|
95
|
+
console.log(chalk.yellow(' ā ļø Python 3 not found'));
|
|
96
|
+
console.log(chalk.dim(' Required for audio-transcriber skill'));
|
|
97
|
+
console.log(chalk.dim(' Install: https://www.python.org/downloads/'));
|
|
98
|
+
warnings++;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Check Whisper (if Python available)
|
|
102
|
+
if (pythonCheck.available) {
|
|
103
|
+
console.log(chalk.bold('\nWhisper (Audio Transcription):'));
|
|
104
|
+
const fasterWhisperInstalled = await requirementsInstaller.isPackageInstalled('faster_whisper');
|
|
105
|
+
const whisperInstalled = await requirementsInstaller.isPackageInstalled('whisper');
|
|
106
|
+
|
|
107
|
+
if (fasterWhisperInstalled) {
|
|
108
|
+
console.log(chalk.green(' ā
Faster-Whisper installed (optimized)'));
|
|
109
|
+
} else if (whisperInstalled) {
|
|
110
|
+
console.log(chalk.green(' ā
OpenAI Whisper installed'));
|
|
111
|
+
} else {
|
|
112
|
+
console.log(chalk.yellow(' ā ļø Whisper not installed'));
|
|
113
|
+
console.log(chalk.dim(' Required for audio-transcriber skill'));
|
|
114
|
+
console.log(chalk.dim(' Install: pip install --user openai-whisper'));
|
|
115
|
+
warnings++;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Check ffmpeg
|
|
119
|
+
console.log(chalk.bold('\nffmpeg (Audio Processing):'));
|
|
120
|
+
try {
|
|
121
|
+
execSync('which ffmpeg', { stdio: 'pipe' });
|
|
122
|
+
const ffmpegVersion = execSync('ffmpeg -version 2>&1 | head -1', {
|
|
123
|
+
encoding: 'utf-8',
|
|
124
|
+
stdio: 'pipe'
|
|
125
|
+
}).trim();
|
|
126
|
+
console.log(chalk.green(` ā
Installed`));
|
|
127
|
+
console.log(chalk.dim(` ${ffmpegVersion.split('\n')[0]}`));
|
|
128
|
+
} catch {
|
|
129
|
+
console.log(chalk.yellow(' ā ļø Not installed (optional)'));
|
|
130
|
+
console.log(chalk.dim(' Recommended for audio format conversion'));
|
|
131
|
+
console.log(chalk.dim(' Install: brew install ffmpeg (macOS)'));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
83
135
|
console.log(chalk.cyan('\n' + 'ā'.repeat(60)));
|
|
84
136
|
console.log(chalk.bold('\nNetwork Connectivity:\n'));
|
|
85
137
|
|
package/lib/commands/install.js
CHANGED
|
@@ -4,6 +4,7 @@ const PlatformDetector = require('../core/detector');
|
|
|
4
4
|
const SkillDownloader = require('../core/downloader');
|
|
5
5
|
const VersionChecker = require('../core/version-checker');
|
|
6
6
|
const SkillInstaller = require('../core/installer');
|
|
7
|
+
const RequirementsInstaller = require('../core/requirements-installer');
|
|
7
8
|
const InstallationPrompts = require('../ui/prompts');
|
|
8
9
|
const ProgressGauge = require('../ui/progress-gauge');
|
|
9
10
|
const path = require('path');
|
|
@@ -195,6 +196,69 @@ async function installCommand(skillNames, options) {
|
|
|
195
196
|
results.installed.push(skillName);
|
|
196
197
|
console.log(chalk.green(` ā
Installed successfully`));
|
|
197
198
|
}
|
|
199
|
+
|
|
200
|
+
// Check for Python requirements
|
|
201
|
+
const requirementsInstaller = new RequirementsInstaller();
|
|
202
|
+
const firstPlatform = selectedPlatforms[0];
|
|
203
|
+
const skillPath = path.join(installPaths[firstPlatform], skillName);
|
|
204
|
+
|
|
205
|
+
const requirements = await requirementsInstaller.detectRequirements(skillPath);
|
|
206
|
+
|
|
207
|
+
if (requirements.hasRequirements) {
|
|
208
|
+
console.log(chalk.blue('\n š¦ This skill requires Python dependencies'));
|
|
209
|
+
|
|
210
|
+
// Check Python availability
|
|
211
|
+
const pythonCheck = await requirementsInstaller.verifyPython();
|
|
212
|
+
|
|
213
|
+
if (!pythonCheck.available) {
|
|
214
|
+
console.log(chalk.yellow(' ā ļø Python 3 not found'));
|
|
215
|
+
console.log(chalk.dim(' Please install Python 3.8+ to use this skill'));
|
|
216
|
+
console.log(chalk.dim(' Download: https://www.python.org/downloads/'));
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
console.log(chalk.green(` ā
Python detected: ${pythonCheck.version}`));
|
|
221
|
+
|
|
222
|
+
// Ask user if they want to install requirements
|
|
223
|
+
let installRequirements = options.yes;
|
|
224
|
+
|
|
225
|
+
if (!options.yes) {
|
|
226
|
+
const inquirer = require('inquirer');
|
|
227
|
+
const answer = await inquirer.prompt([
|
|
228
|
+
{
|
|
229
|
+
type: 'confirm',
|
|
230
|
+
name: 'install',
|
|
231
|
+
message: 'Install Python requirements now?',
|
|
232
|
+
default: true
|
|
233
|
+
}
|
|
234
|
+
]);
|
|
235
|
+
installRequirements = answer.install;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (installRequirements) {
|
|
239
|
+
const installResult = await requirementsInstaller.installRequirements(requirements, {
|
|
240
|
+
verbose: options.verbose
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
if (!installResult.success) {
|
|
244
|
+
console.log(chalk.yellow('\n š” You can install requirements later:'));
|
|
245
|
+
if (requirements.type === 'bash') {
|
|
246
|
+
console.log(chalk.dim(` bash ${requirements.scriptPath}`));
|
|
247
|
+
} else if (requirements.type === 'pip') {
|
|
248
|
+
console.log(chalk.dim(` pip install --user ${requirements.packages.join(' ')}`));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
console.log(chalk.blue('\n ā¹ļø Skipped requirements installation'));
|
|
253
|
+
console.log(chalk.dim(' You can install later:'));
|
|
254
|
+
if (requirements.type === 'bash') {
|
|
255
|
+
console.log(chalk.dim(` bash ${path.relative(process.cwd(), requirements.scriptPath)}`));
|
|
256
|
+
} else if (requirements.type === 'pip') {
|
|
257
|
+
console.log(chalk.dim(` pip install --user ${requirements.packages.join(' ')}`));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
198
262
|
} else {
|
|
199
263
|
results.failed.push(skillName);
|
|
200
264
|
console.log(chalk.red(` ā Failed: ${result.errors.join(', ')}`));
|
package/lib/commands/list.js
CHANGED
|
@@ -2,6 +2,7 @@ const chalk = require('chalk');
|
|
|
2
2
|
const PlatformDetector = require('../core/detector');
|
|
3
3
|
const SkillDownloader = require('../core/downloader');
|
|
4
4
|
const VersionChecker = require('../core/version-checker');
|
|
5
|
+
const RequirementsInstaller = require('../core/requirements-installer');
|
|
5
6
|
const path = require('path');
|
|
6
7
|
|
|
7
8
|
async function listCommand(options) {
|
|
@@ -10,6 +11,7 @@ async function listCommand(options) {
|
|
|
10
11
|
const detector = new PlatformDetector();
|
|
11
12
|
const downloader = new SkillDownloader();
|
|
12
13
|
const versionChecker = new VersionChecker();
|
|
14
|
+
const requirementsInstaller = new RequirementsInstaller();
|
|
13
15
|
|
|
14
16
|
try {
|
|
15
17
|
// Get available skills
|
|
@@ -25,6 +27,7 @@ async function listCommand(options) {
|
|
|
25
27
|
let installedStatus = 'ā¬';
|
|
26
28
|
let versionInfo = '';
|
|
27
29
|
let platformList = [];
|
|
30
|
+
let requirementsStatus = '';
|
|
28
31
|
|
|
29
32
|
// Check if installed in each platform
|
|
30
33
|
for (const [platform, dirPath] of Object.entries(installPaths)) {
|
|
@@ -34,6 +37,20 @@ async function listCommand(options) {
|
|
|
34
37
|
if (updateStatus.installed) {
|
|
35
38
|
platformList.push(platform);
|
|
36
39
|
|
|
40
|
+
// Check requirements status only once
|
|
41
|
+
if (!requirementsStatus) {
|
|
42
|
+
const reqStatus = await requirementsInstaller.checkRequirementsStatus(skillPath);
|
|
43
|
+
if (reqStatus.hasRequirements) {
|
|
44
|
+
if (reqStatus.status === 'installed') {
|
|
45
|
+
requirementsStatus = chalk.green(` š (${reqStatus.details.join(', ')})`);
|
|
46
|
+
} else if (reqStatus.status === 'not-installed') {
|
|
47
|
+
requirementsStatus = chalk.yellow(` š (requirements not installed)`);
|
|
48
|
+
} else {
|
|
49
|
+
requirementsStatus = chalk.dim(` š`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
37
54
|
if (updateStatus.needsUpdate) {
|
|
38
55
|
installedStatus = 'ā ļø ';
|
|
39
56
|
versionInfo = chalk.yellow(` (v${updateStatus.currentVersion} ā v${skill.version} available)`);
|
|
@@ -44,7 +61,7 @@ async function listCommand(options) {
|
|
|
44
61
|
}
|
|
45
62
|
}
|
|
46
63
|
|
|
47
|
-
console.log(`${installedStatus} ${chalk.bold(skill.name)} v${skill.version}${versionInfo}`);
|
|
64
|
+
console.log(`${installedStatus} ${chalk.bold(skill.name)} v${skill.version}${versionInfo}${requirementsStatus}`);
|
|
48
65
|
console.log(chalk.dim(` ${skill.description}`));
|
|
49
66
|
|
|
50
67
|
if (platformList.length > 0) {
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const ora = require('ora');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Handles installation of Python requirements for skills
|
|
9
|
+
*/
|
|
10
|
+
class RequirementsInstaller {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.pythonCmd = 'python3';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Detect if skill has requirements to install
|
|
17
|
+
* @param {string} skillPath - Path to skill directory
|
|
18
|
+
* @returns {Promise<Object>} Requirements info
|
|
19
|
+
*/
|
|
20
|
+
async detectRequirements(skillPath) {
|
|
21
|
+
// Check for install script (preferred method)
|
|
22
|
+
const installScript = path.join(skillPath, 'scripts', 'install-requirements.sh');
|
|
23
|
+
|
|
24
|
+
if (await fs.pathExists(installScript)) {
|
|
25
|
+
return {
|
|
26
|
+
hasRequirements: true,
|
|
27
|
+
scriptPath: installScript,
|
|
28
|
+
type: 'bash',
|
|
29
|
+
method: 'script'
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Check for requirements.txt (fallback)
|
|
34
|
+
const requirementsTxt = path.join(skillPath, 'requirements.txt');
|
|
35
|
+
|
|
36
|
+
if (await fs.pathExists(requirementsTxt)) {
|
|
37
|
+
const packages = await fs.readFile(requirementsTxt, 'utf-8');
|
|
38
|
+
const parsedPackages = packages
|
|
39
|
+
.split('\n')
|
|
40
|
+
.filter(p => p.trim() && !p.trim().startsWith('#'));
|
|
41
|
+
if (parsedPackages.length === 0) {
|
|
42
|
+
return { hasRequirements: false };
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
hasRequirements: true,
|
|
46
|
+
file: requirementsTxt,
|
|
47
|
+
packages: parsedPackages,
|
|
48
|
+
type: 'pip',
|
|
49
|
+
method: 'requirements.txt'
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { hasRequirements: false };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Verify Python is available
|
|
58
|
+
* @returns {Promise<Object>} Python availability info
|
|
59
|
+
*/
|
|
60
|
+
async verifyPython() {
|
|
61
|
+
try {
|
|
62
|
+
const version = execSync(`${this.pythonCmd} --version`, {
|
|
63
|
+
encoding: 'utf-8',
|
|
64
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
65
|
+
}).trim();
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
available: true,
|
|
69
|
+
version: version,
|
|
70
|
+
command: this.pythonCmd
|
|
71
|
+
};
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return { available: false };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Install requirements for a skill
|
|
79
|
+
* @param {Object} requirements - Requirements object from detectRequirements()
|
|
80
|
+
* @param {Object} options - Installation options
|
|
81
|
+
* @returns {Promise<Object>} Installation result
|
|
82
|
+
*/
|
|
83
|
+
async installRequirements(requirements, options = {}) {
|
|
84
|
+
if (!requirements.hasRequirements) {
|
|
85
|
+
return { success: true, skipped: true };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const spinner = ora('Installing skill requirements...').start();
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
if (requirements.type === 'bash') {
|
|
92
|
+
// Execute installation script
|
|
93
|
+
spinner.text = `Running ${path.basename(requirements.scriptPath)}...`;
|
|
94
|
+
|
|
95
|
+
execSync(`bash "${requirements.scriptPath}"`, {
|
|
96
|
+
stdio: options.verbose ? 'inherit' : 'pipe',
|
|
97
|
+
cwd: path.dirname(requirements.scriptPath),
|
|
98
|
+
env: { ...process.env, TERM: 'dumb' } // Prevent interactive prompts
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
} else if (requirements.type === 'pip') {
|
|
102
|
+
// Install via pip
|
|
103
|
+
spinner.text = `Installing Python packages: ${requirements.packages.join(', ')}...`;
|
|
104
|
+
|
|
105
|
+
const packagesStr = requirements.packages.join(' ');
|
|
106
|
+
execSync(`${this.pythonCmd} -m pip install --user --break-system-packages ${packagesStr}`, {
|
|
107
|
+
stdio: options.verbose ? 'inherit' : 'pipe'
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
spinner.succeed(chalk.green('Requirements installed successfully'));
|
|
112
|
+
return { success: true };
|
|
113
|
+
|
|
114
|
+
} catch (error) {
|
|
115
|
+
spinner.fail(chalk.red('Requirements installation failed'));
|
|
116
|
+
|
|
117
|
+
console.error(chalk.yellow('\nā ļø Automatic installation failed'));
|
|
118
|
+
console.error(chalk.gray(`Error: ${error.message}`));
|
|
119
|
+
console.error(chalk.yellow('\nš” You can install requirements manually:'));
|
|
120
|
+
|
|
121
|
+
if (requirements.type === 'bash') {
|
|
122
|
+
console.error(chalk.gray(` bash ${requirements.scriptPath}`));
|
|
123
|
+
} else if (requirements.type === 'pip') {
|
|
124
|
+
console.error(chalk.gray(` pip install --user ${requirements.packages.join(' ')}`));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return { success: false, error: error.message };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Verify if Python package is installed
|
|
133
|
+
* @param {string} packageName - Package name to check
|
|
134
|
+
* @returns {Promise<boolean>} True if installed
|
|
135
|
+
*/
|
|
136
|
+
async isPackageInstalled(packageName) {
|
|
137
|
+
try {
|
|
138
|
+
execSync(`${this.pythonCmd} -c "import ${packageName}"`, {
|
|
139
|
+
stdio: 'pipe'
|
|
140
|
+
});
|
|
141
|
+
return true;
|
|
142
|
+
} catch {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Check status of requirements for installed skills
|
|
149
|
+
* @param {string} skillPath - Path to skill directory
|
|
150
|
+
* @returns {Promise<Object>} Status info
|
|
151
|
+
*/
|
|
152
|
+
async checkRequirementsStatus(skillPath) {
|
|
153
|
+
const requirements = await this.detectRequirements(skillPath);
|
|
154
|
+
|
|
155
|
+
if (!requirements.hasRequirements) {
|
|
156
|
+
return { hasRequirements: false, status: 'n/a' };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// For audio-transcriber, check if Whisper is installed
|
|
160
|
+
const skillName = path.basename(skillPath);
|
|
161
|
+
|
|
162
|
+
if (skillName === 'audio-transcriber') {
|
|
163
|
+
const whisperInstalled = await this.isPackageInstalled('whisper');
|
|
164
|
+
const fasterWhisperInstalled = await this.isPackageInstalled('faster_whisper');
|
|
165
|
+
|
|
166
|
+
let status = 'not-installed';
|
|
167
|
+
let details = [];
|
|
168
|
+
|
|
169
|
+
if (fasterWhisperInstalled) {
|
|
170
|
+
status = 'installed';
|
|
171
|
+
details.push('faster-whisper');
|
|
172
|
+
} else if (whisperInstalled) {
|
|
173
|
+
status = 'installed';
|
|
174
|
+
details.push('openai-whisper');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Check ffmpeg
|
|
178
|
+
try {
|
|
179
|
+
execSync('which ffmpeg', { stdio: 'pipe' });
|
|
180
|
+
details.push('ffmpeg');
|
|
181
|
+
} catch {
|
|
182
|
+
// ffmpeg not installed (optional)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
hasRequirements: true,
|
|
187
|
+
status,
|
|
188
|
+
details,
|
|
189
|
+
packages: fasterWhisperInstalled || whisperInstalled ? details : []
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// For other Python skills in the future
|
|
194
|
+
return {
|
|
195
|
+
hasRequirements: true,
|
|
196
|
+
status: 'unknown',
|
|
197
|
+
details: []
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
module.exports = RequirementsInstaller;
|