humanbehavior-js
Version:
SDK for HumanBehavior session and event recording
668 lines (582 loc) • 19.8 kB
text/typescript
/**
* 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' })
};
}
}