UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio

386 lines 16.2 kB
#!/usr/bin/env node /** * Azure OpenAI Setup Command * * Setup for Azure OpenAI integration: * - AZURE_OPENAI_API_KEY (required) * - AZURE_OPENAI_ENDPOINT (required) * - AZURE_OPENAI_MODEL (optional) * * Follows the same UX patterns as other setup commands */ import inquirer from "inquirer"; import chalk from "chalk"; import ora from "ora"; import { logger } from "../../lib/utils/logger.js"; import { updateEnvFile as updateEnvFileShared, displayEnvUpdateSummary, } from "../utils/envManager.js"; import { getTopModelChoices } from "../../lib/utils/modelChoices.js"; import { AIProviderName, } from "../../lib/types/index.js"; import { maskCredential } from "../utils/maskCredential.js"; export async function handleAzureSetup(argv) { try { const options = { checkOnly: argv.check || false, interactive: !argv.nonInteractive, }; logger.always(chalk.blue("🔍 Checking Azure OpenAI configuration...")); // Step 1: Check for existing configuration const hasApiKey = !!process.env.AZURE_OPENAI_API_KEY; const hasEndpoint = !!process.env.AZURE_OPENAI_ENDPOINT; const hasModel = !!process.env.AZURE_OPENAI_MODEL; // Display current status displayCurrentStatus(hasApiKey, hasEndpoint, hasModel); // Check-only mode - show status and exit if (options.checkOnly) { if (hasApiKey && hasEndpoint) { logger.always(chalk.green("✅ Azure OpenAI setup complete")); const apiKey = process.env.AZURE_OPENAI_API_KEY; if (apiKey) { logger.always(` API Key: ${maskCredential(apiKey)}`); } logger.always(` Endpoint: ${process.env.AZURE_OPENAI_ENDPOINT}`); if (hasModel) { logger.always(` Model: ${process.env.AZURE_OPENAI_MODEL}`); } else { logger.always(" Model: (using deployment default)"); } } else { logger.always(chalk.yellow("⚠️ Azure OpenAI setup incomplete")); } return; } const config = {}; // Step 2: Handle existing configuration if (hasApiKey && hasEndpoint) { logger.always(chalk.green("✅ Azure OpenAI credentials found in environment")); const apiKey = process.env.AZURE_OPENAI_API_KEY; if (apiKey) { logger.always(` API Key: ${maskCredential(apiKey)}`); } logger.always(` Endpoint: ${process.env.AZURE_OPENAI_ENDPOINT}`); if (hasModel) { logger.always(` Model: ${process.env.AZURE_OPENAI_MODEL}`); } else { logger.always(" Model: (using deployment default)"); } if (options.interactive) { const { reconfigure } = await inquirer.prompt([ { type: "confirm", name: "reconfigure", message: "Azure OpenAI is already configured. Do you want to reconfigure?", default: false, }, ]); if (!reconfigure) { // Still offer model selection if no model is set if (!hasModel) { const { wantsCustomModel } = await inquirer.prompt([ { type: "confirm", name: "wantsCustomModel", message: "Do you want to specify an Azure OpenAI model? (optional)", default: false, }, ]); if (wantsCustomModel) { config.model = await promptForModel(); } } else { // Offer to change existing model const { wantsChangeModel } = await inquirer.prompt([ { type: "confirm", name: "wantsChangeModel", message: `Do you want to change the Azure OpenAI model? (current: ${process.env.AZURE_OPENAI_MODEL})`, default: false, }, ]); if (wantsChangeModel) { config.model = await promptForModel(); } } if (config.model) { await updateEnvFileWithConfig(config); logger.always(chalk.green("✅ Model configuration updated!")); logger.always(` AZURE_OPENAI_MODEL=${config.model}`); } else { logger.always(chalk.blue("👍 Keeping existing configuration.")); } // Show usage example showUsageExample(); return; } else { // User chose to reconfigure - mark this for proper handling logger.always(chalk.blue("📝 Reconfiguring Azure OpenAI setup...")); config.isReconfiguring = true; } } else { // Non-interactive mode - just use existing credentials logger.always(chalk.green("✅ Setup complete! Using existing Azure OpenAI configuration.")); return; } } // Step 3: Interactive setup for missing or reconfiguring credentials if (options.interactive) { const isReconfiguring = config.isReconfiguring === true; // Handle API key setup/reconfiguration if (!hasApiKey || isReconfiguring) { if (!hasApiKey) { // No API key exists - prompt for it logger.always(""); logger.always(chalk.yellow("📋 To get your Azure OpenAI credentials:")); logger.always("1. Visit: https://portal.azure.com/"); logger.always("2. Navigate to your Azure OpenAI resource"); logger.always("3. Go to 'Keys and Endpoint' section"); logger.always("4. Copy the API key and endpoint URL"); logger.always(""); } else if (isReconfiguring) { // Ask if they want to change the API key const apiKey = process.env.AZURE_OPENAI_API_KEY; const { wantsChangeApiKey } = await inquirer.prompt([ { type: "confirm", name: "wantsChangeApiKey", message: `Do you want to change the Azure OpenAI API key? (current: ${apiKey ? maskCredential(apiKey) : "****"})`, default: false, }, ]); if (!wantsChangeApiKey) { config.apiKey = undefined; // Don't update the API key } } if (!hasApiKey || (isReconfiguring && config.apiKey !== undefined)) { const { apiKey } = await inquirer.prompt([ { type: "password", name: "apiKey", message: isReconfiguring ? "Enter your new Azure OpenAI API key:" : "Enter your Azure OpenAI API key:", validate: validateApiKey, }, ]); config.apiKey = apiKey.trim(); } } // Handle endpoint setup/reconfiguration if (!hasEndpoint || isReconfiguring) { if (isReconfiguring && hasEndpoint) { const { wantsChangeEndpoint } = await inquirer.prompt([ { type: "confirm", name: "wantsChangeEndpoint", message: `Do you want to change the Azure OpenAI endpoint? (current: ${process.env.AZURE_OPENAI_ENDPOINT})`, default: false, }, ]); if (!wantsChangeEndpoint) { config.endpoint = undefined; // Don't update the endpoint } } if (!hasEndpoint || (isReconfiguring && config.endpoint !== undefined)) { const { endpoint } = await inquirer.prompt([ { type: "input", name: "endpoint", message: isReconfiguring ? "Enter your new Azure OpenAI endpoint URL:" : "Enter your Azure OpenAI endpoint URL:", validate: validateEndpoint, }, ]); config.endpoint = endpoint.trim(); } } // Prompt for model selection const { wantsCustomModel } = await inquirer.prompt([ { type: "confirm", name: "wantsCustomModel", message: hasModel ? `Do you want to change the Azure OpenAI model? (current: ${process.env.AZURE_OPENAI_MODEL})` : "Do you want to specify an Azure OpenAI model? (optional)", default: false, }, ]); if (wantsCustomModel) { config.model = await promptForModel(); } } else { // Non-interactive mode logger.always(chalk.yellow("⚠️ Non-interactive mode: setup incomplete")); logger.always(chalk.yellow("💡 Run without --non-interactive to configure Azure OpenAI")); return; } // Step 4: Update .env file if (config.apiKey || config.endpoint || config.model) { await updateEnvFileWithConfig(config); logger.always(chalk.green("✅ Azure OpenAI setup complete!")); if (config.apiKey) { logger.always(` API Key: ${maskCredential(config.apiKey)}`); } if (config.endpoint) { logger.always(` Endpoint: ${config.endpoint}`); } if (config.model) { logger.always(` Model: ${config.model}`); } // Show usage example showUsageExample(); } else if (options.interactive && !options.checkOnly) { logger.always(chalk.green("✅ Setup complete!")); showUsageExample(); } } catch (error) { logger.error(chalk.red("❌ Azure OpenAI setup failed:")); logger.error(chalk.red(error instanceof Error ? error.message : "Unknown error")); process.exit(1); } } /** * Display current configuration status */ function displayCurrentStatus(hasApiKey, hasEndpoint, hasModel) { if (hasApiKey) { logger.always(chalk.green("✔ AZURE_OPENAI_API_KEY found in environment")); } else { logger.always(chalk.red("✘ AZURE_OPENAI_API_KEY not found")); } if (hasEndpoint) { logger.always(chalk.green(`✔ AZURE_OPENAI_ENDPOINT found: ${process.env.AZURE_OPENAI_ENDPOINT}`)); } else { logger.always(chalk.red("✘ AZURE_OPENAI_ENDPOINT not found")); } if (hasModel) { logger.always(chalk.green(`✔ AZURE_OPENAI_MODEL found: ${process.env.AZURE_OPENAI_MODEL}`)); } else { logger.always(chalk.yellow("⚠ AZURE_OPENAI_MODEL not set (will use deployment default)")); } } /** * Validate Azure OpenAI API key format */ function validateApiKey(input) { if (!input.trim()) { return "Azure OpenAI API key is required"; } const trimmed = input.trim(); if (trimmed.length < 20) { return "Azure OpenAI API key seems too short"; } // Azure OpenAI keys are typically 32 character hex strings if (!/^[a-f0-9]{32}$/i.test(trimmed)) { return "Azure OpenAI API key should be a 32-character hexadecimal string"; } return true; } /** * Validate Azure OpenAI endpoint URL */ function validateEndpoint(input) { if (!input.trim()) { return "Azure OpenAI endpoint URL is required"; } const trimmed = input.trim(); try { const url = new URL(trimmed); if (!url.hostname.includes("openai.azure.com")) { return "Endpoint should be an Azure OpenAI URL (*.openai.azure.com)"; } return true; } catch { return "Invalid URL format. Should be like: https://your-resource.openai.azure.com/"; } } /** * Prompt user for model selection */ async function promptForModel() { const { modelChoice } = await inquirer.prompt([ { type: "select", name: "modelChoice", message: "Select an Azure OpenAI model:", choices: getTopModelChoices(AIProviderName.AZURE, 5), }, ]); if (modelChoice === "custom") { const { customModel } = await inquirer.prompt([ { type: "input", name: "customModel", message: "Enter your Azure OpenAI deployment name:", validate: (input) => { if (!input.trim()) { return "Deployment name is required"; } // Basic validation - Azure deployment names are alphanumeric with hyphens const trimmed = input.trim(); if (!/^[a-z0-9-]+$/i.test(trimmed)) { return "Deployment name should contain only letters, numbers, and hyphens"; } return true; }, }, ]); return customModel.trim(); } return modelChoice; } /** * Update .env file with Azure OpenAI configuration using shared utilities */ async function updateEnvFileWithConfig(config) { const spinner = ora("💾 Updating .env file...").start(); try { // Prepare environment variables for the shared utility const newVars = {}; if (config.apiKey) { newVars.AZURE_OPENAI_API_KEY = config.apiKey; } if (config.endpoint) { newVars.AZURE_OPENAI_ENDPOINT = config.endpoint; } if (config.model) { newVars.AZURE_OPENAI_MODEL = config.model; } // Use shared envManager utility with backup enabled const result = updateEnvFileShared(newVars, ".env", true); spinner.succeed(chalk.green("✔ .env file updated successfully")); // Display summary using shared utility displayEnvUpdateSummary(result, false); } catch (error) { spinner.fail(chalk.red("❌ Failed to update .env file")); logger.error(chalk.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`)); throw error; } } /** * Show usage example */ function showUsageExample() { logger.always(""); logger.always(chalk.green("🚀 You can now use Azure OpenAI with the NeuroLink CLI:")); logger.always(chalk.cyan(" pnpm cli generate 'Hello from Azure OpenAI!' --provider azure")); logger.always(chalk.cyan(" pnpm cli generate 'Explain quantum computing' --provider azure")); logger.always(chalk.cyan(" pnpm cli generate 'Analyze this data' --provider azure --enable-analytics")); } //# sourceMappingURL=setup-azure.js.map