{"version":3,"file":"index.cjs","sources":["../src/utils/logger.js","../src/constants/emotions.js","../src/services/humeService.js","../src/services/videoStreamService.js","../src/config/redis.js","../src/services/emotionalContextService.js","../src/config/database.js","../src/services/customModelService.js","../src/services/modelSelectionService.js","../src/utils/healthCheck.js","../src/config/weaviate.js","../src/index.js"],"sourcesContent":["import winston from 'winston';\n\nconst logLevels = {\n  error: 0,\n  warn: 1,\n  info: 2,\n  debug: 3,\n};\n\nconst logColors = {\n  error: 'red',\n  warn: 'yellow',\n  info: 'green',\n  debug: 'blue',\n};\n\nlet logger = null;\n\nexport async function setupLogger() {\n  if (logger) {\n    return logger;\n  }\n  \n  await createLogsDirectory();\n\n  // Add colors to Winston\n  winston.addColors(logColors);\n\n  const format = winston.format.combine(\n    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),\n    winston.format.errors({ stack: true }),\n    winston.format.colorize({ all: true }),\n    winston.format.printf(({ level, message, timestamp, stack }) => {\n      if (stack) {\n        return `${timestamp} ${level}: ${message}\\n${stack}`;\n      }\n      return `${timestamp} ${level}: ${message}`;\n    })\n  );\n\n  logger = winston.createLogger({\n    level: process.env.LOG_LEVEL || 'info',\n    levels: logLevels,\n    format,\n    transports: [\n      // Console transport\n      new winston.transports.Console(),\n      \n      // File transport for errors\n      new winston.transports.File({\n        filename: 'logs/error.log',\n        level: 'error',\n        format: winston.format.uncolorize(),\n      }),\n      \n      // File transport for all logs\n      new winston.transports.File({\n        filename: 'logs/combined.log',\n        format: winston.format.uncolorize(),\n      }),\n    ],\n    exceptionHandlers: [\n      new winston.transports.File({\n        filename: 'logs/exceptions.log',\n        format: winston.format.uncolorize(),\n      }),\n    ],\n    rejectionHandlers: [\n      new winston.transports.File({\n        filename: 'logs/rejections.log',\n        format: winston.format.uncolorize(),\n      }),\n    ],\n  });\n\n  // Create a stream for Morgan HTTP logging\n  logger.stream = {\n    write: (message) => {\n      logger.info(message.trim());\n    },\n  };\n\n  return logger;\n}\n\nexport async function createLogsDirectory() {\n  const { mkdir } = await import('fs/promises');\n  try {\n    await mkdir('logs', { recursive: true });\n  } catch (error) {\n    if (error.code !== 'EEXIST') {\n      console.error('Failed to create logs directory:', error);\n    }\n  }\n}\n\nexport { logger };","export const expressionColors = {\n  admiration: \"#ffc58f\",\n  adoration: \"#ffc6cc\",\n  aestheticAppreciation: \"#e2cbff\",\n  amusement: \"#febf52\",\n  anger: \"#b21816\",\n  annoyance: \"#ffffff\",\n  anxiety: \"#6e42cc\",\n  awe: \"#7dabd3\",\n  awkwardness: \"#d7d99d\",\n  boredom: \"#a4a4a4\",\n  calmness: \"#a9cce1\",\n  concentration: \"#336cff\",\n  contemplation: \"#b0aeef\",\n  confusion: \"#c66a26\",\n  contempt: \"#76842d\",\n  contentment: \"#e5c6b4\",\n  craving: \"#54591c\",\n  determination: \"#ff5c00\",\n  disappointment: \"#006c7c\",\n  disapproval: \"#ffffff\",\n  disgust: \"#1a7a41\",\n  distress: \"#c5f264\",\n  doubt: \"#998644\",\n  ecstasy: \"#ff48a4\",\n  embarrassment: \"#63c653\",\n  empathicPain: \"#ca5555\",\n  enthusiasm: \"#ffffff\",\n  entrancement: \"#7554d6\",\n  envy: \"#1d4921\",\n  excitement: \"#fff974\",\n  fear: \"#d1c9ef\",\n  gratitude: \"#ffffff\",\n  guilt: \"#879aa1\",\n  horror: \"#772e7a\",\n  interest: \"#a9cce1\",\n  joy: \"#ffd600\",\n  love: \"#f44f4c\",\n  neutral: \"#879aa1\",\n  nostalgia: \"#b087a1\",\n  pain: \"#8c1d1d\",\n  pride: \"#9a4cb6\",\n  realization: \"#217aa8\",\n  relief: \"#fe927a\",\n  romance: \"#f0cc86\",\n  sadness: \"#305575\",\n  sarcasm: \"#ffffff\",\n  satisfaction: \"#a6ddaf\",\n  sexualDesire: \"#aa0d59\",\n  shame: \"#8a6262\",\n  surprise: \"#70e63a\",\n  surpriseNegative: \"#70e63a\",\n  surprisePositive: \"#7affff\",\n  sympathy: \"#7f88e0\",\n  tiredness: \"#757575\",\n  triumph: \"#ec8132\",\n};\n\nexport const isExpressionColor = (color) => {\n  return color in expressionColors;\n};\n\n// Get the number of emotional dimensions from the colors\nexport const EMOTION_DIMENSIONS = Object.keys(expressionColors).length;\n\n// Convert emotion to RGB vector for neural processing\nexport const emotionToVector = (emotion) => {\n  const color = expressionColors[emotion];\n  if (!color) return null;\n\n  // Convert hex to RGB\n  const r = parseInt(color.slice(1, 3), 16) / 255;\n  const g = parseInt(color.slice(3, 5), 16) / 255;\n  const b = parseInt(color.slice(5, 7), 16) / 255;\n\n  return [r, g, b];\n};\n\n// Convert RGB vector back to closest emotion\nexport const vectorToEmotion = (vector) => {\n  if (!vector || vector.length !== 3) return 'neutral';\n\n  // Convert vector back to hex color\n  const toHex = (n) => {\n    const hex = Math.round(n * 255).toString(16);\n    return hex.length === 1 ? '0' + hex : hex;\n  };\n  const color = `#${toHex(vector[0])}${toHex(vector[1])}${toHex(vector[2])}`;\n\n  // Find closest matching emotion\n  let closestEmotion = 'neutral';\n  let minDistance = Infinity;\n\n  for (const [emotion, emotionColor] of Object.entries(expressionColors)) {\n    const distance = colorDistance(color, emotionColor);\n    if (distance < minDistance) {\n      minDistance = distance;\n      closestEmotion = emotion;\n    }\n  }\n\n  return closestEmotion;\n};\n\n// Calculate Euclidean distance between two hex colors\nconst colorDistance = (color1, color2) => {\n  const r1 = parseInt(color1.slice(1, 3), 16);\n  const g1 = parseInt(color1.slice(3, 5), 16);\n  const b1 = parseInt(color1.slice(5, 7), 16);\n\n  const r2 = parseInt(color2.slice(1, 3), 16);\n  const g2 = parseInt(color2.slice(3, 5), 16);\n  const b2 = parseInt(color2.slice(5, 7), 16);\n\n  return Math.sqrt(\n    Math.pow(r1 - r2, 2) +\n    Math.pow(g1 - g2, 2) +\n    Math.pow(b1 - b2, 2)\n  );\n};","import WebSocket from 'ws';\nimport { logger } from '../utils/logger.js';\nimport { expressionColors, emotionToVector } from '../constants/emotions.js';\n\nexport class HumeService {\n  constructor() {\n    this.ws = null;\n    this.apiKey = process.env.HUME_API_KEY;\n    this.endpoint = process.env.HUME_ENDPOINT;\n    this.isConnected = false;\n    this.activeStreams = new Map();\n    this.messageQueue = [];\n    this.processingQueue = false;\n    this.lastActivityTime = Date.now();\n    this.inactivityTimeout = 60000; // 1 minute inactivity timeout\n    this.reconnectAttempts = 0;\n    this.maxReconnectAttempts = 5;\n    this.reconnectDelay = 1000; // Start with 1 second\n  }\n\n  async connect(config = {}) {\n    if (!this.apiKey) {\n      throw new Error('Hume API key not configured');\n    }\n\n    return new Promise((resolve, reject) => {\n      try {\n        const params = new URLSearchParams({\n          apiKey: this.apiKey,\n          ...config\n        });\n\n        const wsUrl = `${this.endpoint}?${params.toString()}`;\n        this.ws = new WebSocket(wsUrl);\n\n        this.ws.on('open', () => {\n          logger.info('Connected to Hume.ai websocket');\n          this.isConnected = true;\n          this.reconnectAttempts = 0;\n          this.reconnectDelay = 1000;\n          this.setupInactivityCheck();\n          resolve();\n        });\n\n        this.ws.on('message', (data) => {\n          this.lastActivityTime = Date.now();\n          this.handleMessage(data);\n        });\n\n        this.ws.on('error', (error) => {\n          logger.error('Hume websocket error:', error);\n          this.handleError(error);\n        });\n\n        this.ws.on('close', () => {\n          logger.info('Hume websocket closed');\n          this.isConnected = false;\n          this.handleDisconnect();\n        });\n      } catch (error) {\n        reject(error);\n      }\n    });\n  }\n\n  setupInactivityCheck() {\n    setInterval(() => {\n      const inactiveTime = Date.now() - this.lastActivityTime;\n      if (inactiveTime >= this.inactivityTimeout) {\n        logger.warn('WebSocket inactive, reconnecting...');\n        this.reconnect();\n      }\n    }, 10000); // Check every 10 seconds\n  }\n\n  async reconnect() {\n    if (this.reconnectAttempts < this.maxReconnectAttempts) {\n      this.reconnectAttempts++;\n      this.reconnectDelay *= 2; // Exponential backoff\n      logger.info(`Attempting to reconnect in ${this.reconnectDelay}ms (attempt ${this.reconnectAttempts})`);\n      \n      setTimeout(async () => {\n        try {\n          await this.connect();\n          // Resubscribe active streams\n          for (const [streamId, config] of this.activeStreams) {\n            await this.startStream(streamId, config);\n          }\n        } catch (error) {\n          logger.error('Reconnection attempt failed:', error);\n        }\n      }, this.reconnectDelay);\n    } else {\n      logger.error('Max reconnection attempts reached');\n    }\n  }\n\n  async startStream(streamId, config) {\n    if (!this.isConnected) {\n      await this.connect();\n    }\n\n    const streamConfig = {\n      models: config.models || { language: {}, face: {}, prosody: {} },\n      raw_text: config.rawText || true,\n      reset_stream: config.resetStream || false\n    };\n\n    this.activeStreams.set(streamId, {\n      config: streamConfig,\n      callbacks: new Map(),\n      buffer: []\n    });\n\n    await this.sendMessage({\n      type: 'stream_start',\n      stream_id: streamId,\n      config: streamConfig\n    });\n\n    logger.info(`Started stream ${streamId}`);\n  }\n\n  async stopStream(streamId) {\n    const stream = this.activeStreams.get(streamId);\n    if (!stream) return;\n\n    await this.sendMessage({\n      type: 'stream_end',\n      stream_id: streamId\n    });\n\n    this.activeStreams.delete(streamId);\n    logger.info(`Stopped stream ${streamId}`);\n  }\n\n  async processText(text, streamId = null) {\n    const id = streamId || `text_${Date.now()}`;\n    if (!streamId) {\n      await this.startStream(id, { models: { language: {} } });\n    }\n\n    return this.sendData(id, {\n      type: 'text',\n      data: text\n    });\n  }\n\n  async processVoice(audioData, streamId = null) {\n    const id = streamId || `voice_${Date.now()}`;\n    if (!streamId) {\n      await this.startStream(id, { models: { prosody: {} } });\n    }\n\n    // Split audio into 5-second chunks\n    const chunks = this.splitAudioIntoChunks(audioData);\n    const results = [];\n\n    for (const chunk of chunks) {\n      const result = await this.sendData(id, {\n        type: 'prosody',\n        data: chunk.toString('base64')\n      });\n      results.push(result);\n    }\n\n    if (!streamId) {\n      await this.stopStream(id);\n    }\n\n    return this.mergeResults(results);\n  }\n\n  async processFacial(imageData, streamId = null) {\n    const id = streamId || `face_${Date.now()}`;\n    if (!streamId) {\n      await this.startStream(id, { models: { face: {} } });\n    }\n\n    const result = await this.sendData(id, {\n      type: 'face',\n      data: imageData.toString('base64')\n    });\n\n    if (!streamId) {\n      await this.stopStream(id);\n    }\n\n    return result;\n  }\n\n  splitAudioIntoChunks(audioData, chunkSize = 5000) {\n    // Split audio data into 5-second chunks\n    const chunks = [];\n    let offset = 0;\n    while (offset < audioData.length) {\n      chunks.push(audioData.slice(offset, offset + chunkSize));\n      offset += chunkSize;\n    }\n    return chunks;\n  }\n\n  mergeResults(results) {\n    // Merge multiple chunk results into a single result\n    const merged = {\n      emotions: new Map()\n    };\n\n    results.forEach(result => {\n      result.emotions.forEach(emotion => {\n        const existing = merged.emotions.get(emotion.name) || { score: 0, count: 0 };\n        existing.score += emotion.score;\n        existing.count += 1;\n        merged.emotions.set(emotion.name, existing);\n      });\n    });\n\n    // Average the scores\n    return Array.from(merged.emotions.entries()).map(([name, data]) => ({\n      name,\n      score: data.score / data.count\n    }));\n  }\n\n  async sendData(streamId, data) {\n    return new Promise((resolve, reject) => {\n      const messageId = Date.now().toString();\n      const stream = this.activeStreams.get(streamId);\n      \n      if (!stream) {\n        reject(new Error(`Stream ${streamId} not found`));\n        return;\n      }\n\n      stream.callbacks.set(messageId, (response) => {\n        if (response.error) {\n          reject(new Error(response.error));\n        } else {\n          resolve(this.processEmotions(response.emotions));\n        }\n      });\n\n      this.sendMessage({\n        id: messageId,\n        stream_id: streamId,\n        ...data\n      });\n    });\n  }\n\n  async sendMessage(message) {\n    if (!this.isConnected) {\n      throw new Error('WebSocket not connected');\n    }\n\n    this.messageQueue.push(message);\n    if (!this.processingQueue) {\n      await this.processMessageQueue();\n    }\n  }\n\n  async processMessageQueue() {\n    this.processingQueue = true;\n    while (this.messageQueue.length > 0) {\n      const message = this.messageQueue.shift();\n      try {\n        this.ws.send(JSON.stringify(message));\n        this.lastActivityTime = Date.now();\n        // Small delay to respect rate limits\n        await new Promise(resolve => setTimeout(resolve, 20));\n      } catch (error) {\n        logger.error('Failed to send message:', error);\n        this.messageQueue.unshift(message);\n        break;\n      }\n    }\n    this.processingQueue = false;\n  }\n\n  handleMessage(data) {\n    try {\n      const message = JSON.parse(data);\n      const stream = this.activeStreams.get(message.stream_id);\n      \n      if (stream && message.id && stream.callbacks.has(message.id)) {\n        const callback = stream.callbacks.get(message.id);\n        callback(message);\n        stream.callbacks.delete(message.id);\n      }\n    } catch (error) {\n      logger.error('Error handling Hume message:', error);\n    }\n  }\n\n  processEmotions(emotions) {\n    return emotions.map(emotion => ({\n      name: emotion.name,\n      score: emotion.score,\n      vector: emotionToVector(emotion.name),\n      color: expressionColors[emotion.name],\n      confidence: emotion.confidence || emotion.score\n    }))\n    .filter(emotion => emotion.confidence >= 0.1)\n    .sort((a, b) => b.score - a.score);\n  }\n\n  async close() {\n    // Stop all active streams\n    for (const streamId of this.activeStreams.keys()) {\n      await this.stopStream(streamId);\n    }\n\n    if (this.ws) {\n      this.ws.close();\n      this.ws = null;\n      this.isConnected = false;\n      logger.info('Hume websocket connection closed');\n    }\n  }\n}\n\n// Create singleton instance\nconst humeService = new HumeService();\n\nexport default humeService;","import { logger } from '../utils/logger.js';\nimport humeService from './humeService.js';\n\nexport class VideoStreamService {\n  constructor() {\n    this.activeStreams = new Map();\n    this.chunkDuration = 5000; // 5 seconds in milliseconds\n    this.maxResolution = { width: 3000, height: 3000 };\n    this.processingInterval = 1000; // Process every second\n  }\n\n  async startStream(streamId, onEmotionUpdate, config = {}) {\n    if (this.activeStreams.has(streamId)) {\n      logger.warn(`Stream ${streamId} is already active`);\n      return;\n    }\n\n    const streamContext = {\n      id: streamId,\n      buffer: [],\n      lastProcessed: Date.now(),\n      onUpdate: onEmotionUpdate,\n      processingInterval: null,\n      config: {\n        resetStream: config.resetStream || false,\n        models: {\n          face: config.faceConfig || {}\n        },\n        ...config\n      }\n    };\n\n    try {\n      // Start Hume stream\n      await humeService.startStream(streamId, streamContext.config);\n\n      // Start processing interval\n      streamContext.processingInterval = setInterval(\n        () => this.processStreamBuffer(streamContext),\n        this.processingInterval\n      );\n\n      this.activeStreams.set(streamId, streamContext);\n      logger.info(`Started video stream ${streamId}`);\n    } catch (error) {\n      logger.error(`Failed to start video stream ${streamId}:`, error);\n      throw error;\n    }\n  }\n\n  async stopStream(streamId) {\n    const streamContext = this.activeStreams.get(streamId);\n    if (!streamContext) {\n      logger.warn(`Stream ${streamId} not found`);\n      return;\n    }\n\n    // Clear processing interval\n    if (streamContext.processingInterval) {\n      clearInterval(streamContext.processingInterval);\n    }\n\n    // Process any remaining frames\n    await this.processStreamBuffer(streamContext);\n\n    // Stop Hume stream\n    await humeService.stopStream(streamId);\n\n    this.activeStreams.delete(streamId);\n    logger.info(`Stopped video stream ${streamId}`);\n  }\n\n  async addFrame(streamId, frameData, timestamp = Date.now()) {\n    const streamContext = this.activeStreams.get(streamId);\n    if (!streamContext) {\n      logger.warn(`Stream ${streamId} not found, frame discarded`);\n      return;\n    }\n\n    try {\n      // Validate frame dimensions\n      const dimensions = await this.getFrameDimensions(frameData);\n      if (!this.validateFrameDimensions(dimensions)) {\n        logger.warn(`Frame dimensions exceed maximum (${dimensions.width}x${dimensions.height})`);\n        return;\n      }\n\n      streamContext.buffer.push({\n        data: frameData,\n        timestamp\n      });\n\n      // Trim buffer if it gets too large\n      this.trimBuffer(streamContext);\n    } catch (error) {\n      logger.error(`Error adding frame to stream ${streamId}:`, error);\n    }\n  }\n\n  async processStreamBuffer(streamContext) {\n    if (streamContext.buffer.length === 0) return;\n\n    try {\n      const now = Date.now();\n      const chunkStartTime = now - this.chunkDuration;\n\n      // Get frames within the current chunk\n      const chunkFrames = streamContext.buffer.filter(\n        frame => frame.timestamp >= chunkStartTime\n      );\n\n      if (chunkFrames.length === 0) return;\n\n      // Select the best frame from the chunk\n      const selectedFrame = this.selectBestFrame(chunkFrames);\n\n      // Process the frame with Hume\n      const emotions = await humeService.processFacial(\n        selectedFrame.data,\n        streamContext.id\n      );\n\n      // Update emotional state\n      if (streamContext.onUpdate && emotions.length > 0) {\n        streamContext.onUpdate({\n          streamId: streamContext.id,\n          timestamp: now,\n          emotions,\n          frameCount: chunkFrames.length,\n          selectedFrameTime: selectedFrame.timestamp\n        });\n      }\n\n      // Remove processed frames\n      streamContext.buffer = streamContext.buffer.filter(\n        frame => frame.timestamp > chunkStartTime\n      );\n\n      streamContext.lastProcessed = now;\n    } catch (error) {\n      logger.error(`Error processing stream ${streamContext.id}:`, error);\n    }\n  }\n\n  selectBestFrame(frames) {\n    // For now, select the middle frame\n    // Could be enhanced with frame quality detection\n    return frames[Math.floor(frames.length / 2)];\n  }\n\n  trimBuffer(streamContext) {\n    const now = Date.now();\n    // Keep only frames from the last chunk duration\n    streamContext.buffer = streamContext.buffer.filter(\n      frame => now - frame.timestamp <= this.chunkDuration\n    );\n  }\n\n  async getFrameDimensions(frameData) {\n    // Implementation would depend on how frames are provided\n    // This is a placeholder that should be implemented based on\n    // the actual frame format (e.g., raw pixels, base64 image, etc.)\n    return {\n      width: 1280,  // placeholder\n      height: 720   // placeholder\n    };\n  }\n\n  validateFrameDimensions(dimensions) {\n    return dimensions.width <= this.maxResolution.width &&\n           dimensions.height <= this.maxResolution.height;\n  }\n\n  getStreamStatus(streamId) {\n    const streamContext = this.activeStreams.get(streamId);\n    if (!streamContext) return null;\n\n    return {\n      id: streamContext.id,\n      isActive: true,\n      bufferSize: streamContext.buffer.length,\n      lastProcessed: streamContext.lastProcessed,\n      timeSinceLastProcess: Date.now() - streamContext.lastProcessed,\n      config: streamContext.config\n    };\n  }\n\n  getAllStreams() {\n    return Array.from(this.activeStreams.keys()).map(id => this.getStreamStatus(id));\n  }\n\n  async cleanup() {\n    // Stop all active streams\n    for (const streamId of this.activeStreams.keys()) {\n      await this.stopStream(streamId);\n    }\n  }\n}\n\n// Create singleton instance\nconst videoStreamService = new VideoStreamService();\n\nexport default videoStreamService;","import { createClient } from 'redis';\nimport { logger } from '../utils/logger.js';\n\nlet client = null;\n\nexport async function setupRedis() {\n  try {\n    const url = process.env.REDIS_URL;\n    if (!url) {\n      throw new Error('REDIS_URL environment variable is not set');\n    }\n\n    client = createClient({\n      url,\n      socket: {\n        reconnectStrategy: (retries) => {\n          const maxRetryTime = 3000; // 3 seconds\n          const retryTime = Math.min(retries * 100, maxRetryTime);\n          logger.info(`Retrying Redis connection in ${retryTime}ms (attempt ${retries + 1})`);\n          return retryTime;\n        },\n        connectTimeout: 10000, // 10 seconds\n        keepAlive: 5000, // 5 seconds\n      },\n      database: 0,\n      commandsQueueMaxLength: 100000,\n      readonly: false,\n      legacyMode: false,\n      isolationPoolOptions: {\n        min: 5,\n        max: 20,\n        acquireTimeoutMillis: 5000,\n        createTimeoutMillis: 5000,\n        idleTimeoutMillis: 5000,\n        createRetryIntervalMillis: 200,\n      }\n    });\n\n    // Event handlers\n    client.on('connect', () => {\n      logger.info('Redis client connecting...');\n    });\n\n    client.on('ready', () => {\n      logger.info('Redis client connected and ready');\n    });\n\n    client.on('error', (err) => {\n      logger.error('Redis client error:', err);\n    });\n\n    client.on('reconnecting', () => {\n      logger.info('Redis client reconnecting...');\n    });\n\n    client.on('end', () => {\n      logger.info('Redis client connection closed');\n    });\n\n    // Connect to Redis\n    await client.connect();\n\n    // Test connection\n    await testConnection();\n\n    // Initialize data structures\n    await initializeDataStructures();\n\n    return client;\n  } catch (error) {\n    logger.error('Failed to setup Redis:', error);\n    throw error;\n  }\n}\n\nasync function testConnection() {\n  try {\n    await client.ping();\n    logger.info('Redis connection test successful');\n  } catch (error) {\n    logger.error('Redis connection test failed:', error);\n    throw error;\n  }\n}\n\nasync function initializeDataStructures() {\n  try {\n    // Initialize emotional state hash if it doesn't exist\n    const emotionalStateExists = await client.exists('emotional_state');\n    if (!emotionalStateExists) {\n      await client.hSet('emotional_state', {\n        emotion: 'neutral',\n        vector: '[]',\n        confidence: '1.0',\n        timestamp: Date.now().toString(),\n        type: 'system'\n      });\n    }\n\n    // Initialize memory windows\n    const windows = ['short_term', 'medium_term', 'long_term'];\n    for (const window of windows) {\n      const key = `memory:window:${window}`;\n      const exists = await client.exists(key);\n      if (!exists) {\n        await client.zAdd(key, {\n          score: Date.now(),\n          value: JSON.stringify({\n            type: 'system',\n            content: 'initialized',\n            timestamp: Date.now()\n          })\n        });\n      }\n    }\n\n    // Initialize attention system structures\n    const attentionExists = await client.exists('attention:4w');\n    if (!attentionExists) {\n      await client.hSet('attention:4w', {\n        who: '[]',\n        what: '[]',\n        when: '[]',\n        where: '[]'\n      });\n    }\n\n    logger.info('Redis data structures initialized');\n  } catch (error) {\n    logger.error('Failed to initialize Redis data structures:', error);\n    throw error;\n  }\n}\n\nexport function getRedisClient() {\n  if (!client) {\n    throw new Error('Redis client not initialized. Call setupRedis first.');\n  }\n  return client;\n}\n\nexport async function closeRedis() {\n  if (client) {\n    try {\n      await client.quit();\n      client = null;\n      logger.info('Redis connection closed gracefully');\n    } catch (error) {\n      logger.error('Error closing Redis connection:', error);\n      // Force close if graceful shutdown fails\n      client.disconnect();\n      client = null;\n    }\n  }\n}\n\n// Cleanup handler for graceful shutdown\nprocess.on('SIGTERM', async () => {\n  logger.info('SIGTERM received, closing Redis connection...');\n  await closeRedis();\n});\n\nprocess.on('SIGINT', async () => {\n  logger.info('SIGINT received, closing Redis connection...');\n  await closeRedis();\n});","import { logger } from '../utils/logger.js';\nimport humeService from './humeService.js';\nimport videoStreamService from './videoStreamService.js';\nimport { getRedisClient } from '../config/redis.js';\nimport { emotionToVector, vectorToEmotion } from '../constants/emotions.js';\n\nexport class EmotionalContextService {\n  constructor() {\n    this.redis = null;\n    this.activeContexts = new Map();\n    this.emotionalBuffer = new Map();\n    this.bufferTimeout = 5000; // 5 seconds\n    this.customModelEnabled = false;\n    this.weights = {\n      evi: 0.5,      // EVI's built-in emotional processing\n      video: 0.3,    // Video facial analysis\n      voice: 0.2     // Voice prosody analysis\n    };\n  }\n\n  async initialize() {\n    this.redis = getRedisClient();\n    await this.setupEmotionalBuffers();\n    await this.loadCustomModel();\n  }\n\n  async loadCustomModel() {\n    try {\n      const hasCustomModel = await this.redis.exists('custom_model_config');\n      if (hasCustomModel) {\n        const config = JSON.parse(await this.redis.get('custom_model_config'));\n        this.customModelEnabled = config.enabled;\n        if (config.weights) {\n          this.weights = config.weights;\n        }\n        logger.info('Custom model configuration loaded');\n      }\n    } catch (error) {\n      logger.error('Failed to load custom model:', error);\n    }\n  }\n\n  async setupEmotionalBuffers() {\n    try {\n      const bufferKey = 'emotional_context_buffers';\n      const exists = await this.redis.exists(bufferKey);\n      \n      if (!exists) {\n        await this.redis.hSet(bufferKey, {\n          active_sessions: '{}',\n          buffer_timeouts: '{}'\n        });\n      }\n    } catch (error) {\n      logger.error('Failed to setup emotional buffers:', error);\n      throw error;\n    }\n  }\n\n  async startContext(contextId, options = {}) {\n    const context = {\n      id: contextId,\n      startTime: Date.now(),\n      options: {\n        useVideo: options.useVideo ?? false,\n        useVoice: options.useVoice ?? true,\n        useEVI: options.useEVI ?? false,\n        customModel: options.customModel ?? this.customModelEnabled,\n        bufferSize: options.bufferSize ?? 5,\n        ...options\n      },\n      emotionalState: {\n        current: 'neutral',\n        confidence: 1.0,\n        vector: emotionToVector('neutral'),\n        history: [],\n        sources: {}\n      }\n    };\n\n    this.activeContexts.set(contextId, context);\n\n    // Start video stream if enabled\n    if (context.options.useVideo) {\n      await videoStreamService.startStream(contextId, (emotionData) => {\n        this.handleVideoEmotion(contextId, emotionData);\n      }, {\n        resetStream: true,\n        faceConfig: {\n          // Configure face detection settings\n          minConfidence: 0.7,\n          returnPoints: true\n        }\n      });\n    }\n\n    // Initialize Hume stream for voice if not using EVI\n    if (context.options.useVoice && !context.options.useEVI) {\n      await humeService.startStream(contextId, {\n        models: { prosody: {} },\n        resetStream: true\n      });\n    }\n\n    logger.info(`Started emotional context ${contextId} with options:`, context.options);\n    return context;\n  }\n\n  async handleEVIEmotion(contextId, eviEmotion) {\n    const context = this.activeContexts.get(contextId);\n    if (!context) {\n      logger.warn(`Context ${contextId} not found for EVI emotion`);\n      return;\n    }\n\n    // Store EVI emotion in context sources\n    context.emotionalState.sources.evi = {\n      emotion: eviEmotion.emotion,\n      confidence: eviEmotion.confidence,\n      vector: eviEmotion.vector,\n      timestamp: Date.now()\n    };\n\n    await this.updateEmotionalState(contextId, {\n      emotion: eviEmotion.emotion,\n      confidence: eviEmotion.confidence,\n      vector: eviEmotion.vector,\n      source: 'evi',\n      timestamp: Date.now()\n    });\n  }\n\n  async handleVideoEmotion(contextId, videoEmotion) {\n    const context = this.activeContexts.get(contextId);\n    if (!context) {\n      logger.warn(`Context ${contextId} not found for video emotion`);\n      return;\n    }\n\n    if (videoEmotion.emotions.length > 0) {\n      const dominant = videoEmotion.emotions[0];\n      \n      // Store video emotion in context sources\n      context.emotionalState.sources.video = {\n        emotion: dominant.name,\n        confidence: dominant.confidence,\n        vector: dominant.vector,\n        timestamp: videoEmotion.timestamp\n      };\n\n      await this.updateEmotionalState(contextId, {\n        emotion: dominant.name,\n        confidence: dominant.confidence,\n        vector: dominant.vector,\n        source: 'video',\n        timestamp: videoEmotion.timestamp\n      });\n    }\n  }\n\n  async handleVoiceEmotion(contextId, voiceData) {\n    const context = this.activeContexts.get(contextId);\n    if (!context) {\n      logger.warn(`Context ${contextId} not found for voice emotion`);\n      return;\n    }\n\n    try {\n      let emotions;\n      if (context.options.useEVI) {\n        // EVI handles voice emotion processing\n        return;\n      } else {\n        // Process voice through Hume\n        emotions = await humeService.processVoice(voiceData, contextId);\n      }\n\n      if (emotions.length > 0) {\n        const dominant = emotions[0];\n        \n        // Store voice emotion in context sources\n        context.emotionalState.sources.voice = {\n          emotion: dominant.name,\n          confidence: dominant.confidence,\n          vector: dominant.vector,\n          timestamp: Date.now()\n        };\n\n        await this.updateEmotionalState(contextId, {\n          emotion: dominant.name,\n          confidence: dominant.confidence,\n          vector: dominant.vector,\n          source: 'voice',\n          timestamp: Date.now()\n        });\n      }\n    } catch (error) {\n      logger.error(`Error processing voice emotion for context ${contextId}:`, error);\n    }\n  }\n\n  async updateEmotionalState(contextId, emotionData) {\n    const context = this.activeContexts.get(contextId);\n    if (!context) return;\n\n    // Add to emotional buffer\n    if (!this.emotionalBuffer.has(contextId)) {\n      this.emotionalBuffer.set(contextId, []);\n    }\n    this.emotionalBuffer.get(contextId).push(emotionData);\n\n    // Process buffer if it reaches the size limit or after timeout\n    if (this.emotionalBuffer.get(contextId).length >= context.options.bufferSize) {\n      await this.processEmotionalBuffer(contextId);\n    } else {\n      // Set timeout to process buffer\n      setTimeout(async () => {\n        await this.processEmotionalBuffer(contextId);\n      }, this.bufferTimeout);\n    }\n  }\n\n  async processEmotionalBuffer(contextId) {\n    const buffer = this.emotionalBuffer.get(contextId);\n    if (!buffer || buffer.length === 0) return;\n\n    const context = this.activeContexts.get(contextId);\n    if (!context) return;\n\n    const combinedVector = new Array(buffer[0].vector.length).fill(0);\n    let totalWeight = 0;\n\n    // Process each source type separately\n    const sourceGroups = this.groupBySource(buffer);\n    \n    for (const [source, emotions] of Object.entries(sourceGroups)) {\n      const weight = this.weights[source] * this.calculateSourceConfidence(emotions);\n      const sourceVector = this.combineSourceEmotions(emotions);\n      \n      sourceVector.forEach((v, i) => {\n        combinedVector[i] += v * weight;\n      });\n      totalWeight += weight;\n    }\n\n    // Normalize vector\n    if (totalWeight > 0) {\n      combinedVector.forEach((_, i) => {\n        combinedVector[i] /= totalWeight;\n      });\n    }\n\n    // Update context state\n    context.emotionalState = {\n      current: vectorToEmotion(combinedVector),\n      confidence: totalWeight,\n      vector: combinedVector,\n      sources: context.emotionalState.sources,\n      history: [\n        ...context.emotionalState.history,\n        {\n          timestamp: Date.now(),\n          emotions: buffer,\n          sources: { ...context.emotionalState.sources }\n        }\n      ].slice(-100) // Keep last 100 emotional states\n    };\n\n    // Store in Redis\n    await this.redis.hSet(`emotional_context:${contextId}`, {\n      state: JSON.stringify(context.emotionalState),\n      lastUpdate: Date.now().toString()\n    });\n\n    // Clear buffer\n    this.emotionalBuffer.set(contextId, []);\n  }\n\n  groupBySource(buffer) {\n    return buffer.reduce((groups, emotion) => {\n      const source = emotion.source;\n      if (!groups[source]) {\n        groups[source] = [];\n      }\n      groups[source].push(emotion);\n      return groups;\n    }, {});\n  }\n\n  calculateSourceConfidence(emotions) {\n    return emotions.reduce((sum, e) => sum + e.confidence, 0) / emotions.length;\n  }\n\n  combineSourceEmotions(emotions) {\n    const vector = new Array(emotions[0].vector.length).fill(0);\n    emotions.forEach(emotion => {\n      emotion.vector.forEach((v, i) => {\n        vector[i] += v * emotion.confidence;\n      });\n    });\n    return vector;\n  }\n\n  async getEmotionalContext(contextId) {\n    const context = this.activeContexts.get(contextId);\n    if (!context) {\n      const storedContext = await this.redis.hGetAll(`emotional_context:${contextId}`);\n      if (storedContext.state) {\n        return JSON.parse(storedContext.state);\n      }\n      return null;\n    }\n    return context.emotionalState;\n  }\n\n  async stopContext(contextId) {\n    const context = this.activeContexts.get(contextId);\n    if (!context) return;\n\n    // Process any remaining emotions in buffer\n    await this.processEmotionalBuffer(contextId);\n\n    // Stop video stream if active\n    if (context.options.useVideo) {\n      await videoStreamService.stopStream(contextId);\n    }\n\n    // Stop Hume stream if using it for voice\n    if (context.options.useVoice && !context.options.useEVI) {\n      await humeService.stopStream(contextId);\n    }\n\n    // Clean up\n    this.activeContexts.delete(contextId);\n    this.emotionalBuffer.delete(contextId);\n\n    logger.info(`Stopped emotional context ${contextId}`);\n  }\n\n  async cleanup() {\n    // Stop all active contexts\n    for (const contextId of this.activeContexts.keys()) {\n      await this.stopContext(contextId);\n    }\n  }\n}\n\n// Create singleton instance\nconst emotionalContextService = new EmotionalContextService();\n\nexport default emotionalContextService;","import { MongoClient } from 'mongodb';\nimport { logger } from '../utils/logger.js';\n\nlet client = null;\n\nexport async function setupDatabase() {\n  try {\n    const uri = process.env.MONGODB_URI;\n    if (!uri) {\n      throw new Error('MONGODB_URI environment variable is not set');\n    }\n\n    client = new MongoClient(uri, {\n      useNewUrlParser: true,\n      useUnifiedTopology: true,\n    });\n\n    await client.connect();\n    logger.info('Successfully connected to MongoDB');\n\n    // Create time series collections\n    const db = client.db('memorable');\n    \n    // Create collections with time series configuration\n    await createTimeSeriesCollection(db, 'emotions', 'timestamp');\n    await createTimeSeriesCollection(db, 'interactions', 'timestamp');\n    await createTimeSeriesCollection(db, 'contextual_data', 'timestamp');\n    \n    return client;\n  } catch (error) {\n    logger.error('MongoDB connection error:', error);\n    throw error;\n  }\n}\n\nasync function createTimeSeriesCollection(db, collectionName, timeField) {\n  try {\n    await db.createCollection(collectionName, {\n      timeseries: {\n        timeField,\n        metaField: \"metadata\",\n        granularity: \"seconds\"\n      }\n    });\n    logger.info(`Created time series collection: ${collectionName}`);\n  } catch (error) {\n    // Collection might already exist\n    if (error.code !== 48) { // 48 is the error code for \"collection already exists\"\n      throw error;\n    }\n  }\n}\n\nexport function getDatabase() {\n  if (!client) {\n    throw new Error('Database not initialized. Call setupDatabase first.');\n  }\n  return client.db('memorable');\n}\n\nexport async function closeDatabase() {\n  if (client) {\n    await client.close();\n    client = null;\n    logger.info('MongoDB connection closed');\n  }\n}","import { logger } from '../utils/logger.js';\nimport { getRedisClient } from '../config/redis.js';\nimport { getDatabase } from '../config/database.js';\n\nexport class CustomModelService {\n  constructor() {\n    this.redis = null;\n    this.db = null;\n    this.apiKey = process.env.HUME_API_KEY;\n    this.apiEndpoint = 'https://api.hume.ai/v0/custom/models';\n    this.activeModels = new Map();\n    this.trainingJobs = new Map();\n  }\n\n  async initialize() {\n    this.redis = getRedisClient();\n    this.db = getDatabase();\n    await this.loadActiveModels();\n  }\n\n  async loadActiveModels() {\n    try {\n      const models = await this.db.collection('custom_models')\n        .find({ status: 'active' })\n        .toArray();\n\n      models.forEach(model => {\n        this.activeModels.set(model.modelId, model);\n      });\n\n      logger.info(`Loaded ${models.length} active custom models`);\n    } catch (error) {\n      logger.error('Failed to load active models:', error);\n    }\n  }\n\n  async createTrainingJob(userId, config) {\n    try {\n      const jobId = `train_${Date.now()}_${userId}`;\n      const job = {\n        id: jobId,\n        userId,\n        status: 'preparing',\n        config: {\n          name: config.name,\n          description: config.description,\n          labelSet: config.labels || [],\n          dataConfig: {\n            includeExpressions: true,\n            includeLanguage: true,\n            includeProsody: true\n          },\n          ...config\n        },\n        created: new Date(),\n        updated: new Date()\n      };\n\n      await this.db.collection('training_jobs').insertOne(job);\n      this.trainingJobs.set(jobId, job);\n\n      // Start collecting training data\n      await this.collectTrainingData(jobId);\n\n      return jobId;\n    } catch (error) {\n      logger.error('Failed to create training job:', error);\n      throw error;\n    }\n  }\n\n  async collectTrainingData(jobId) {\n    const job = this.trainingJobs.get(jobId);\n    if (!job) throw new Error(`Training job ${jobId} not found`);\n\n    try {\n      // Update job status\n      job.status = 'collecting';\n      await this.updateJobStatus(job);\n\n      // Get user's emotional history\n      const emotionalHistory = await this.getEmotionalHistory(job.userId);\n\n      // Process and label the data\n      const labeledData = await this.processTrainingData(emotionalHistory, job.config);\n\n      // Store processed data\n      await this.storeTrainingData(jobId, labeledData);\n\n      // Start training if enough data\n      if (labeledData.length >= 100) {\n        await this.startModelTraining(jobId);\n      } else {\n        job.status = 'insufficient_data';\n        await this.updateJobStatus(job);\n      }\n    } catch (error) {\n      logger.error(`Failed to collect training data for job ${jobId}:`, error);\n      job.status = 'failed';\n      job.error = error.message;\n      await this.updateJobStatus(job);\n    }\n  }\n\n  async getEmotionalHistory(userId) {\n    const history = await this.db.collection('emotional_history')\n      .find({\n        userId,\n        timestamp: { $gte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) } // Last 30 days\n      })\n      .sort({ timestamp: 1 })\n      .toArray();\n\n    return history;\n  }\n\n  async processTrainingData(history, config) {\n    const labeledData = [];\n\n    for (const entry of history) {\n      if (!entry.emotionalState || !entry.context) continue;\n\n      const processedEntry = {\n        timestamp: entry.timestamp,\n        labels: this.generateLabels(entry, config.labelSet),\n        data: {\n          expressions: entry.emotionalState.sources.video || null,\n          language: entry.context.text || null,\n          prosody: entry.emotionalState.sources.voice || null\n        }\n      };\n\n      if (this.validateTrainingEntry(processedEntry)) {\n        labeledData.push(processedEntry);\n      }\n    }\n\n    return labeledData;\n  }\n\n  generateLabels(entry, labelSet) {\n    const labels = new Set();\n\n    // Generate labels based on emotional state and context\n    labelSet.forEach(label => {\n      if (this.matchesLabelCriteria(entry, label)) {\n        labels.add(label);\n      }\n    });\n\n    return Array.from(labels);\n  }\n\n  matchesLabelCriteria(entry, label) {\n    // Implement label matching logic based on emotional state and context\n    // This would be customized based on the specific requirements\n    return false;\n  }\n\n  validateTrainingEntry(entry) {\n    return entry.labels.length > 0 &&\n           (entry.data.expressions || entry.data.language || entry.data.prosody);\n  }\n\n  async storeTrainingData(jobId, data) {\n    await this.db.collection('training_data').insertOne({\n      jobId,\n      data,\n      timestamp: new Date()\n    });\n  }\n\n  async startModelTraining(jobId) {\n    const job = this.trainingJobs.get(jobId);\n    if (!job) throw new Error(`Training job ${jobId} not found`);\n\n    try {\n      // Update job status\n      job.status = 'training';\n      await this.updateJobStatus(job);\n\n      // Get training data\n      const trainingData = await this.db.collection('training_data')\n        .findOne({ jobId });\n\n      // Submit training job to Hume API\n      const response = await fetch(this.apiEndpoint, {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n          'X-Hume-Api-Key': this.apiKey\n        },\n        body: JSON.stringify({\n          name: job.config.name,\n          description: job.config.description,\n          data: trainingData.data\n        })\n      });\n\n      if (!response.ok) {\n        throw new Error(`Hume API error: ${response.statusText}`);\n      }\n\n      const result = await response.json();\n      job.modelId = result.model_id;\n      job.status = 'training';\n      await this.updateJobStatus(job);\n\n      // Start monitoring training progress\n      this.monitorTraining(jobId);\n    } catch (error) {\n      logger.error(`Failed to start training for job ${jobId}:`, error);\n      job.status = 'failed';\n      job.error = error.message;\n      await this.updateJobStatus(job);\n    }\n  }\n\n  async monitorTraining(jobId) {\n    const job = this.trainingJobs.get(jobId);\n    if (!job || !job.modelId) return;\n\n    try {\n      const response = await fetch(`${this.apiEndpoint}/${job.modelId}`, {\n        headers: { 'X-Hume-Api-Key': this.apiKey }\n      });\n\n      if (!response.ok) {\n        throw new Error(`Hume API error: ${response.statusText}`);\n      }\n\n      const status = await response.json();\n\n      if (status.status === 'completed') {\n        await this.handleTrainingComplete(job);\n      } else if (status.status === 'failed') {\n        await this.handleTrainingFailed(job, status.error);\n      } else {\n        // Check again in 5 minutes\n        setTimeout(() => this.monitorTraining(jobId), 5 * 60 * 1000);\n      }\n    } catch (error) {\n      logger.error(`Error monitoring training for job ${jobId}:`, error);\n    }\n  }\n\n  async handleTrainingComplete(job) {\n    try {\n      // Update job status\n      job.status = 'completed';\n      await this.updateJobStatus(job);\n\n      // Add model to active models\n      const model = {\n        modelId: job.modelId,\n        name: job.config.name,\n        description: job.config.description,\n        userId: job.userId,\n        status: 'active',\n        created: new Date(),\n        lastUsed: null\n      };\n\n      await this.db.collection('custom_models').insertOne(model);\n      this.activeModels.set(job.modelId, model);\n\n      logger.info(`Training completed for job ${job.id}`);\n    } catch (error) {\n      logger.error(`Error handling training completion for job ${job.id}:`, error);\n    }\n  }\n\n  async handleTrainingFailed(job, error) {\n    job.status = 'failed';\n    job.error = error;\n    await this.updateJobStatus(job);\n    logger.error(`Training failed for job ${job.id}:`, error);\n  }\n\n  async updateJobStatus(job) {\n    await this.db.collection('training_jobs').updateOne(\n      { id: job.id },\n      {\n        $set: {\n          status: job.status,\n          error: job.error,\n          updated: new Date(),\n          modelId: job.modelId\n        }\n      }\n    );\n  }\n\n  async getJobStatus(jobId) {\n    const job = this.trainingJobs.get(jobId);\n    if (!job) {\n      const stored = await this.db.collection('training_jobs')\n        .findOne({ id: jobId });\n      return stored;\n    }\n    return job;\n  }\n\n  async getActiveModels(userId) {\n    return Array.from(this.activeModels.values())\n      .filter(model => model.userId === userId);\n  }\n\n  async deleteModel(modelId) {\n    try {\n      // Delete from Hume API\n      await fetch(`${this.apiEndpoint}/${modelId}`, {\n        method: 'DELETE',\n        headers: { 'X-Hume-Api-Key': this.apiKey }\n      });\n\n      // Update local state\n      this.activeModels.delete(modelId);\n\n      // Update database\n      await this.db.collection('custom_models').updateOne(\n        { modelId },\n        { $set: { status: 'deleted' } }\n      );\n\n      logger.info(`Deleted custom model ${modelId}`);\n    } catch (error) {\n      logger.error(`Failed to delete model ${modelId}:`, error);\n      throw error;\n    }\n  }\n}\n\n// Create singleton instance\nconst customModelService = new CustomModelService();\n\nexport default customModelService;","import { logger } from '../utils/logger.js';\nimport os from 'os';\n\nexport class ModelSelectionService {\n  constructor() {\n    this.isServerEnvironment = process.env.NODE_ENV === 'production';\n    this.hasGPU = process.env.ENABLE_CUDA === '1';\n    this.modelConfigs = {\n      local: {\n        default: 'ollama/mistral:3.2-small',\n        management: 'ollama/mistral:3.2-small',\n        embedding: 'ollama/nomic-embed-text',\n        fallback: 'ollama/tinyllama'\n      },\n      server: {\n        default: 'ollama/mistral:7b-instruct',\n        management: 'ollama/mixtral:8x7b-instruct',\n        embedding: 'ollama/nomic-embed-text:latest',\n        fallback: 'ollama/mistral:3.2-small'\n      }\n    };\n\n    // Performance tracking\n    this.metrics = {\n      requestCount: 0,\n      totalLatency: 0,\n      errors: 0,\n      lastSwitchTime: Date.now(),\n      modelUsage: new Map()\n    };\n\n    // Memory thresholds (percentage)\n    this.memoryThresholds = {\n      warning: 80,\n      critical: 90\n    };\n\n    // Memoization caches\n    this.responseCache = new Map();\n    this.modelStateCache = new Map();\n    this.taskPatternCache = new Map();\n\n    // Cache configuration\n    this.cacheConfig = {\n      maxSize: 1000,\n      ttl: 3600000, // 1 hour\n      criticalityThreshold: 0.8\n    };\n\n    // Initialize performance monitoring\n    this.startPerformanceMonitoring();\n  }\n\n  getModelConfig(type = 'default') {\n    const environment = this.isServerEnvironment ? 'server' : 'local';\n    const config = this.modelConfigs[environment];\n\n    // If GPU is available locally, we can use larger models\n    if (!this.isServerEnvironment && this.hasGPU) {\n      return this.modelConfigs.server[type];\n    }\n\n    return config[type];\n  }\n\n  async validateModel(modelName) {\n    try {\n      // Check if model is available in Ollama\n      const response = await fetch('http://localhost:11434/api/tags');\n      const { models } = await response.json();\n      \n      return models.some(model => model.name === modelName);\n    } catch (error) {\n      logger.error('Error validating model:', error);\n      this.metrics.errors++;\n      return false;\n    }\n  }\n\n  async ensureModel(type = 'default') {\n    const modelName = this.getModelConfig(type);\n    const isAvailable = await this.validateModel(modelName);\n\n    if (!isAvailable) {\n      logger.info(`Model ${modelName} not found, falling back to smaller model`);\n      return this.modelConfigs[this.isServerEnvironment ? 'server' : 'local'].fallback;\n    }\n\n    return modelName;\n  }\n\n  getResourceLimits() {\n    if (this.isServerEnvironment) {\n      return {\n        maxMemory: '16gb',\n        maxThreads: 8,\n        batchSize: 32\n      };\n    }\n\n    return {\n      maxMemory: '4gb',\n      maxThreads: 4,\n      batchSize: 8\n    };\n  }\n\n  async getOptimalConfig() {\n    const startTime = Date.now();\n    const modelName = await this.ensureModel();\n    const resources = this.getResourceLimits();\n\n    // Update metrics\n    this.metrics.requestCount++;\n    this.metrics.totalLatency += Date.now() - startTime;\n    this.updateModelUsage(modelName);\n\n    return {\n      model: modelName,\n      ...resources,\n      environment: this.isServerEnvironment ? 'server' : 'local',\n      gpu: this.hasGPU\n    };\n  }\n\n  // Memoization methods\n  async getMemoizedResponse(prompt, modelName, taskType) {\n    const cacheKey = this.generateCacheKey(prompt, modelName, taskType);\n    \n    if (this.responseCache.has(cacheKey)) {\n      const cached = this.responseCache.get(cacheKey);\n      if (Date.now() - cached.timestamp < this.cacheConfig.ttl) {\n        logger.info('Using memoized response');\n        return cached.response;\n      }\n      this.responseCache.delete(cacheKey);\n    }\n\n    return null;\n  }\n\n  async memoizeResponse(prompt, response, modelName, taskType, criticality) {\n    const cacheKey = this.generateCacheKey(prompt, modelName, taskType);\n    \n    // Only memoize if task criticality is above threshold\n    if (criticality >= this.cacheConfig.criticalityThreshold) {\n      this.responseCache.set(cacheKey, {\n        response,\n        timestamp: Date.now(),\n        criticality\n      });\n\n      // Maintain cache size\n      if (this.responseCache.size > this.cacheConfig.maxSize) {\n        const oldestKey = Array.from(this.responseCache.keys())[0];\n        this.responseCache.delete(oldestKey);\n      }\n\n      // Update task pattern for night processing\n      this.updateTaskPattern(taskType, prompt);\n    }\n  }\n\n  generateCacheKey(prompt, modelName, taskType) {\n    return `${modelName}:${taskType}:${prompt.slice(0, 100)}`;\n  }\n\n  updateTaskPattern(taskType, prompt) {\n    const patterns = this.taskPatternCache.get(taskType) || [];\n    patterns.push({\n      prompt: prompt.slice(0, 100),\n      timestamp: Date.now()\n    });\n    this.taskPatternCache.set(taskType, patterns.slice(-100)); // Keep last 100 patterns\n  }\n\n  async getModelState(modelName) {\n    return this.modelStateCache.get(modelName) || {\n      lastUsed: 0,\n      performance: {},\n      errors: 0\n    };\n  }\n\n  async updateModelState(modelName, metrics) {\n    const currentState = await this.getModelState(modelName);\n    this.modelStateCache.set(modelName, {\n      ...currentState,\n      ...metrics,\n      lastUsed: Date.now()\n    });\n  }\n\n  // Performance monitoring methods\n  startPerformanceMonitoring() {\n    // Monitor system metrics every 30 seconds\n    setInterval(() => this.checkSystemHealth(), 30000);\n    logger.info('Performance monitoring started');\n  }\n\n  checkSystemHealth() {\n    const memoryUsage = this.getMemoryUsage();\n    const avgLatency = this.metrics.totalLatency / this.metrics.requestCount || 0;\n\n    logger.info('System health metrics:', {\n      memoryUsage,\n      avgLatency,\n      requestCount: this.metrics.requestCount,\n      errors: this.metrics.errors,\n      cacheSize: this.responseCache.size\n    });\n\n    // Check if we need to switch to a smaller model\n    if (this.shouldSwitchModel(memoryUsage)) {\n      this.switchToSmallerModel();\n    }\n  }\n\n  getMemoryUsage() {\n    const used = process.memoryUsage();\n    const total = os.totalmem();\n    return {\n      heapUsed: (used.heapUsed / 1024 / 1024).toFixed(2) + 'MB',\n      heapTotal: (used.heapTotal / 1024 / 1024).toFixed(2) + 'MB',\n      rss: (used.rss / 1024 / 1024).toFixed(2) + 'MB',\n      percentage: ((used.heapUsed / total) * 100).toFixed(2) + '%'\n    };\n  }\n\n  shouldSwitchModel(memoryUsage) {\n    const usagePercentage = parseFloat(memoryUsage.percentage);\n    return usagePercentage > this.memoryThresholds.warning;\n  }\n\n  async switchToSmallerModel() {\n    const currentTime = Date.now();\n    // Prevent frequent switches (minimum 5 minutes between switches)\n    if (currentTime - this.metrics.lastSwitchTime < 300000) {\n      return;\n    }\n\n    logger.warn('Switching to smaller model due to high memory usage');\n    const fallbackModel = this.modelConfigs[this.isServerEnvironment ? 'server' : 'local'].fallback;\n    await this.warmupModel(fallbackModel);\n    this.metrics.lastSwitchTime = currentTime;\n  }\n\n  updateModelUsage(modelName) {\n    const currentCount = this.metrics.modelUsage.get(modelName) || 0;\n    this.metrics.modelUsage.set(modelName, currentCount + 1);\n  }\n\n  async warmupModel(modelName) {\n    try {\n      logger.info(`Warming up model: ${modelName}`);\n      const response = await fetch('http://localhost:11434/api/generate', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify({\n          model: modelName,\n          prompt: 'Warm up test.',\n          stream: false\n        })\n      });\n\n      if (!response.ok) {\n        throw new Error(`Failed to warm up model: ${response.statusText}`);\n      }\n\n      logger.info(`Model ${modelName} warmed up successfully`);\n      return true;\n    } catch (error) {\n      logger.error('Error warming up model:', error);\n      this.metrics.errors++;\n      return false;\n    }\n  }\n\n  getMetrics() {\n    return {\n      ...this.metrics,\n      avgLatency: this.metrics.totalLatency / this.metrics.requestCount || 0,\n      modelUsage: Object.fromEntries(this.metrics.modelUsage),\n      cacheStats: {\n        size: this.responseCache.size,\n        taskPatterns: Object.fromEntries(this.taskPatternCache)\n      }\n    };\n  }\n}\n\n// Create singleton instance\nconst modelSelectionService = new ModelSelectionService();\n\nexport default modelSelectionService;","import { getDatabase } from '../config/database.js';\nimport { getRedisClient } from '../config/redis.js';\nimport { getWeaviateClient } from '../config/weaviate.js';\nimport { logger } from './logger.js';\n\nexport async function checkHealth() {\n  const status = {\n    healthy: true,\n    services: {\n      mongodb: false,\n      redis: false,\n      weaviate: false\n    },\n    timestamp: new Date().toISOString()\n  };\n\n  try {\n    // Check MongoDB\n    const db = getDatabase();\n    await db.command({ ping: 1 });\n    status.services.mongodb = true;\n  } catch (error) {\n    logger.error('MongoDB health check failed:', error);\n    status.healthy = false;\n  }\n\n  try {\n    // Check Redis\n    const redis = getRedisClient();\n    await redis.ping();\n    status.services.redis = true;\n  } catch (error) {\n    logger.error('Redis health check failed:', error);\n    status.healthy = false;\n  }\n\n  try {\n    // Check Weaviate\n    const weaviate = getWeaviateClient();\n    await weaviate.schema.getter().do();\n    status.services.weaviate = true;\n  } catch (error) {\n    logger.error('Weaviate health check failed:', error);\n    status.healthy = false;\n  }\n\n  return status;\n}","import weaviate from 'weaviate-client';\nimport { logger } from '../utils/logger.js';\n\nlet client = null;\n\nexport async function setupWeaviate() {\n  try {\n    const url = process.env.WEAVIATE_URL;\n    const apiKey = process.env.WEAVIATE_API_KEY;\n\n    if (!url) {\n      throw new Error('WEAVIATE_URL environment variable is not set');\n    }\n\n    client = weaviate.client({\n      scheme: url.startsWith('https') ? 'https' : 'http',\n      host: url.replace(/(^\\w+:|^)\\/\\//, ''), // Remove protocol\n      headers: apiKey ? { 'X-API-Key': apiKey } : {},\n    });\n\n    // Initialize schema\n    await initializeSchema();\n    logger.info('Successfully connected to Weaviate');\n\n    return client;\n  } catch (error) {\n    logger.error('Weaviate connection error:', error);\n    throw error;\n  }\n}\n\nasync function initializeSchema() {\n  try {\n    // Define schema for emotional vectors\n    await createSchemaClass('EmotionalVector', {\n      class: 'EmotionalVector',\n      description: 'Stores emotional vector embeddings',\n      vectorizer: 'none', // We'll provide our own vectors\n      properties: [\n        {\n          name: 'vector',\n          dataType: ['number[]'],\n          description: '83-dimensional emotional vector',\n        },\n        {\n          name: 'timestamp',\n          dataType: ['date'],\n          description: 'When this emotional vector was recorded',\n        },\n        {\n          name: 'source',\n          dataType: ['string'],\n          description: 'Source of the emotional data',\n        }\n      ],\n    });\n\n    // Define schema for memory embeddings\n    await createSchemaClass('MemoryEmbedding', {\n      class: 'MemoryEmbedding',\n      description: 'Stores memory embeddings',\n      vectorizer: 'none',\n      properties: [\n        {\n          name: 'vector',\n          dataType: ['number[]'],\n          description: 'Memory embedding vector',\n        },\n        {\n          name: 'context',\n          dataType: ['string'],\n          description: 'Context of the memory',\n        },\n        {\n          name: 'timestamp',\n          dataType: ['date'],\n          description: 'When this memory was created',\n        },\n        {\n          name: 'type',\n          dataType: ['string'],\n          description: 'Type of memory (text, vision, audio, etc.)',\n        }\n      ],\n    });\n\n    logger.info('Weaviate schema initialized');\n  } catch (error) {\n    logger.error('Failed to initialize Weaviate schema:', error);\n    throw error;\n  }\n}\n\nasync function createSchemaClass(className, schema) {\n  try {\n    // Check if class exists\n    const classExists = await client.schema\n      .classGetter()\n      .withClassName(className)\n      .do();\n\n    if (!classExists) {\n      await client.schema\n        .classCreator()\n        .withClass(schema)\n        .do();\n      logger.info(`Created schema class: ${className}`);\n    }\n  } catch (error) {\n    if (!error.message.includes('already exists')) {\n      throw error;\n    }\n  }\n}\n\nexport function getWeaviateClient() {\n  if (!client) {\n    throw new Error('Weaviate not initialized. Call setupWeaviate first.');\n  }\n  return client;\n}\n\nexport async function closeWeaviate() {\n  if (client) {\n    client = null;\n    logger.info('Weaviate connection closed');\n  }\n}","import emotionalContextService from './services/emotionalContextService.js';\nimport humeService from './services/humeService.js';\nimport videoStreamService from './services/videoStreamService.js';\nimport customModelService from './services/customModelService.js';\nimport modelSelectionService from './services/modelSelectionService.js';\nimport { expressionColors, emotionToVector, vectorToEmotion } from './constants/emotions.js';\nimport { checkHealth } from './utils/healthCheck.js';\n\nclass MemoRable {\n  constructor(config = {}) {\n    this.config = {\n      humeApiKey: config.humeApiKey || process.env.HUME_API_KEY,\n      mongoUri: config.mongoUri || process.env.MONGODB_URI,\n      redisUrl: config.redisUrl || process.env.REDIS_URL,\n      weaviateUrl: config.weaviateUrl || process.env.WEAVIATE_URL,\n      ...config\n    };\n  }\n\n  async initialize() {\n    // Initialize all services\n    await emotionalContextService.initialize();\n    await humeService.connect();\n    await customModelService.initialize();\n    return this;\n  }\n\n  async checkHealth() {\n    return checkHealth();\n  }\n\n  // Emotion Processing\n  async processEmotion(input, type, contextId = null) {\n    return emotionalContextService.processEmotion(input, type, contextId);\n  }\n\n  async startEmotionalContext(contextId, options = {}) {\n    return emotionalContextService.startContext(contextId, options);\n  }\n\n  async stopEmotionalContext(contextId) {\n    return emotionalContextService.stopContext(contextId);\n  }\n\n  // Video Stream Processing\n  async startVideoStream(streamId, onEmotionUpdate, config = {}) {\n    return videoStreamService.startStream(streamId, onEmotionUpdate, config);\n  }\n\n  async addVideoFrame(streamId, frameData, timestamp) {\n    return videoStreamService.addFrame(streamId, frameData, timestamp);\n  }\n\n  async stopVideoStream(streamId) {\n    return videoStreamService.stopStream(streamId);\n  }\n\n  // Custom Model Management\n  async createCustomModel(userId, config) {\n    return customModelService.createTrainingJob(userId, config);\n  }\n\n  async getCustomModels(userId) {\n    return customModelService.getActiveModels(userId);\n  }\n\n  // Utility Functions\n  getEmotionColor(emotion) {\n    return expressionColors[emotion];\n  }\n\n  emotionToVector(emotion) {\n    return emotionToVector(emotion);\n  }\n\n  vectorToEmotion(vector) {\n    return vectorToEmotion(vector);\n  }\n\n  // Cleanup\n  async cleanup() {\n    await emotionalContextService.cleanup();\n    await humeService.close();\n    await videoStreamService.cleanup();\n    await customModelService.cleanup();\n  }\n}\n\n// Example usage:\n/*\nconst memorable = new MemoRable({\n  humeApiKey: 'your-hume-api-key',\n  // Optional: override other configurations\n});\n\nawait memorable.initialize();\n\n// Start an emotional context\nconst contextId = 'user123';\nawait memorable.startEmotionalContext(contextId, {\n  useVideo: true,\n  useVoice: true\n});\n\n// Process emotions\nawait memorable.processEmotion('I am happy', 'text', contextId);\n\n// Process video frames\nconst streamId = 'video123';\nawait memorable.startVideoStream(streamId, (emotionData) => {\n  console.log('Emotion update:', emotionData);\n});\n\n// Add video frames\nawait memorable.addVideoFrame(streamId, frameData);\n\n// Cleanup\nawait memorable.cleanup();\n*/\n\nexport default MemoRable;\n\n// Also export individual services for advanced usage\nexport {\n  emotionalContextService,\n  humeService,\n  videoStreamService,\n  customModelService,\n  modelSelectionService,\n  expressionColors,\n  emotionToVector,\n  vectorToEmotion,\n  checkHealth\n};"],"names":["logger","expressionColors","admiration","adoration","aestheticAppreciation","amusement","anger","annoyance","anxiety","awe","awkwardness","boredom","calmness","concentration","contemplation","confusion","contempt","contentment","craving","determination","disappointment","disapproval","disgust","distress","doubt","ecstasy","embarrassment","empathicPain","enthusiasm","entrancement","envy","excitement","fear","gratitude","guilt","horror","interest","joy","love","neutral","nostalgia","pain","pride","realization","relief","romance","sadness","sarcasm","satisfaction","sexualDesire","shame","surprise","surpriseNegative","surprisePositive","sympathy","tiredness","triumph","Object","keys","length","emotionToVector","emotion","color","parseInt","slice","vectorToEmotion","vector","toHex","n","hex","Math","round","toString","closestEmotion","minDistance","Infinity","emotionColor","entries","distance","colorDistance","color1","color2","r1","g1","b1","r2","g2","b2","sqrt","pow","humeService","constructor","this","ws","apiKey","process","env","HUME_API_KEY","endpoint","HUME_ENDPOINT","isConnected","activeStreams","Map","messageQueue","processingQueue","lastActivityTime","Date","now","inactivityTimeout","reconnectAttempts","maxReconnectAttempts","reconnectDelay","connect","config","Error","Promise","resolve","reject","params","URLSearchParams","wsUrl","WebSocket","on","info","setupInactivityCheck","data","handleMessage","error","handleError","handleDisconnect","setInterval","warn","reconnect","setTimeout","async","streamId","startStream","streamConfig","models","language","face","prosody","raw_text","rawText","reset_stream","resetStream","set","callbacks","buffer","sendMessage","type","stream_id","stopStream","get","delete","processText","text","id","sendData","processVoice","audioData","chunks","splitAudioIntoChunks","results","chunk","result","push","mergeResults","processFacial","imageData","chunkSize","offset","merged","emotions","forEach","existing","name","score","count","Array","from","map","messageId","stream","response","processEmotions","message","processMessageQueue","shift","send","JSON","stringify","unshift","parse","has","callback","confidence","filter","sort","a","b","close","videoStreamService","chunkDuration","maxResolution","width","height","processingInterval","onEmotionUpdate","streamContext","lastProcessed","onUpdate","faceConfig","processStreamBuffer","clearInterval","addFrame","frameData","timestamp","dimensions","getFrameDimensions","validateFrameDimensions","trimBuffer","chunkStartTime","chunkFrames","frame","selectedFrame","selectBestFrame","frameCount","selectedFrameTime","frames","floor","getStreamStatus","isActive","bufferSize","timeSinceLastProcess","getAllStreams","cleanup","getRedisClient","closeRedis","emotionalContextService","redis","activeContexts","emotionalBuffer","bufferTimeout","customModelEnabled","weights","evi","video","voice","initialize","setupEmotionalBuffers","loadCustomModel","exists","enabled","bufferKey","hSet","active_sessions","buffer_timeouts","startContext","contextId","options","context","startTime","useVideo","useVoice","useEVI","customModel","emotionalState","current","history","sources","emotionData","handleVideoEmotion","minConfidence","returnPoints","handleEVIEmotion","eviEmotion","updateEmotionalState","source","videoEmotion","dominant","handleVoiceEmotion","voiceData","processEmotionalBuffer","combinedVector","fill","totalWeight","sourceGroups","groupBySource","weight","calculateSourceConfidence","combineSourceEmotions","v","i","_","state","lastUpdate","reduce","groups","sum","e","getEmotionalContext","storedContext","hGetAll","stopContext","getDatabase","customModelService","db","apiEndpoint","activeModels","trainingJobs","loadActiveModels","collection","find","status","toArray","model","modelId","createTrainingJob","userId","jobId","job","description","labelSet","labels","dataConfig","includeExpressions","includeLanguage","includeProsody","created","updated","insertOne","collectTrainingData","updateJobStatus","emotionalHistory","getEmotionalHistory","labeledData","processTrainingData","storeTrainingData","startModelTraining","$gte","entry","processedEntry","generateLabels","expressions","validateTrainingEntry","Set","label","matchesLabelCriteria","add","trainingData","findOne","fetch","method","headers","body","ok","statusText","json","model_id","monitorTraining","handleTrainingComplete","handleTrainingFailed","lastUsed","updateOne","$set","getJobStatus","getActiveModels","values","deleteModel","modelSelectionService","isServerEnvironment","NODE_ENV","hasGPU","ENABLE_CUDA","modelConfigs","local","default","management","embedding","fallback","server","metrics","requestCount","totalLatency","errors","lastSwitchTime","modelUsage","memoryThresholds","warning","critical","responseCache","modelStateCache","taskPatternCache","cacheConfig","maxSize","ttl","criticalityThreshold","startPerformanceMonitoring","getModelConfig","environment","validateModel","modelName","some","ensureModel","getResourceLimits","maxMemory","maxThreads","batchSize","getOptimalConfig","resources","updateModelUsage","gpu","getMemoizedResponse","prompt","taskType","cacheKey","generateCacheKey","cached","memoizeResponse","criticality","size","oldestKey","updateTaskPattern","patterns","getModelState","performance","updateModelState","currentState","checkSystemHealth","memoryUsage","getMemoryUsage","avgLatency","cacheSize","shouldSwitchModel","switchToSmallerModel","used","total","os","totalmem","heapUsed","toFixed","heapTotal","rss","percentage","parseFloat","currentTime","fallbackModel","warmupModel","currentCount","getMetrics","fromEntries","cacheStats","taskPatterns","checkHealth","healthy","services","mongodb","weaviate","toISOString","command","ping","getWeaviateClient","schema","getter","do","humeApiKey","mongoUri","MONGODB_URI","redisUrl","REDIS_URL","weaviateUrl","WEAVIATE_URL","processEmotion","input","startEmotionalContext","stopEmotionalContext","startVideoStream","addVideoFrame","stopVideoStream","createCustomModel","getCustomModels","getEmotionColor"],"mappings":"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"}