@juspay/neurolink 7.34.0 ā 7.36.0
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/CHANGELOG.md +12 -0
- package/README.md +64 -7
- package/dist/adapters/providerImageAdapter.d.ts +56 -0
- package/dist/adapters/providerImageAdapter.js +257 -0
- package/dist/cli/commands/config.d.ts +20 -20
- package/dist/cli/commands/setup-anthropic.d.ts +16 -0
- package/dist/cli/commands/setup-anthropic.js +414 -0
- package/dist/cli/commands/setup-azure.d.ts +17 -0
- package/dist/cli/commands/setup-azure.js +415 -0
- package/dist/cli/commands/setup-bedrock.d.ts +13 -0
- package/dist/cli/commands/setup-bedrock.js +487 -0
- package/dist/cli/commands/setup-gcp.d.ts +18 -0
- package/dist/cli/commands/setup-gcp.js +569 -0
- package/dist/cli/commands/setup-google-ai.d.ts +16 -0
- package/dist/cli/commands/setup-google-ai.js +369 -0
- package/dist/cli/commands/setup-huggingface.d.ts +8 -0
- package/dist/cli/commands/setup-huggingface.js +200 -0
- package/dist/cli/commands/setup-mistral.d.ts +8 -0
- package/dist/cli/commands/setup-mistral.js +233 -0
- package/dist/cli/commands/setup-openai.d.ts +16 -0
- package/dist/cli/commands/setup-openai.js +402 -0
- package/dist/cli/commands/setup.d.ts +19 -0
- package/dist/cli/commands/setup.js +539 -0
- package/dist/cli/factories/commandFactory.d.ts +5 -0
- package/dist/cli/factories/commandFactory.js +67 -3
- package/dist/cli/factories/setupCommandFactory.d.ts +18 -0
- package/dist/cli/factories/setupCommandFactory.js +137 -0
- package/dist/cli/parser.js +4 -1
- package/dist/cli/utils/envManager.d.ts +3 -2
- package/dist/cli/utils/envManager.js +18 -4
- package/dist/core/baseProvider.js +99 -45
- package/dist/core/types.d.ts +3 -0
- package/dist/lib/adapters/providerImageAdapter.d.ts +56 -0
- package/dist/lib/adapters/providerImageAdapter.js +257 -0
- package/dist/lib/core/baseProvider.js +99 -45
- package/dist/lib/core/types.d.ts +3 -0
- package/dist/lib/neurolink.js +8 -3
- package/dist/lib/types/content.d.ts +78 -0
- package/dist/lib/types/content.js +5 -0
- package/dist/lib/types/conversation.d.ts +19 -0
- package/dist/lib/types/generateTypes.d.ts +4 -1
- package/dist/lib/types/streamTypes.d.ts +6 -3
- package/dist/lib/utils/imageProcessor.d.ts +84 -0
- package/dist/lib/utils/imageProcessor.js +362 -0
- package/dist/lib/utils/messageBuilder.d.ts +8 -1
- package/dist/lib/utils/messageBuilder.js +279 -0
- package/dist/neurolink.js +8 -3
- package/dist/types/content.d.ts +78 -0
- package/dist/types/content.js +5 -0
- package/dist/types/conversation.d.ts +19 -0
- package/dist/types/generateTypes.d.ts +4 -1
- package/dist/types/streamTypes.d.ts +6 -3
- package/dist/utils/imageProcessor.d.ts +84 -0
- package/dist/utils/imageProcessor.js +362 -0
- package/dist/utils/messageBuilder.d.ts +8 -1
- package/dist/utils/messageBuilder.js +279 -0
- package/package.json +1 -1
@@ -0,0 +1,369 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
/**
|
3
|
+
* Google AI Studio Setup Command
|
4
|
+
*
|
5
|
+
* Simple setup for Google AI Studio (Google AI) integration:
|
6
|
+
* - GOOGLE_AI_API_KEY (required)
|
7
|
+
* - GOOGLE_AI_MODEL (optional, with recommended choices)
|
8
|
+
*
|
9
|
+
* Follows the same UX patterns as setup-openai and setup-gcp
|
10
|
+
*/
|
11
|
+
import path from "path";
|
12
|
+
import inquirer from "inquirer";
|
13
|
+
import chalk from "chalk";
|
14
|
+
import ora from "ora";
|
15
|
+
import { logger } from "../../lib/utils/logger.js";
|
16
|
+
import { GoogleAIModels } from "../../lib/types/providers.js";
|
17
|
+
import { updateEnvFile as updateEnvFileManager, displayEnvUpdateSummary, } from "../utils/envManager.js";
|
18
|
+
/**
|
19
|
+
* Get the runtime default model that matches the provider implementation
|
20
|
+
*/
|
21
|
+
function getRuntimeDefaultModel() {
|
22
|
+
return process.env.GOOGLE_AI_MODEL || GoogleAIModels.GEMINI_2_5_FLASH;
|
23
|
+
}
|
24
|
+
export async function handleGoogleAISetup(argv) {
|
25
|
+
try {
|
26
|
+
const options = {
|
27
|
+
checkOnly: argv.check || false,
|
28
|
+
interactive: !argv.nonInteractive,
|
29
|
+
};
|
30
|
+
logger.always(chalk.blue("š Checking Google AI Studio configuration..."));
|
31
|
+
// Step 1: Check for existing configuration
|
32
|
+
const hasApiKey = !!(process.env.GOOGLE_AI_API_KEY || process.env.GOOGLE_GENERATIVE_AI_API_KEY);
|
33
|
+
const hasModel = !!process.env.GOOGLE_AI_MODEL;
|
34
|
+
const currentApiKey = process.env.GOOGLE_AI_API_KEY || process.env.GOOGLE_GENERATIVE_AI_API_KEY;
|
35
|
+
// Display current status
|
36
|
+
displayCurrentStatus(hasApiKey, hasModel);
|
37
|
+
// Check-only mode - show status and exit
|
38
|
+
if (options.checkOnly) {
|
39
|
+
if (hasApiKey && currentApiKey) {
|
40
|
+
logger.always(chalk.green("ā
Google AI Studio setup complete"));
|
41
|
+
logger.always(` API Key: ${maskCredential(currentApiKey)}`);
|
42
|
+
if (hasModel) {
|
43
|
+
logger.always(` Model: ${process.env.GOOGLE_AI_MODEL}`);
|
44
|
+
}
|
45
|
+
else {
|
46
|
+
logger.always(` Model: ${getRuntimeDefaultModel()} (default)`);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
else {
|
50
|
+
logger.always(chalk.yellow("ā ļø Google AI Studio setup incomplete"));
|
51
|
+
}
|
52
|
+
return;
|
53
|
+
}
|
54
|
+
const config = {};
|
55
|
+
// Step 2: Handle existing configuration
|
56
|
+
if (hasApiKey && currentApiKey) {
|
57
|
+
logger.always(chalk.green("ā
Google AI Studio API key found in environment"));
|
58
|
+
logger.always(` API Key: ${maskCredential(currentApiKey)}`);
|
59
|
+
if (hasModel) {
|
60
|
+
logger.always(` Model: ${process.env.GOOGLE_AI_MODEL}`);
|
61
|
+
}
|
62
|
+
else {
|
63
|
+
logger.always(` Model: ${getRuntimeDefaultModel()} (default)`);
|
64
|
+
}
|
65
|
+
if (options.interactive) {
|
66
|
+
const { reconfigure } = await inquirer.prompt([
|
67
|
+
{
|
68
|
+
type: "confirm",
|
69
|
+
name: "reconfigure",
|
70
|
+
message: "Google AI Studio is already configured. Do you want to reconfigure?",
|
71
|
+
default: false,
|
72
|
+
},
|
73
|
+
]);
|
74
|
+
if (!reconfigure) {
|
75
|
+
// Still offer model selection if no model is set
|
76
|
+
if (!hasModel) {
|
77
|
+
const { wantsCustomModel } = await inquirer.prompt([
|
78
|
+
{
|
79
|
+
type: "confirm",
|
80
|
+
name: "wantsCustomModel",
|
81
|
+
message: "Do you want to specify a Google AI model? (optional)",
|
82
|
+
default: false,
|
83
|
+
},
|
84
|
+
]);
|
85
|
+
if (wantsCustomModel) {
|
86
|
+
config.model = await promptForModel();
|
87
|
+
}
|
88
|
+
}
|
89
|
+
else {
|
90
|
+
// Offer to change existing model
|
91
|
+
const { wantsChangeModel } = await inquirer.prompt([
|
92
|
+
{
|
93
|
+
type: "confirm",
|
94
|
+
name: "wantsChangeModel",
|
95
|
+
message: `Do you want to change the Google AI model? (current: ${process.env.GOOGLE_AI_MODEL})`,
|
96
|
+
default: false,
|
97
|
+
},
|
98
|
+
]);
|
99
|
+
if (wantsChangeModel) {
|
100
|
+
config.model = await promptForModel();
|
101
|
+
}
|
102
|
+
}
|
103
|
+
if (config.model) {
|
104
|
+
await updateEnvFile(config);
|
105
|
+
logger.always(chalk.green("ā
Model configuration updated!"));
|
106
|
+
logger.always(` GOOGLE_AI_MODEL=${config.model}`);
|
107
|
+
}
|
108
|
+
else {
|
109
|
+
logger.always(chalk.blue("š Keeping existing configuration."));
|
110
|
+
}
|
111
|
+
// Show usage example
|
112
|
+
showUsageExample();
|
113
|
+
return;
|
114
|
+
}
|
115
|
+
else {
|
116
|
+
// User chose to reconfigure - mark this for proper handling
|
117
|
+
logger.always(chalk.blue("š Reconfiguring Google AI Studio setup..."));
|
118
|
+
config.isReconfiguring = true;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
else {
|
122
|
+
// Non-interactive mode - just use existing credentials
|
123
|
+
logger.always(chalk.green("ā
Setup complete! Using existing Google AI Studio configuration."));
|
124
|
+
return;
|
125
|
+
}
|
126
|
+
}
|
127
|
+
// Step 3: Interactive setup for missing or reconfiguring credentials
|
128
|
+
if (options.interactive) {
|
129
|
+
const isReconfiguring = config.isReconfiguring === true;
|
130
|
+
// Handle API key setup/reconfiguration
|
131
|
+
if (!hasApiKey) {
|
132
|
+
// No API key exists - prompt for it
|
133
|
+
logger.always("");
|
134
|
+
logger.always(chalk.yellow("š To get your Google AI Studio API key:"));
|
135
|
+
logger.always("1. Visit: https://aistudio.google.com/app/apikey");
|
136
|
+
logger.always("2. Sign in with your Google account");
|
137
|
+
logger.always("3. Click 'Create API key' (free tier available)");
|
138
|
+
logger.always("4. Copy the API key (starts with AIza...)");
|
139
|
+
logger.always("");
|
140
|
+
const { apiKey } = await inquirer.prompt([
|
141
|
+
{
|
142
|
+
type: "password",
|
143
|
+
name: "apiKey",
|
144
|
+
message: "Enter your Google AI Studio API key:",
|
145
|
+
validate: validateApiKey,
|
146
|
+
},
|
147
|
+
]);
|
148
|
+
config.apiKey = apiKey.trim();
|
149
|
+
}
|
150
|
+
else if (isReconfiguring) {
|
151
|
+
// API key exists and user is reconfiguring - ask if they want to change it
|
152
|
+
const { wantsChangeApiKey } = await inquirer.prompt([
|
153
|
+
{
|
154
|
+
type: "confirm",
|
155
|
+
name: "wantsChangeApiKey",
|
156
|
+
message: `Do you want to change the Google AI Studio API key? (current: ${currentApiKey ? maskCredential(currentApiKey) : "****"})`,
|
157
|
+
default: false,
|
158
|
+
},
|
159
|
+
]);
|
160
|
+
if (wantsChangeApiKey) {
|
161
|
+
logger.always("");
|
162
|
+
logger.always(chalk.yellow("š To get your Google AI Studio API key:"));
|
163
|
+
logger.always("1. Visit: https://aistudio.google.com/app/apikey");
|
164
|
+
logger.always("2. Sign in with your Google account");
|
165
|
+
logger.always("3. Click 'Create API key' (free tier available)");
|
166
|
+
logger.always("4. Copy the API key (starts with AIza...)");
|
167
|
+
logger.always("");
|
168
|
+
const { apiKey } = await inquirer.prompt([
|
169
|
+
{
|
170
|
+
type: "password",
|
171
|
+
name: "apiKey",
|
172
|
+
message: "Enter your new Google AI Studio API key (replacing existing):",
|
173
|
+
validate: validateApiKey,
|
174
|
+
},
|
175
|
+
]);
|
176
|
+
config.apiKey = apiKey.trim();
|
177
|
+
}
|
178
|
+
}
|
179
|
+
// Prompt for model selection
|
180
|
+
const { wantsCustomModel } = await inquirer.prompt([
|
181
|
+
{
|
182
|
+
type: "confirm",
|
183
|
+
name: "wantsCustomModel",
|
184
|
+
message: hasModel
|
185
|
+
? `Do you want to change the Google AI model? (current: ${process.env.GOOGLE_AI_MODEL})`
|
186
|
+
: "Do you want to specify a Google AI model? (optional)",
|
187
|
+
default: false,
|
188
|
+
},
|
189
|
+
]);
|
190
|
+
if (wantsCustomModel) {
|
191
|
+
config.model = await promptForModel();
|
192
|
+
}
|
193
|
+
}
|
194
|
+
else {
|
195
|
+
// Non-interactive mode
|
196
|
+
logger.always(chalk.yellow("ā ļø Non-interactive mode: setup incomplete"));
|
197
|
+
logger.always(chalk.yellow("š” Run without --non-interactive to configure Google AI Studio"));
|
198
|
+
return;
|
199
|
+
}
|
200
|
+
// Step 4: Update .env file
|
201
|
+
if (config.apiKey || config.model) {
|
202
|
+
await updateEnvFile(config);
|
203
|
+
logger.always(chalk.green("ā
Google AI Studio setup complete!"));
|
204
|
+
if (config.apiKey) {
|
205
|
+
logger.always(` API Key: ${maskCredential(config.apiKey)}`);
|
206
|
+
}
|
207
|
+
if (config.model) {
|
208
|
+
logger.always(` Model: ${config.model}`);
|
209
|
+
}
|
210
|
+
// Show usage example
|
211
|
+
showUsageExample();
|
212
|
+
}
|
213
|
+
else if (options.interactive && !options.checkOnly) {
|
214
|
+
logger.always(chalk.green("ā
Setup complete!"));
|
215
|
+
showUsageExample();
|
216
|
+
}
|
217
|
+
}
|
218
|
+
catch (error) {
|
219
|
+
logger.error(chalk.red("ā Google AI Studio setup failed:"));
|
220
|
+
logger.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
|
221
|
+
process.exit(1);
|
222
|
+
}
|
223
|
+
}
|
224
|
+
/**
|
225
|
+
* Display current configuration status
|
226
|
+
*/
|
227
|
+
function displayCurrentStatus(hasApiKey, hasModel) {
|
228
|
+
if (hasApiKey) {
|
229
|
+
logger.always(chalk.green("ā Google AI Studio API key found in environment"));
|
230
|
+
}
|
231
|
+
else {
|
232
|
+
logger.always(chalk.red("ā Google AI Studio API key not found"));
|
233
|
+
}
|
234
|
+
if (hasModel) {
|
235
|
+
logger.always(chalk.green(`ā GOOGLE_AI_MODEL found: ${process.env.GOOGLE_AI_MODEL}`));
|
236
|
+
}
|
237
|
+
else {
|
238
|
+
logger.always(chalk.yellow(`ā GOOGLE_AI_MODEL not set (will use ${getRuntimeDefaultModel()} default)`));
|
239
|
+
}
|
240
|
+
}
|
241
|
+
/**
|
242
|
+
* Validate Google AI Studio API key format
|
243
|
+
*/
|
244
|
+
function validateApiKey(input) {
|
245
|
+
if (!input.trim()) {
|
246
|
+
return "Google AI Studio API key is required";
|
247
|
+
}
|
248
|
+
const trimmed = input.trim();
|
249
|
+
if (!trimmed.startsWith("AIza")) {
|
250
|
+
return "Google AI Studio API key should start with 'AIza'";
|
251
|
+
}
|
252
|
+
if (trimmed.length < 20) {
|
253
|
+
return "Google AI Studio API key seems too short";
|
254
|
+
}
|
255
|
+
// Basic format check: AIza[32+ char random string]
|
256
|
+
if (!/^AIza[a-zA-Z0-9_-]{20,}$/.test(trimmed)) {
|
257
|
+
return "Invalid Google AI Studio API key format";
|
258
|
+
}
|
259
|
+
return true;
|
260
|
+
}
|
261
|
+
/**
|
262
|
+
* Prompt user for model selection
|
263
|
+
*/
|
264
|
+
async function promptForModel() {
|
265
|
+
const { modelChoice } = await inquirer.prompt([
|
266
|
+
{
|
267
|
+
type: "list",
|
268
|
+
name: "modelChoice",
|
269
|
+
message: "Select a Google AI model:",
|
270
|
+
choices: [
|
271
|
+
{
|
272
|
+
name: "gemini-2.5-pro (Recommended - Latest high-capability model)",
|
273
|
+
value: "gemini-2.5-pro",
|
274
|
+
},
|
275
|
+
{
|
276
|
+
name: "gemini-2.5-flash (Fast and efficient)",
|
277
|
+
value: "gemini-2.5-flash",
|
278
|
+
},
|
279
|
+
{
|
280
|
+
name: "gemini-pro-vision (Multimodal - text and images)",
|
281
|
+
value: "gemini-pro-vision",
|
282
|
+
},
|
283
|
+
{
|
284
|
+
name: "gemini-pro (Previous generation)",
|
285
|
+
value: "gemini-pro",
|
286
|
+
},
|
287
|
+
{
|
288
|
+
name: "Custom model (enter manually)",
|
289
|
+
value: "custom",
|
290
|
+
},
|
291
|
+
],
|
292
|
+
},
|
293
|
+
]);
|
294
|
+
if (modelChoice === "custom") {
|
295
|
+
const { customModel } = await inquirer.prompt([
|
296
|
+
{
|
297
|
+
type: "input",
|
298
|
+
name: "customModel",
|
299
|
+
message: "Enter your custom Google AI model name:",
|
300
|
+
validate: (input) => {
|
301
|
+
if (!input.trim()) {
|
302
|
+
return "Model name is required";
|
303
|
+
}
|
304
|
+
// Basic validation - Google AI models typically follow certain patterns
|
305
|
+
const trimmed = input.trim();
|
306
|
+
if (!/^[a-z0-9-._]+$/i.test(trimmed)) {
|
307
|
+
return "Model name should contain only letters, numbers, hyphens, dots, and underscores";
|
308
|
+
}
|
309
|
+
return true;
|
310
|
+
},
|
311
|
+
},
|
312
|
+
]);
|
313
|
+
return customModel.trim();
|
314
|
+
}
|
315
|
+
return modelChoice;
|
316
|
+
}
|
317
|
+
/**
|
318
|
+
* Update .env file with Google AI Studio configuration
|
319
|
+
*/
|
320
|
+
async function updateEnvFile(config) {
|
321
|
+
const envPath = path.join(process.cwd(), ".env");
|
322
|
+
const spinner = ora("š¾ Updating .env file...").start();
|
323
|
+
try {
|
324
|
+
// Prepare environment variables to update
|
325
|
+
const envVars = {};
|
326
|
+
const keysToDelete = [];
|
327
|
+
if (config.apiKey) {
|
328
|
+
// Use GOOGLE_AI_API_KEY as the primary key
|
329
|
+
envVars.GOOGLE_AI_API_KEY = config.apiKey;
|
330
|
+
// Remove alternative key if it exists
|
331
|
+
keysToDelete.push("GOOGLE_GENERATIVE_AI_API_KEY");
|
332
|
+
}
|
333
|
+
if (config.model) {
|
334
|
+
envVars.GOOGLE_AI_MODEL = config.model;
|
335
|
+
}
|
336
|
+
// Update .env file using centralized envManager
|
337
|
+
const result = updateEnvFileManager(envVars, envPath, true, keysToDelete);
|
338
|
+
spinner.succeed(chalk.green("ā .env file updated successfully"));
|
339
|
+
// Display summary of changes (quietly, since we have our own success message)
|
340
|
+
displayEnvUpdateSummary(result, true);
|
341
|
+
}
|
342
|
+
catch (error) {
|
343
|
+
spinner.fail(chalk.red("ā Failed to update .env file"));
|
344
|
+
logger.error(chalk.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
345
|
+
throw error;
|
346
|
+
}
|
347
|
+
}
|
348
|
+
/**
|
349
|
+
* Mask API key for display
|
350
|
+
*/
|
351
|
+
function maskCredential(credential) {
|
352
|
+
if (!credential || credential.length < 8) {
|
353
|
+
return "****";
|
354
|
+
}
|
355
|
+
const start = credential.slice(0, 7); // Show 'AIza' plus a few chars
|
356
|
+
const end = credential.slice(-4);
|
357
|
+
const middle = "*".repeat(Math.max(4, credential.length - 11));
|
358
|
+
return `${start}${middle}${end}`;
|
359
|
+
}
|
360
|
+
/**
|
361
|
+
* Show usage example
|
362
|
+
*/
|
363
|
+
function showUsageExample() {
|
364
|
+
logger.always("");
|
365
|
+
logger.always(chalk.green("š You can now use Google AI Studio with the NeuroLink CLI:"));
|
366
|
+
logger.always(chalk.cyan(" pnpm cli generate 'Hello from Google AI!' --provider google-ai"));
|
367
|
+
logger.always(chalk.cyan(" pnpm cli generate 'Explain quantum computing' --provider google-ai"));
|
368
|
+
logger.always(chalk.cyan(" pnpm cli generate 'Analyze this data' --provider google-ai --enable-analytics"));
|
369
|
+
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import type { Arguments, CommandBuilder } from "yargs";
|
2
|
+
interface SetupHuggingFaceArgs {
|
3
|
+
check?: boolean;
|
4
|
+
"non-interactive"?: boolean;
|
5
|
+
}
|
6
|
+
export declare const handleHuggingFaceSetup: (argv: Arguments<SetupHuggingFaceArgs>) => Promise<void>;
|
7
|
+
export declare const setupHuggingFaceBuilder: CommandBuilder;
|
8
|
+
export {};
|
@@ -0,0 +1,200 @@
|
|
1
|
+
import chalk from "chalk";
|
2
|
+
import ora from "ora";
|
3
|
+
import inquirer from "inquirer";
|
4
|
+
import { logger } from "../../lib/utils/logger.js";
|
5
|
+
import { updateEnvFile as writeEnvFile, displayEnvUpdateSummary, } from "../utils/envManager.js";
|
6
|
+
/**
|
7
|
+
* Validates Hugging Face API key format
|
8
|
+
* Must start with "hf_" prefix
|
9
|
+
*/
|
10
|
+
function validateHuggingFaceApiKey(apiKey) {
|
11
|
+
return (typeof apiKey === "string" && apiKey.startsWith("hf_") && apiKey.length > 10);
|
12
|
+
}
|
13
|
+
/**
|
14
|
+
* Check current Hugging Face configuration
|
15
|
+
*/
|
16
|
+
function checkHuggingFaceConfig() {
|
17
|
+
const apiKey = process.env.HUGGINGFACE_API_KEY || process.env.HF_TOKEN;
|
18
|
+
const model = process.env.HUGGINGFACE_MODEL;
|
19
|
+
const hasApiKey = !!apiKey;
|
20
|
+
const hasModel = !!model;
|
21
|
+
const isValid = hasApiKey && validateHuggingFaceApiKey(apiKey);
|
22
|
+
return {
|
23
|
+
hasApiKey,
|
24
|
+
hasModel,
|
25
|
+
apiKey: apiKey ? `hf_${"*".repeat(6)}` : undefined,
|
26
|
+
model,
|
27
|
+
isValid,
|
28
|
+
};
|
29
|
+
}
|
30
|
+
export const handleHuggingFaceSetup = async (argv) => {
|
31
|
+
const spinner = ora();
|
32
|
+
try {
|
33
|
+
spinner.start("Checking Hugging Face configuration...");
|
34
|
+
const config = checkHuggingFaceConfig();
|
35
|
+
spinner.stop();
|
36
|
+
// Display current status
|
37
|
+
logger.always(chalk.bold.blue("\nš¤ Hugging Face Configuration Status\n"));
|
38
|
+
logger.always(`${config.hasApiKey ? "ā
" : "ā"} API Key: ${config.apiKey || "Not set"}`);
|
39
|
+
logger.always(`${config.hasModel ? "ā
" : "ā ļø"} Model: ${config.model || "Not set (will use default)"}`);
|
40
|
+
if (config.isValid) {
|
41
|
+
logger.always(chalk.green("\nā
Hugging Face is properly configured!"));
|
42
|
+
if (argv.check) {
|
43
|
+
return;
|
44
|
+
}
|
45
|
+
const { shouldReconfigure } = await inquirer.prompt([
|
46
|
+
{
|
47
|
+
type: "confirm",
|
48
|
+
name: "shouldReconfigure",
|
49
|
+
message: "Configuration looks good. Do you want to reconfigure anyway?",
|
50
|
+
default: false,
|
51
|
+
},
|
52
|
+
]);
|
53
|
+
if (!shouldReconfigure) {
|
54
|
+
logger.always(chalk.green("ā
Keeping existing configuration."));
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
else {
|
59
|
+
logger.always(chalk.yellow("\nā ļø Hugging Face configuration needs setup."));
|
60
|
+
if (argv.check) {
|
61
|
+
throw new Error("Hugging Face configuration is incomplete");
|
62
|
+
}
|
63
|
+
}
|
64
|
+
if (argv["non-interactive"]) {
|
65
|
+
logger.always(chalk.yellow("Non-interactive mode: Skipping configuration setup."));
|
66
|
+
logger.always(chalk.blue("Please set HUGGINGFACE_API_KEY manually."));
|
67
|
+
return;
|
68
|
+
}
|
69
|
+
// Interactive setup
|
70
|
+
logger.always(chalk.blue("\nš ļø Let's configure Hugging Face!\n"));
|
71
|
+
// Step 1: API Key
|
72
|
+
const { apiKey } = await inquirer.prompt([
|
73
|
+
{
|
74
|
+
type: "password",
|
75
|
+
name: "apiKey",
|
76
|
+
message: "Enter your Hugging Face API token:",
|
77
|
+
mask: "*",
|
78
|
+
validate: (input) => {
|
79
|
+
if (!input.trim()) {
|
80
|
+
return "API token is required";
|
81
|
+
}
|
82
|
+
if (!validateHuggingFaceApiKey(input.trim())) {
|
83
|
+
return "Invalid API token format. Must start with 'hf_'";
|
84
|
+
}
|
85
|
+
return true;
|
86
|
+
},
|
87
|
+
},
|
88
|
+
]);
|
89
|
+
// Step 2: Model Selection
|
90
|
+
const { modelChoice } = await inquirer.prompt([
|
91
|
+
{
|
92
|
+
type: "list",
|
93
|
+
name: "modelChoice",
|
94
|
+
message: "Select a Hugging Face model:",
|
95
|
+
choices: [
|
96
|
+
{
|
97
|
+
name: "Skip - use default (microsoft/DialoGPT-large)",
|
98
|
+
value: "default",
|
99
|
+
},
|
100
|
+
{
|
101
|
+
name: "microsoft/DialoGPT-large (Conversational AI - Recommended)",
|
102
|
+
value: "microsoft/DialoGPT-large",
|
103
|
+
},
|
104
|
+
{
|
105
|
+
name: "microsoft/DialoGPT-medium (Faster, smaller)",
|
106
|
+
value: "microsoft/DialoGPT-medium",
|
107
|
+
},
|
108
|
+
{
|
109
|
+
name: "facebook/blenderbot-400M-distill (General purpose)",
|
110
|
+
value: "facebook/blenderbot-400M-distill",
|
111
|
+
},
|
112
|
+
{
|
113
|
+
name: "microsoft/DialoGPT-small (Fastest)",
|
114
|
+
value: "microsoft/DialoGPT-small",
|
115
|
+
},
|
116
|
+
{
|
117
|
+
name: "Custom model name",
|
118
|
+
value: "custom",
|
119
|
+
},
|
120
|
+
],
|
121
|
+
default: "default",
|
122
|
+
},
|
123
|
+
]);
|
124
|
+
let selectedModel;
|
125
|
+
if (modelChoice === "custom") {
|
126
|
+
const { customModel } = await inquirer.prompt([
|
127
|
+
{
|
128
|
+
type: "input",
|
129
|
+
name: "customModel",
|
130
|
+
message: "Enter custom model name:",
|
131
|
+
validate: (input) => {
|
132
|
+
const trimmed = input.trim();
|
133
|
+
if (!trimmed) {
|
134
|
+
return "Model name is required";
|
135
|
+
}
|
136
|
+
if (!trimmed.includes("/")) {
|
137
|
+
return "Model name should include organization (e.g., 'microsoft/DialoGPT-large')";
|
138
|
+
}
|
139
|
+
return true;
|
140
|
+
},
|
141
|
+
},
|
142
|
+
]);
|
143
|
+
selectedModel = customModel.trim();
|
144
|
+
}
|
145
|
+
else if (modelChoice !== "default") {
|
146
|
+
selectedModel = modelChoice;
|
147
|
+
}
|
148
|
+
// If modelChoice === "default", selectedModel remains undefined
|
149
|
+
// Save configuration
|
150
|
+
spinner.start("Saving configuration...");
|
151
|
+
const updates = {
|
152
|
+
HUGGINGFACE_API_KEY: apiKey.trim(),
|
153
|
+
};
|
154
|
+
// Only set model if user didn't choose default
|
155
|
+
if (selectedModel) {
|
156
|
+
updates.HUGGINGFACE_MODEL = selectedModel;
|
157
|
+
}
|
158
|
+
try {
|
159
|
+
const result = writeEnvFile(updates);
|
160
|
+
spinner.stop();
|
161
|
+
// Display update summary
|
162
|
+
displayEnvUpdateSummary(result, false);
|
163
|
+
logger.always(chalk.green("\nā
Hugging Face configuration saved successfully!"));
|
164
|
+
}
|
165
|
+
catch (envError) {
|
166
|
+
spinner.stop();
|
167
|
+
throw new Error(`Failed to save configuration: ${envError instanceof Error ? envError.message : String(envError)}`);
|
168
|
+
}
|
169
|
+
logger.always(chalk.blue("\nš Usage examples:"));
|
170
|
+
logger.always(chalk.gray(' neurolink generate "Hello, how are you?" --provider huggingface'));
|
171
|
+
if (selectedModel) {
|
172
|
+
logger.always(chalk.gray(` neurolink generate "Tell me a story" --provider huggingface --model ${selectedModel}`));
|
173
|
+
}
|
174
|
+
else {
|
175
|
+
logger.always(chalk.gray(' neurolink generate "Tell me a story" --provider huggingface'));
|
176
|
+
logger.always(chalk.gray(' neurolink generate "Explain AI" --provider huggingface --model microsoft/DialoGPT-medium'));
|
177
|
+
}
|
178
|
+
logger.always(chalk.blue("\nš Resources:"));
|
179
|
+
logger.always(chalk.gray(" ⢠Hugging Face Models: https://huggingface.co/models"));
|
180
|
+
logger.always(chalk.gray(" ⢠API Documentation: https://huggingface.co/docs/api-inference"));
|
181
|
+
logger.always(chalk.gray(" ⢠Get API Token: https://huggingface.co/settings/tokens"));
|
182
|
+
}
|
183
|
+
catch (error) {
|
184
|
+
spinner.stop();
|
185
|
+
logger.error("Hugging Face setup failed", error);
|
186
|
+
throw error;
|
187
|
+
}
|
188
|
+
};
|
189
|
+
export const setupHuggingFaceBuilder = {
|
190
|
+
check: {
|
191
|
+
type: "boolean",
|
192
|
+
describe: "Only check existing configuration without prompting",
|
193
|
+
default: false,
|
194
|
+
},
|
195
|
+
"non-interactive": {
|
196
|
+
type: "boolean",
|
197
|
+
describe: "Skip interactive prompts",
|
198
|
+
default: false,
|
199
|
+
},
|
200
|
+
};
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import type { Arguments, CommandBuilder } from "yargs";
|
2
|
+
interface SetupMistralArgs {
|
3
|
+
check?: boolean;
|
4
|
+
"non-interactive"?: boolean;
|
5
|
+
}
|
6
|
+
export declare const handleMistralSetup: (argv: Arguments<SetupMistralArgs>) => Promise<void>;
|
7
|
+
export declare const setupMistralBuilder: CommandBuilder;
|
8
|
+
export {};
|