A.D.A V2 (Advanced Design Assistant)

repository·main·Indexed 20 days ago

https://github.com/nazirlouis/ada_v2

A multimodal AI assistant and Electron desktop application integrating Google's Gemini 2.5 Native Audio with computer vision, gesture control, and 3D CAD generation. It features a Python backend for hardware logic, including 3D printer integration (Klipper, OctoPrint, PrusaLink), TP-Link Kasa smart home control, and MediaPipe-based face authentication.

Tokens
7.2K
Snippets
13
Records
28
Agent score
68%

What's inside ada-v2

  1. Security and Data Privacy in A.D.A V2

    main

    A.D.A V2 implements several security measures to protect user data:

    • API Keys: Stored locally in a .env file and excluded from version control.
    • Biometric Data: Face data is processed locally and is never uploaded to the cloud.
    • Data Locality: All project data is stored on your local machine; no cloud storage is used.
    • Action Confirmation: High-impact actions (such as writing files, CAD generation, or web automation) may require explicit user approval.
    WARNING

    Never share your .env file or reference.jpg. These contain sensitive credentials and biometric data.

  2. Understand the A.D.A V2 Project Structure

    main

    The project is divided into three main layers: a Python backend for AI and hardware logic, a React frontend for the user interface, and an Electron wrapper for the desktop application.

    Backend (backend/)

    • ada.py: Integrates with the Gemini Live API.
    • server.py: The FastAPI and Socket.IO server.
    • cad_agent.py: Orchestrates CAD generation.
    • printer_agent.py: Handles 3D printer discovery and slicing.
    • web_agent.py: Manages browser automation via Playwright.
    • kasa_agent.py: Controls TP-Link smart home devices.
    • authenticator.py: Implements MediaPipe-based face authentication.
    • project_manager.py: Manages project context.
    • tools.py: Defines tools available to Gemini.
    • reference.jpg: Required. Your face photo for authentication.

    Frontend (src/)

    • React-based UI components and main application logic.

    Desktop (electron/)

    • Electron main process for window management and IPC setup.

    Data and Config

    • projects/: Directory where user project data is automatically stored (do not commit this to Git).
    • .env: File for storing sensitive API keys (do not commit this to Git).
  3. Run ADA V2

    main

    You can run the application in two ways. Ensure your ada_v2 Conda environment is active.

    Option 1: Single Terminal (Easy Mode)

    This mode automatically starts the backend in the background.

    conda activate ada_v2
    npm run dev

    Option 2: Two Terminals (Developer Mode)

    Recommended for debugging as it allows you to view Python logs.

    Terminal 1 (Backend):

    conda activate ada_v2
    python backend/server.py

    Terminal 2 (Frontend):

    npm run dev
    # Terminal 1
    conda activate ada_v2
    python backend/server.py
    
    # Terminal 2
    npm run dev
  4. Setup 3D Printing and Slicing

    main

    ADA V2 can slice STL files and send them to compatible 3D printers.

    Supported Hardware

    • Klipper/Moonraker (e.g., Creality K1, Voron)
    • OctoPrint
    • PrusaLink (Experimental)

    Installation Steps

    1. Install a Slicer: Download and install OrcaSlicer (recommended) or PrusaSlicer. Run it once to ensure profiles are created. ADA will attempt to auto-detect the installation path.
    2. Connect Printer:
      • Ensure the printer and computer are on the same Wi-Fi network.
      • Open the Printer Window in ADA (Cube icon).
      • ADA uses mDNS to scan for printers automatically.
      • Manual Connection: If auto-discovery fails, use the "Add Printer" button and enter the printer's IP address (e.g., 192.168.1.50).
  5. Development Workflow Tips

    main

    When developing A.D.A V2, use these patterns to speed up your workflow:

    • Backend Debugging: Run the backend separately using python backend/server.py to view Python-specific logs directly.
    • Frontend Development: Use npm run dev to run the React frontend without launching the Electron wrapper. This allows for faster hot-reloading.
    • Git Hygiene: Ensure the projects/ folder is added to your .gitignore to avoid committing user data.
  6. Configure Gemini API Key

    main

    ADA V2 requires a Google Gemini API key for voice and intelligence capabilities.

    1. Obtain a key from Google AI Studio.
    2. Create a file named .env in the root ada_v2 folder (the same level as README.md).
    3. Add the following line to the file, replacing your_api_key_here with your actual key:

    GEMINI_API_KEY=your_api_key_here

    Note: Do not use quotes or spaces around the key. Ensure the .env file is in the root directory, not inside the backend/ folder.

    GEMINI_API_KEY=your_api_key_here
  7. Configure Face Authentication

    main

    To enable secure biometric login via MediaPipe Face Landmarker:

    1. Prepare a clear photo of your face.
    2. Rename the file to reference.jpg.
    3. Place the file in the ada_v2/backend folder.
    4. To enable or disable this feature, modify the face_auth_enabled key in settings.json.
  8. Quick Start for Experienced Developers

    main

    Follow these steps to clone, configure, and run ADA V2 using Conda and npm. This assumes you already have Git, Conda, and Node.js installed.

    1. Clone and enter:
      git clone https://github.com/nazirlouis/ada_v2.git && cd ada_v2
    2. Setup Python environment (Requires Python 3.11):
      conda create -n ada_v2 python=3.11 -y && conda activate ada_v2
      brew install portaudio  # macOS only (for PyAudio)
      pip install -r requirements.txt
      playwright install chromium
    3. Setup frontend:
      npm install
    4. Configure Environment: Create a .env file in the root directory with your Gemini API key:
      echo "GEMINI_API_KEY=your_key_here" > .env
    5. Run the application:
      conda activate ada_v2 && npm run dev
    # 1. Clone and enter
    git clone https://github.com/nazirlouis/ada_v2.git && cd ada_v2
    
    # 2. Create Python environment (Python 3.11)
    conda create -n ada_v2 python=3.11 -y && conda activate ada_v2
    brew install portaudio  # macOS only (for PyAudio)
    pip install -r requirements.txt
    playwright install chromium
    
    # 3. Setup frontend
    npm install
    
    # 4. Create .env file
    echo "GEMINI_API_KEY=your_key_here" > .env
    
    # 5. Run!
    conda activate ada_v2 && npm run dev
  9. Application Lifecycle and Backend Orchestration

    main

    The application manages a dual-process architecture: an Electron frontend and a Python backend.

    Startup Sequence:

    1. The app checks if port 8000 is already in use via checkBackendPort(8000).
    2. If the port is free, it spawns the Python backend using startPythonBackend() (executing backend/server.py).
    3. The app polls http://127.0.0.1:8000/status via waitForBackend() until a 200 OK response is received.
    4. Once the backend is healthy, the Electron mainWindow is created and loaded.

    Shutdown Sequence:

    • On will-quit, the application attempts to kill the Python backend process.
    • On Windows, it uses taskkill /pid <pid> /f /t to ensure the entire process tree is terminated.
    • On Unix-like systems, it sends a SIGKILL signal.
  10. Manage Modular UI Layout and Z-Index

    main

    The application features a 'Modular Mode' where UI elements (windows) can be positioned and sized independently.

    Window Management

    • Positioning: Elements use elementPositions (x, y) and elementSizes (w, h) to define their footprint.
    • Stacking Order: The zIndexOrder array determines which windows appear on top. The last element in the array has the highest z-index.
    • Bring to Front: Use the bringToFront(id) function to move a specific window to the top of the stack.
    • Viewport Clamping: The clampToViewport utility ensures windows do not move outside the visible screen area, accounting for a top bar margin.
  11. How Audio and Video Input Works

    main

    The backend manages an AudioLoop that processes real-time audio and video. Clients can start the loop, send video frames, and provide text input. If face_auth_enabled is true in settings, the start_audio command will be blocked until the FaceAuthenticator confirms the user's identity.

    // Start the audio/vision session
    socket.emit('start_audio', { device_index: 0 });
    
    // Send video frames for vision capabilities
    socket.emit('video_frame', { image: base64OrBlobData });
    
    // Send text input (can be used alongside video frames)
    socket.emit('user_input', { text: 'What do you see?' });
  12. How gesture-based interaction works in A.D.A V2

    main

    A.D.A V2 uses hand tracking to enable gesture-based control of the UI. The system interprets specific hand landmarks to trigger actions:

    • Cursor Movement: The cursor position is derived from hand landmarks and mapped to screen coordinates.
    • Pinch Gesture (Clicking): Triggered when the distance between the index finger tip and the thumb tip falls below a specific threshold (0.05). A pinch triggers a click() event on the element currently under the cursor.
    • Fist Gesture (Dragging): Detected when all finger tips are closer to the wrist than their respective MCP (knuckle) joints. When a fist is detected over a draggable element (like cad, browser, kasa, or printer), the system enters a drag state.
    • Stable Dragging: To prevent jitter, dragging is controlled by the movement of the wrist rather than the index finger. The system calculates the delta between the current wrist position and the last known wrist position to update the element's coordinates.
    • Snapping: The cursor automatically snaps to interactive elements (buttons, inputs, selects, or .draggable elements) when within a certain threshold, providing visual feedback via a snap-highlight class and glow effects.
    // Pinch Detection (Distance between Index and Thumb)
    const distance = Math.sqrt(
        Math.pow(indexTip.x - thumbTip.x, 2) + Math.pow(indexTip.y - thumbTip.y, 2)
    );
    
    const isPinchNow = distance < 0.05; // Threshold
    if (isPinchNow && !isPinching) {
        // Click Triggered
        const el = document.elementFromPoint(finalX, finalY);
        if (el) {
            const clickable = el.closest('button, input, a, [role="button"]');
            if (clickable && typeof clickable.click === 'function') {
                clickable.click();
            } else if (typeof el.click === 'function') {
                el.click();
            }
        }
    }
    
    // Fist Detection for Gesture-Based Dragging
    const isFist = isFingerFolded(8, 5) && isFingerFolded(12, 9) && isFingerFolded(16, 13) && isFingerFolded(20, 17);
    
    if (isFist && activeDragElementRef.current) {
        const dx = wristScreenX - lastWristPosRef.current.x;
        const dy = wristScreenY - lastWristPosRef.current.y;
        if (Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5) {
            updateElementPosition(activeDragElementRef.current, dx, dy);
        }
        lastWristPosRef.current = { x: wristScreenX, y: wristScreenY };
    }