UNPKG

capsule-ai-cli

Version:

The AI Model Orchestrator - Intelligent multi-model workflows with device-locked licensing

170 lines • 6.62 kB
import chalk from 'chalk'; import { v4 as uuidv4 } from 'uuid'; import { serviceLocator } from './service-locator.js'; export class ChatService { messages = []; currentModel = 'gpt-4o'; sessionId = uuidv4(); startTime = new Date(); async initialize() { try { const licenseService = serviceLocator.getLicense(); const { valid, license } = await licenseService.validate(); if (!valid) { console.log(chalk.yellow('\nšŸŽ Using Capsule CLI Free Edition')); console.log(chalk.dim('Upgrade to Pro for advanced features: Model Fusion, Smart Router, and more!')); console.log(chalk.dim('Learn more: capsule activate <license-key>\n')); } else { console.log(chalk.green(`\n✨ Capsule CLI ${license.tier.toUpperCase()} Edition`)); } const analytics = await serviceLocator.getAnalytics(); analytics.track({ event: 'session_start', sessionId: this.sessionId, timestamp: new Date(), properties: { edition: license?.tier || 'free' } }); const router = await serviceLocator.getModelRouter(); const models = await router.listAvailableModels(); if (models.length === 0) { return { success: false, error: 'No AI providers configured. Set API keys for OpenAI, Anthropic, or other providers.' }; } return { success: true }; } catch (error) { return { success: false, error: `Failed to initialize: ${error.message}` }; } } async sendMessage(content, options = {}) { const startTime = Date.now(); this.messages.push({ role: 'user', content }); try { const router = await serviceLocator.getModelRouter(); const analytics = await serviceLocator.getAnalytics(); const config = serviceLocator.getConfig(); const estimate = await router.estimateCost({ model: this.currentModel, messages: this.messages, stream: options.stream }); if (config.get('ui.showCosts')) { console.log(chalk.dim(`\nEstimated cost: ~$${estimate.estimatedCost.toFixed(4)}...`)); } const response = await router.route({ model: this.currentModel, messages: this.messages, stream: options.stream }); console.log(chalk.cyan('\nšŸ¤– Assistant:')); console.log(response.content); console.log(); this.messages.push({ role: 'assistant', content: response.content }); const duration = Date.now() - startTime; await analytics.track({ event: 'model_completion', sessionId: this.sessionId, timestamp: new Date(), properties: { model: this.currentModel, provider: response.provider, promptTokens: response.usage.promptTokens, completionTokens: response.usage.completionTokens, totalTokens: response.usage.totalTokens, cost: estimate.estimatedCost, duration } }); if (config.get('ui.showCosts')) { console.log(chalk.gray(`Cost: $${estimate.estimatedCost.toFixed(4)} | ` + `Tokens: ${response.usage.totalTokens} | ` + `Time: ${(duration / 1000).toFixed(1)}s`)); } } catch (error) { console.log(chalk.red('\nāŒ Error:'), error.message); const analytics = await serviceLocator.getAnalytics(); await analytics.track({ event: 'error', sessionId: this.sessionId, timestamp: new Date(), properties: { error: error.message, model: this.currentModel } }); if (error.message.includes('401')) { console.log(chalk.yellow('Invalid API key. Please check your API keys.')); } else if (error.message.includes('429')) { console.log(chalk.yellow('Rate limit exceeded. Please try again later.')); } else if (error.message.includes('network')) { console.log(chalk.yellow('Network error. Please check your connection.')); } } } clearHistory() { this.messages = []; console.log(chalk.green('āœ“ Conversation history cleared')); } async showStats() { const analytics = await serviceLocator.getAnalytics(); const insights = await analytics.getInsights('week'); console.log(chalk.cyan('\nšŸ“Š Weekly Usage Stats:')); console.log(chalk.dim('━'.repeat(40))); console.log(`Sessions: ${insights.totalSessions}`); console.log(`Queries: ${insights.totalQueries}`); console.log(`Avg Response Time: ${(insights.averageResponseTime / 1000).toFixed(1)}s`); console.log(chalk.dim('━'.repeat(40))); console.log('\nTop Models:'); Object.entries(insights.modelUsage) .sort(([, a], [, b]) => b - a) .slice(0, 3) .forEach(([model, count]) => { console.log(` ${model}: ${count} requests`); }); console.log(); } async cleanup() { const analytics = await serviceLocator.getAnalytics(); await analytics.track({ event: 'session_end', sessionId: this.sessionId, timestamp: new Date(), properties: { duration: Date.now() - this.startTime.getTime(), messageCount: this.messages.length } }); } setModel(model) { this.currentModel = model; console.log(chalk.green(`āœ“ Model set to: ${model}`)); } getHistory() { return this.messages; } addSystemMessage(content) { this.messages.push({ role: 'system', content }); } } export const chatService = new ChatService(); //# sourceMappingURL=chat-service.js.map