UNPKG

humanbehavior-js

Version:

SDK for HumanBehavior session and event recording

668 lines (582 loc) 19.8 kB
/** * Centralized AI Service Implementation * * This service runs on your backend infrastructure and provides AI-powered * code analysis without requiring users to provide their own API keys. * * The service can be deployed as: * - AWS Lambda function * - Docker container * - Express.js server * - Cloud function */ import { AICodeAnalysis } from '../ai/ai-install-wizard'; export interface FrameworkInfo { name: string; type: 'react' | 'vue' | 'angular' | 'svelte' | 'nextjs' | 'nuxt' | 'remix' | 'vanilla' | 'astro' | 'node'; bundler?: 'vite' | 'webpack' | 'esbuild' | 'rollup'; packageManager?: 'npm' | 'yarn' | 'pnpm'; hasTypeScript?: boolean; hasRouter?: boolean; projectRoot?: string; } export interface CentralizedAIServiceConfig { openaiApiKey: string; openaiModel?: string; maxTokens?: number; temperature?: number; enableCaching?: boolean; cacheTTL?: number; } export interface AIAnalysisRequest { codeSamples: string[]; projectType?: string; userAgent?: string; timestamp: string; } export interface AIAnalysisResponse { analysis: AICodeAnalysis; processingTime: number; cacheHit?: boolean; modelUsed: string; } export interface ConflictResolutionRequest { conflicts: string[]; framework: FrameworkInfo; codeContext?: string; } export interface OptimizationRequest { framework: FrameworkInfo; patterns: string[]; projectContext?: string; } /** * Centralized AI Service Implementation * This runs on your backend infrastructure */ export class CentralizedAIService { private config: CentralizedAIServiceConfig; private cache: Map<string, any> = new Map(); private openai: any; // OpenAI client constructor(config: CentralizedAIServiceConfig) { this.config = { openaiModel: 'gpt-4', maxTokens: 2000, temperature: 0.3, enableCaching: true, cacheTTL: 3600, // 1 hour ...config }; this.initializeOpenAI(); } /** * Initialize OpenAI client */ private initializeOpenAI() { try { // Import OpenAI dynamically to avoid bundling issues const { OpenAI } = require('openai'); this.openai = new OpenAI({ apiKey: this.config.openaiApiKey }); } catch (error) { console.warn('OpenAI not available, falling back to heuristic analysis'); this.openai = null; } } /** * Analyze code patterns using AI */ async analyzeCodePatterns(codeSamples: string[]): Promise<AICodeAnalysis> { const request: AIAnalysisRequest = { codeSamples, timestamp: new Date().toISOString() }; // Check cache first const cacheKey = this.generateCacheKey(request); if (this.config.enableCaching) { const cached = this.cache.get(cacheKey); if (cached && this.isCacheValid(cached.timestamp)) { return cached.analysis; } } // Perform AI analysis const startTime = Date.now(); const analysis = await this.performAIAnalysis(request); const processingTime = Date.now() - startTime; // Cache the result if (this.config.enableCaching) { this.cache.set(cacheKey, { analysis, timestamp: Date.now() }); } return analysis; } /** * Resolve conflicts using AI */ async resolveConflicts(conflicts: string[], framework: FrameworkInfo): Promise<string[]> { const request: ConflictResolutionRequest = { conflicts, framework, codeContext: 'HumanBehavior SDK integration' }; if (!this.openai) { return this.resolveConflictsHeuristic(conflicts, framework); } try { const prompt = this.buildConflictResolutionPrompt(request); const response = await this.openai.chat.completions.create({ model: this.config.openaiModel, messages: [ { role: 'system', content: 'You are an expert at resolving code integration conflicts. Provide specific resolution strategies.' }, { role: 'user', content: prompt } ], max_tokens: this.config.maxTokens, temperature: this.config.temperature }); const content = response.choices[0]?.message?.content; if (content && typeof content === 'string') { return this.parseConflictResolutions(content); } return []; } catch (error) { console.warn('AI conflict resolution failed, using heuristic approach:', error instanceof Error ? error.message : 'Unknown error'); } return this.resolveConflictsHeuristic(conflicts, framework); } /** * Generate optimizations using AI */ async generateOptimizations(framework: FrameworkInfo, patterns: string[]): Promise<string[]> { const request: OptimizationRequest = { framework, patterns, projectContext: 'HumanBehavior SDK integration' }; if (!this.openai) { return this.generateOptimizationsHeuristic(framework, patterns); } try { const prompt = this.buildOptimizationPrompt(request); const response = await this.openai.chat.completions.create({ model: this.config.openaiModel, messages: [ { role: 'system', content: 'You are an expert at optimizing code integration. Provide specific, actionable recommendations.' }, { role: 'user', content: prompt } ], max_tokens: this.config.maxTokens, temperature: this.config.temperature }); const content = response.choices[0]?.message?.content; if (content) { return this.parseOptimizations(content); } } catch (error) { console.warn('AI optimization generation failed, using heuristic approach:', error instanceof Error ? error.message : 'Unknown error'); } return this.generateOptimizationsHeuristic(framework, patterns); } /** * Perform AI analysis */ private async performAIAnalysis(request: AIAnalysisRequest): Promise<AICodeAnalysis> { if (!this.openai) { return this.performHeuristicAnalysis(request); } try { const prompt = this.buildAnalysisPrompt(request); const response = await this.openai.chat.completions.create({ model: this.config.openaiModel, messages: [ { role: 'system', content: 'You are an expert at analyzing code patterns and determining optimal integration strategies. Provide detailed analysis in JSON format.' }, { role: 'user', content: prompt } ], max_tokens: this.config.maxTokens, temperature: this.config.temperature, response_format: { type: 'json_object' } }); const content = response.choices[0]?.message?.content; if (content) { return this.parseAnalysisResult(content); } } catch (error) { console.warn('AI analysis failed, using heuristic approach:', error instanceof Error ? error.message : 'Unknown error'); } return this.performHeuristicAnalysis(request); } /** * Build analysis prompt */ private buildAnalysisPrompt(request: AIAnalysisRequest): string { return `Analyze these code samples to determine the framework and integration strategy: ${request.codeSamples.join('\n\n')} Provide analysis in JSON format with: - framework: { name, type, confidence (0-1) } - patterns: array of detected patterns - conflicts: array of potential conflicts - recommendations: array of integration recommendations - integrationStrategy: "provider" | "plugin" | "module" | "script" | "standalone" - compatibilityMode: "modern" | "legacy" | "hybrid" Focus on: 1. Framework detection beyond package.json 2. Code patterns and architecture 3. Integration compatibility 4. Future-proof strategies 5. Backward compatibility needs Respond with valid JSON only.`; } /** * Build conflict resolution prompt */ private buildConflictResolutionPrompt(request: ConflictResolutionRequest): string { return `Resolve these integration conflicts for ${request.framework.name}: Conflicts: ${request.conflicts.join(', ')} Framework: ${request.framework.name} (${request.framework.type}) Context: ${request.codeContext} Provide specific resolution strategies for each conflict. Options: - update_existing_integration: Update existing code - merge_providers: Merge multiple providers - hybrid_module_support: Support both module systems - skip_conflict: Skip the modification - custom_resolution: Custom resolution strategy Respond with a JSON array of resolution strategies.`; } /** * Build optimization prompt */ private buildOptimizationPrompt(request: OptimizationRequest): string { return `Generate optimizations for ${request.framework.name} integration: Framework: ${request.framework.name} (${request.framework.type}) Patterns: ${request.patterns.join(', ')} Context: ${request.projectContext} Provide specific, actionable optimization recommendations for: 1. Performance improvements 2. Error handling 3. Code organization 4. Future-proofing 5. Backward compatibility Respond with a JSON array of optimization recommendations.`; } /** * Parse analysis result */ private parseAnalysisResult(content: string): AICodeAnalysis { try { const result = JSON.parse(content); return { framework: result.framework || { name: 'vanilla', type: 'vanilla' }, confidence: result.confidence || 0.5, patterns: result.patterns || [], conflicts: result.conflicts || [], recommendations: result.recommendations || [], integrationStrategy: result.integrationStrategy || 'script', compatibilityMode: result.compatibilityMode || 'modern' }; } catch (error) { console.warn('Failed to parse AI analysis result:', error); return this.getDefaultAnalysis(); } } /** * Parse conflict resolutions */ private parseConflictResolutions(content: string): string[] { try { const result = JSON.parse(content); return Array.isArray(result) ? result : []; } catch (error) { console.warn('Failed to parse conflict resolutions:', error); return []; } } /** * Parse optimizations */ private parseOptimizations(content: string): string[] { try { const result = JSON.parse(content); return Array.isArray(result) ? result : []; } catch (error) { console.warn('Failed to parse optimizations:', error); return []; } } /** * Heuristic analysis fallback */ private performHeuristicAnalysis(request: AIAnalysisRequest): AICodeAnalysis { const patterns = request.codeSamples.join(' ').toLowerCase(); // Framework detection let framework: FrameworkInfo = { name: 'vanilla', type: 'vanilla' }; let confidence = 0.5; if (patterns.includes('react')) { framework = { name: 'react', type: 'react' }; confidence = 0.9; } else if (patterns.includes('vue')) { framework = { name: 'vue', type: 'vue' }; confidence = 0.9; } else if (patterns.includes('angular')) { framework = { name: 'angular', type: 'angular' }; confidence = 0.9; } else if (patterns.includes('svelte')) { framework = { name: 'svelte', type: 'svelte' }; confidence = 0.9; } else if (patterns.includes('next')) { framework = { name: 'nextjs', type: 'nextjs' }; confidence = 0.9; } else if (patterns.includes('nuxt')) { framework = { name: 'nuxt', type: 'nuxt' }; confidence = 0.9; } // Integration strategy let integrationStrategy: 'provider' | 'plugin' | 'module' | 'script' | 'standalone' = 'script'; if (framework.type === 'react' || framework.type === 'nextjs') { integrationStrategy = 'provider'; } else if (framework.type === 'vue') { integrationStrategy = 'plugin'; } else if (framework.type === 'angular') { integrationStrategy = 'module'; } // Compatibility mode let compatibilityMode: 'modern' | 'legacy' | 'hybrid' = 'modern'; if (patterns.includes('require(') || patterns.includes('var ')) { compatibilityMode = 'legacy'; } return { framework, confidence, patterns: request.codeSamples, conflicts: [], recommendations: [], integrationStrategy, compatibilityMode }; } /** * Heuristic conflict resolution */ private resolveConflictsHeuristic(conflicts: string[], framework: FrameworkInfo): string[] { const resolutions: string[] = []; for (const conflict of conflicts) { switch (conflict) { case 'existing_humanbehavior_code': resolutions.push('update_existing_integration'); break; case 'existing_provider': resolutions.push('merge_providers'); break; case 'module_system_conflict': resolutions.push('hybrid_module_support'); break; default: resolutions.push('skip_conflict'); } } return resolutions; } /** * Heuristic optimization generation */ private generateOptimizationsHeuristic(framework: FrameworkInfo, patterns: string[]): string[] { const optimizations: string[] = []; switch (framework.type) { case 'react': optimizations.push('Use React.memo for performance optimization'); optimizations.push('Implement error boundaries for better error tracking'); optimizations.push('Consider using React.lazy for code splitting'); break; case 'vue': optimizations.push('Use Vue 3 Composition API for better performance'); optimizations.push('Implement proper error handling in components'); optimizations.push('Consider using Vue Router for navigation tracking'); break; case 'angular': optimizations.push('Use Angular standalone components for better tree-shaking'); optimizations.push('Implement proper error handling with ErrorHandler'); optimizations.push('Consider using Angular signals for state management'); break; default: optimizations.push('Enable performance tracking'); optimizations.push('Implement error tracking'); optimizations.push('Consider progressive enhancement'); } return optimizations; } /** * Generate cache key */ private generateCacheKey(request: AIAnalysisRequest): string { const content = JSON.stringify(request); return Buffer.from(content).toString('base64').substring(0, 32); } /** * Check if cache is valid */ private isCacheValid(timestamp: number): boolean { const now = Date.now(); const ttl = (this.config.cacheTTL || 3600) * 1000; // Convert to milliseconds return (now - timestamp) < ttl; } /** * Get default analysis */ private getDefaultAnalysis(): AICodeAnalysis { return { framework: { name: 'vanilla', type: 'vanilla' }, confidence: 0.5, patterns: [], conflicts: [], recommendations: [], integrationStrategy: 'script', compatibilityMode: 'modern' }; } /** * Get service statistics */ getStats() { return { cacheSize: this.cache.size, config: { model: this.config.openaiModel, maxTokens: this.config.maxTokens, temperature: this.config.temperature, caching: this.config.enableCaching }, openaiAvailable: !!this.openai }; } /** * Clear cache */ clearCache() { this.cache.clear(); } } /** * Express.js server implementation */ export function createAIServiceServer(config: CentralizedAIServiceConfig) { const express = require('express'); const app = express(); const aiService = new CentralizedAIService(config); app.use(express.json()); // Health check endpoint app.get('/health', (req: any, res: any) => { res.json({ status: 'healthy', stats: aiService.getStats() }); }); // Analysis endpoint app.post('/analyze', async (req: any, res: any) => { try { const { codeSamples, projectType, userAgent } = req.body; if (!codeSamples || !Array.isArray(codeSamples)) { return res.status(400).json({ error: 'codeSamples array is required' }); } const startTime = Date.now(); const analysis = await aiService.analyzeCodePatterns(codeSamples); const processingTime = Date.now() - startTime; res.json({ analysis, processingTime, modelUsed: config.openaiModel || 'heuristic' }); } catch (error) { res.status(500).json({ error: 'Analysis failed', details: error instanceof Error ? error.message : 'Unknown error' }); } }); // Conflict resolution endpoint app.post('/resolve-conflicts', async (req: any, res: any) => { try { const { conflicts, framework } = req.body; if (!conflicts || !framework) { return res.status(400).json({ error: 'conflicts and framework are required' }); } const resolutions = await aiService.resolveConflicts(conflicts, framework); res.json({ resolutions }); } catch (error) { res.status(500).json({ error: 'Conflict resolution failed', details: error instanceof Error ? error.message : 'Unknown error' }); } }); // Optimization endpoint app.post('/optimize', async (req: any, res: any) => { try { const { framework, patterns } = req.body; if (!framework || !patterns) { return res.status(400).json({ error: 'framework and patterns are required' }); } const optimizations = await aiService.generateOptimizations(framework, patterns); res.json({ optimizations }); } catch (error) { res.status(500).json({ error: 'Optimization failed', details: error instanceof Error ? error.message : 'Unknown error' }); } }); return app; } /** * AWS Lambda handler */ export async function lambdaHandler(event: any, context: any) { const config: CentralizedAIServiceConfig = { openaiApiKey: process.env.OPENAI_API_KEY!, openaiModel: process.env.OPENAI_MODEL || 'gpt-4', maxTokens: parseInt(process.env.MAX_TOKENS || '2000'), temperature: parseFloat(process.env.TEMPERATURE || '0.3'), enableCaching: process.env.ENABLE_CACHING !== 'false', cacheTTL: parseInt(process.env.CACHE_TTL || '3600') }; const aiService = new CentralizedAIService(config); try { const { path, httpMethod, body } = event; const parsedBody = body ? JSON.parse(body) : {}; switch (path) { case '/analyze': if (httpMethod !== 'POST') { return { statusCode: 405, body: JSON.stringify({ error: 'Method not allowed' }) }; } const analysis = await aiService.analyzeCodePatterns(parsedBody.codeSamples || []); return { statusCode: 200, body: JSON.stringify({ analysis }) }; case '/resolve-conflicts': if (httpMethod !== 'POST') { return { statusCode: 405, body: JSON.stringify({ error: 'Method not allowed' }) }; } const resolutions = await aiService.resolveConflicts( parsedBody.conflicts || [], parsedBody.framework || { name: 'vanilla', type: 'vanilla' } ); return { statusCode: 200, body: JSON.stringify({ resolutions }) }; default: return { statusCode: 404, body: JSON.stringify({ error: 'Not found' }) }; } } catch (error) { return { statusCode: 500, body: JSON.stringify({ error: 'Internal server error', details: error instanceof Error ? error.message : 'Unknown error' }) }; } }