@neuroequality/neuroadapt-ai
Version:
AI-powered accessibility personalization for neurodivergent users
1 lines • 20.1 kB
Source Map (JSON)
{"version":3,"file":"content-adapter-ZmHfMI1P.cjs","sources":["../src/streaming/content-adapter.ts"],"sourcesContent":["import { EventEmitter } from 'eventemitter3';\nimport type { \n StreamChunk, \n AdaptationSuggestion,\n UserInteraction \n} from '../types/common.js';\n\n/**\n * Events emitted by ContentAdapter\n */\nexport interface ContentAdapterEvents {\n 'content-processed': (result: ProcessedContent) => void;\n 'adaptation-suggested': (suggestion: AdaptationSuggestion) => void;\n 'chunk-processed': (chunk: ProcessedChunk) => void;\n 'processing-complete': (summary: ProcessingSummary) => void;\n 'error': (error: Error) => void;\n}\n\n/**\n * Configuration for content adaptation\n */\nexport interface ContentAdapterConfig {\n chunkSize?: number;\n processingDelay?: number;\n enableRealTimeAnalysis?: boolean;\n adaptationThreshold?: number;\n maxConcurrentChunks?: number;\n retryAttempts?: number;\n}\n\n/**\n * Processed content result\n */\nexport interface ProcessedContent {\n id: string;\n originalContent: string;\n adaptedContent: string;\n adaptations: string[];\n confidence: number;\n processingTime: number;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Processed chunk information\n */\nexport interface ProcessedChunk {\n id: string;\n chunkIndex: number;\n content: string;\n adaptations: string[];\n confidence: number;\n timestamp: number;\n}\n\n/**\n * Processing summary\n */\nexport interface ProcessingSummary {\n totalChunks: number;\n processedChunks: number;\n failedChunks: number;\n totalAdaptations: number;\n averageConfidence: number;\n totalProcessingTime: number;\n suggestedImprovements: string[];\n}\n\n/**\n * Content processing queue item\n */\ninterface QueueItem {\n id: string;\n content: string;\n preferences: Record<string, unknown>;\n context?: Record<string, unknown>;\n timestamp: number;\n retries: number;\n}\n\n/**\n * ContentAdapter provides real-time content adaptation and streaming processing\n */\nexport class ContentAdapter extends EventEmitter<ContentAdapterEvents> {\n private config: Required<ContentAdapterConfig>;\n private processingQueue: QueueItem[] = [];\n private activeProcessing: Map<string, Promise<void>> = new Map();\n private adaptationCache: Map<string, ProcessedContent> = new Map();\n private processingStats: ProcessingSummary;\n\n constructor(config: ContentAdapterConfig = {}) {\n super();\n \n this.config = {\n chunkSize: config.chunkSize || 500, // characters\n processingDelay: config.processingDelay || 100, // ms\n enableRealTimeAnalysis: config.enableRealTimeAnalysis ?? true,\n adaptationThreshold: config.adaptationThreshold || 0.7,\n maxConcurrentChunks: config.maxConcurrentChunks || 3,\n retryAttempts: config.retryAttempts || 2,\n };\n\n this.processingStats = this.createEmptyStats();\n this.startProcessingLoop();\n }\n\n /**\n * Process content with user preferences\n */\n async processContent(\n content: string,\n preferences: Record<string, unknown>,\n context?: Record<string, unknown>\n ): Promise<ProcessedContent> {\n const startTime = Date.now();\n const contentId = this.generateContentId(content);\n\n // Check cache first\n const cached = this.adaptationCache.get(contentId);\n if (cached) {\n return cached;\n }\n\n try {\n const adaptedContent = await this.adaptContent(content, preferences, context);\n const adaptations = this.detectAppliedAdaptations(content, adaptedContent, preferences);\n \n const result: ProcessedContent = {\n id: contentId,\n originalContent: content,\n adaptedContent,\n adaptations,\n confidence: this.calculateConfidence(adaptations, preferences),\n processingTime: Date.now() - startTime,\n metadata: {\n preferences,\n context,\n timestamp: Date.now(),\n },\n };\n\n // Cache result\n this.adaptationCache.set(contentId, result);\n \n // Limit cache size\n if (this.adaptationCache.size > 100) {\n const firstKey = this.adaptationCache.keys().next().value;\n this.adaptationCache.delete(firstKey);\n }\n\n this.emit('content-processed', result);\n return result;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.emit('error', err);\n throw err;\n }\n }\n\n /**\n * Process streaming content chunks\n */\n async processStreamChunks(\n chunks: AsyncGenerator<StreamChunk, void, unknown>,\n preferences: Record<string, unknown>,\n context?: Record<string, unknown>\n ): Promise<void> {\n let buffer = '';\n let chunkIndex = 0;\n const startTime = Date.now();\n\n try {\n for await (const chunk of chunks) {\n if (chunk.type === 'token') {\n buffer += chunk.content;\n \n // Process complete sentences or chunks\n if (this.shouldProcessBuffer(buffer)) {\n const processedChunk = await this.processChunk(\n buffer,\n chunkIndex++,\n preferences,\n context\n );\n \n this.emit('chunk-processed', processedChunk);\n buffer = '';\n }\n } else if (chunk.type === 'done') {\n // Process remaining buffer\n if (buffer.trim()) {\n const processedChunk = await this.processChunk(\n buffer,\n chunkIndex++,\n preferences,\n context\n );\n \n this.emit('chunk-processed', processedChunk);\n }\n \n // Emit completion summary\n const summary: ProcessingSummary = {\n ...this.processingStats,\n totalProcessingTime: Date.now() - startTime,\n };\n \n this.emit('processing-complete', summary);\n break;\n } else if (chunk.type === 'error') {\n throw new Error(`Stream error: ${chunk.content}`);\n }\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.emit('error', err);\n throw err;\n }\n }\n\n /**\n * Add content to processing queue\n */\n queueContent(\n content: string,\n preferences: Record<string, unknown>,\n context?: Record<string, unknown>\n ): string {\n const id = this.generateContentId(content);\n \n const queueItem: QueueItem = {\n id,\n content,\n preferences,\n context,\n timestamp: Date.now(),\n retries: 0,\n };\n\n this.processingQueue.push(queueItem);\n return id;\n }\n\n /**\n * Get processing statistics\n */\n getProcessingStats(): ProcessingSummary {\n return { ...this.processingStats };\n }\n\n /**\n * Clear adaptation cache\n */\n clearCache(): void {\n this.adaptationCache.clear();\n }\n\n /**\n * Get cache information\n */\n getCacheInfo(): { size: number; keys: string[] } {\n return {\n size: this.adaptationCache.size,\n keys: Array.from(this.adaptationCache.keys()),\n };\n }\n\n /**\n * Stop processing and clean up\n */\n destroy(): void {\n this.processingQueue = [];\n this.activeProcessing.clear();\n this.adaptationCache.clear();\n this.removeAllListeners();\n }\n\n // Private methods\n\n private generateContentId(content: string): string {\n // Simple hash function for content ID\n let hash = 0;\n for (let i = 0; i < content.length; i++) {\n const char = content.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash; // Convert to 32-bit integer\n }\n return `content_${Math.abs(hash)}_${Date.now()}`;\n }\n\n private async adaptContent(\n content: string,\n preferences: Record<string, unknown>,\n context?: Record<string, unknown>\n ): Promise<string> {\n let adaptedContent = content;\n\n // Apply various adaptations based on preferences\n if (preferences.highContrast) {\n adaptedContent = this.applyHighContrastAdaptation(adaptedContent);\n }\n\n if (preferences.motionReduction) {\n adaptedContent = this.applyMotionReductionAdaptation(adaptedContent);\n }\n\n if (typeof preferences.fontSize === 'number' && preferences.fontSize !== 1) {\n adaptedContent = this.applyFontSizeAdaptation(adaptedContent, preferences.fontSize);\n }\n\n if (typeof preferences.chunkSize === 'number' && preferences.chunkSize < 4) {\n adaptedContent = await this.applyContentChunking(adaptedContent, preferences.chunkSize);\n }\n\n if (preferences.simplifyLanguage) {\n adaptedContent = await this.applyLanguageSimplification(adaptedContent);\n }\n\n return adaptedContent;\n }\n\n private applyHighContrastAdaptation(content: string): string {\n // Add high contrast markers for styling\n return content.replace(\n /<(p|div|span|h[1-6])([^>]*)>/gi,\n '<$1$2 data-high-contrast=\"true\">'\n );\n }\n\n private applyMotionReductionAdaptation(content: string): string {\n // Remove or disable animations and auto-playing content\n return content\n .replace(/autoplay/gi, 'data-autoplay-disabled')\n .replace(/animation-/gi, 'data-animation-disabled-')\n .replace(/<video([^>]*)\\s+autoplay/gi, '<video$1 data-motion-reduced');\n }\n\n private applyFontSizeAdaptation(content: string, fontSize: number): string {\n const percentageSize = Math.round(fontSize * 100);\n return content.replace(\n /<(p|div|span|h[1-6])([^>]*)>/gi,\n `<$1$2 style=\"font-size: ${percentageSize}%\">`\n );\n }\n\n private async applyContentChunking(content: string, chunkSize: number): Promise<string> {\n const sentences = content.split(/[.!?]+/).filter(s => s.trim());\n const chunks: string[] = [];\n \n for (let i = 0; i < sentences.length; i += chunkSize) {\n const chunk = sentences.slice(i, i + chunkSize).join('. ');\n chunks.push(`<div class=\"content-chunk\">${chunk}</div>`);\n }\n \n return chunks.join('\\n<div class=\"chunk-break\"></div>\\n');\n }\n\n private async applyLanguageSimplification(content: string): Promise<string> {\n // Simplified language processing - in real implementation, this would use AI\n return content\n .replace(/utilize/gi, 'use')\n .replace(/demonstrate/gi, 'show')\n .replace(/accomplish/gi, 'do')\n .replace(/nevertheless/gi, 'but')\n .replace(/consequently/gi, 'so');\n }\n\n private detectAppliedAdaptations(\n original: string,\n adapted: string,\n preferences: Record<string, unknown>\n ): string[] {\n const adaptations: string[] = [];\n \n if (adapted.includes('data-high-contrast')) {\n adaptations.push('High contrast styling applied');\n }\n \n if (adapted.includes('data-motion-reduced')) {\n adaptations.push('Motion reduction applied');\n }\n \n if (adapted.includes('font-size:')) {\n adaptations.push('Font size adjustment applied');\n }\n \n if (adapted.includes('content-chunk')) {\n adaptations.push('Content chunking applied');\n }\n \n if (original !== adapted && adaptations.length === 0) {\n adaptations.push('Language simplification applied');\n }\n \n return adaptations;\n }\n\n private calculateConfidence(\n adaptations: string[],\n preferences: Record<string, unknown>\n ): number {\n // Simple confidence calculation based on applied adaptations\n const maxPossibleAdaptations = Object.keys(preferences).length;\n const appliedAdaptations = adaptations.length;\n \n return Math.min(appliedAdaptations / Math.max(maxPossibleAdaptations, 1), 1);\n }\n\n private shouldProcessBuffer(buffer: string): boolean {\n // Process buffer when it reaches chunk size or contains complete sentences\n return buffer.length >= this.config.chunkSize || \n /[.!?]\\s/.test(buffer) ||\n buffer.includes('\\n\\n');\n }\n\n private async processChunk(\n content: string,\n chunkIndex: number,\n preferences: Record<string, unknown>,\n context?: Record<string, unknown>\n ): Promise<ProcessedChunk> {\n const adaptedContent = await this.adaptContent(content, preferences, context);\n const adaptations = this.detectAppliedAdaptations(content, adaptedContent, preferences);\n \n this.processingStats.processedChunks++;\n this.processingStats.totalAdaptations += adaptations.length;\n \n return {\n id: `chunk_${chunkIndex}`,\n chunkIndex,\n content: adaptedContent,\n adaptations,\n confidence: this.calculateConfidence(adaptations, preferences),\n timestamp: Date.now(),\n };\n }\n\n private startProcessingLoop(): void {\n setInterval(() => {\n this.processQueue();\n }, this.config.processingDelay);\n }\n\n private async processQueue(): Promise<void> {\n if (this.processingQueue.length === 0 || \n this.activeProcessing.size >= this.config.maxConcurrentChunks) {\n return;\n }\n\n const item = this.processingQueue.shift();\n if (!item) return;\n\n const processingPromise = this.processQueueItem(item);\n this.activeProcessing.set(item.id, processingPromise);\n\n try {\n await processingPromise;\n } finally {\n this.activeProcessing.delete(item.id);\n }\n }\n\n private async processQueueItem(item: QueueItem): Promise<void> {\n try {\n const result = await this.processContent(item.content, item.preferences, item.context);\n this.processingStats.totalChunks++;\n } catch (error) {\n this.processingStats.failedChunks++;\n \n if (item.retries < this.config.retryAttempts) {\n item.retries++;\n this.processingQueue.push(item);\n } else {\n this.emit('error', error instanceof Error ? error : new Error(String(error)));\n }\n }\n }\n\n private createEmptyStats(): ProcessingSummary {\n return {\n totalChunks: 0,\n processedChunks: 0,\n failedChunks: 0,\n totalAdaptations: 0,\n averageConfidence: 0,\n totalProcessingTime: 0,\n suggestedImprovements: [],\n };\n }\n} "],"names":["ContentAdapter","EventEmitter","config","content","preferences","context","startTime","contentId","cached","adaptedContent","adaptations","result","firstKey","error","err","chunks","buffer","chunkIndex","chunk","processedChunk","summary","id","queueItem","hash","i","char","fontSize","percentageSize","chunkSize","sentences","s","original","adapted","maxPossibleAdaptations","appliedAdaptations","item","processingPromise"],"mappings":"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"}