perf-lens
Version:
AI-powered frontend performance optimizer
134 lines (133 loc) • 4.39 kB
JavaScript
import fs from 'fs';
import path from 'path';
import os from 'os';
import { createAIModel } from '../ai/models.js';
// Configuration paths
const CONFIG_DIR = path.join(os.homedir(), '.perf-lens');
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
const DEFAULT_MODELS = {
openai: 'o3-mini',
anthropic: 'claude-3-5-haiku-20241022',
gemini: 'gemini-1.5-pro',
};
/**
* Ensures the configuration directory exists in the user's home directory
*/
function ensureConfigDir() {
if (!fs.existsSync(CONFIG_DIR)) {
fs.mkdirSync(CONFIG_DIR, { recursive: true });
}
}
/**
* Retrieves the current AI configuration from disk
* @returns {Config} The current configuration object
*/
function getConfig() {
try {
ensureConfigDir();
if (fs.existsSync(CONFIG_FILE)) {
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
}
}
catch (error) {
console.error('Error reading config:', error);
}
return {};
}
/**
* Saves the AI configuration to disk
* @param {Config} config - The configuration object to save
* @throws {Error} If saving the configuration fails
*/
function saveConfig(config) {
try {
ensureConfigDir();
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
}
catch (error) {
console.error('Error saving config:', error);
throw new Error('Failed to save configuration');
}
}
/**
* Sets the API key for a specific AI provider
* @param {string} key - The API key to set
* @param {AIProvider} provider - The AI provider to set the key for
* @throws {Error} If the provider is not supported
*/
export function setApiKey(key, provider) {
const config = getConfig();
switch (provider) {
case 'openai':
config.openaiApiKey = key;
break;
case 'anthropic':
config.anthropicApiKey = key;
break;
case 'gemini':
config.geminiApiKey = key;
break;
default:
throw new Error(`Unsupported AI provider: ${provider}`);
}
saveConfig(config);
}
/**
* Gets the API key for a specific AI provider from environment variables or config file
* @param {AIProvider} provider - The AI provider to get the key for
* @returns {string | undefined} The API key if found, undefined otherwise
* @throws {Error} If the provider is not supported
*/
export function getApiKey(provider) {
const config = getConfig();
switch (provider) {
case 'openai':
return process.env.PERF_LENS_OPENAI_API_KEY || config.openaiApiKey;
case 'anthropic':
return process.env.PERF_LENS_ANTHROPIC_API_KEY || config.anthropicApiKey;
case 'gemini':
return process.env.PERF_LENS_GEMINI_API_KEY || config.geminiApiKey;
default:
throw new Error(`Unsupported AI provider: ${provider}`);
}
}
/**
* Creates an AI model instance based on the provided configuration
* @param {AIModelConfig} config - The configuration for the AI model
* @returns {AIModel} The created AI model instance
* @throws {Error} If the API key is not found or the model creation fails
*/
export function createModel(config) {
const apiKey = getApiKey(config.provider);
if (!apiKey) {
throw new Error(`API key not found for ${config.provider}! Please set it using:\n` +
`perf-lens config set-key YOUR_API_KEY --provider ${config.provider}\n` +
`Or set the ${config.provider.toUpperCase()}_API_KEY environment variable.`);
}
return createAIModel({
...config,
apiKey,
});
}
/**
* Validates an API key for a specific AI provider by testing the connection
* @param {string} key - The API key to validate
* @param {AIProvider} provider - The AI provider to validate the key for
* @returns {Promise<boolean>} True if the key is valid, false otherwise
*/
export async function validateApiKey(key, provider) {
try {
const model = createModel({
provider,
model: DEFAULT_MODELS[provider],
apiKey: key,
});
// Test the API key with a simple prompt
await model.generateSuggestions('Test connection');
return true;
}
catch (error) {
console.error(`Error validating ${provider} API key:`, error);
return false;
}
}