# 
# This is the Dockerfile for the initial setup of the 
# SO-101 robots using LeRobot on an Intel machine without 
# support for an external graphics card (e.g. no CUDE). This
# is meant to showcase a clean environment.
#
# This can be used as a base image for further 
# research, as is done in ARC. But this file is just to get 
# up and running. You should not edit this, but rather extend 
# it within your experiments 
#
#
# BUILDING
# ===========================================================
#
#       docker build -f Dockerfile.intel_xpu -t lerobot-intel_xpu .
#
#
#
# CREATING THE CONTAINER
# ===========================================================
# 
# Use the below flags:
#
#       --gpus all: Grants the container access to the integrated 
#                   GPUs on your system.
#
#       --privileged and -v /dev:/dev: Crucial for capturing 
#                   data streams from cameras (/dev/video*) and 
#                   communicating with the SO-101 motor controllers 
#                   (/dev/ttyUSB* or /dev/ttyACM*).
#
#       --shm-size=128g: Prevents "bus error" crashes during 
#                   training by providing enough shared memory 
#                   for large robotic datasets. 
#
#       - v /run/user/$(id -u)/pulse:
#                   The last three with pulse, they are to allowing access
#                   for audio from the container to be played on the host
#
#
#        docker run -it \
#            --name lerobot_so101_intel_xpu \
#            --env="DISPLAY=$DISPLAY" \
#            --privileged \
#            --network host \
#            --shm-size=128g \
#            -v ~/code/research/arc/platforms/so101/data:/data \
#            -v /dev:/dev \
#            -v /run/user/$(id -u)/pulse/native:/run/user/$(id -u)/pulse/native \
#            -v ~/.config/pulse/cookie:/root/.config/pulse/cookie \
#            lerobot-intel_xpu bash
#
#
#
# VERIFICATION
# ===========================================================
# 
# Once inside the container, run these commands to confirm 
# everything is connected:
#
#
#   GPU Availablility: 
#
#       python3 -c "import openvino as ov; print(ov.Core().available_devices)"
#
#       Output:
#           ['CPU', 'GPU']
#
#   XPU Support:
#    
#       python3 - << 'EOF'
#       import torch
#       print("Torch:", torch.__version__)
#       print("XPU available:", torch.xpu.is_available())
#       print("XPU device count:", torch.xpu.device_count())
#       print("XPU name:", torch.xpu.get_device_name(0) if torch.xpu.is_available() else None)
#       EOF
#
#       Output: 
#            Torch: 2.10.0+xpu
#            XPU available: True
#            XPU device count: 1
#            XPU name: Intel(R) Graphics [0xb08f]
#
#    Cameras: to ensure cameras are detected
#
#           v4l2-ctl --list-devices 
#
#    Robot: to find your SO-101 ports. 
#
#           ls /dev/ttyACM* 
#               - or - 
#           ls /dev/ttyUSB*  
#
#
# DOCKER DEFINITION
# ===========================================================
#FROM intel/intel-optimized-pytorch:latest
FROM ubuntu:24.04

# Set environment variables
ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHONUNBUFFERED=1

# Add a User with Sudo rights:
# that matches your host ID but has "passwordless sudo" access:
ARG USER_ID=1000
ARG GROUP_ID=1000

# 1. Update apt and install sudo
# 2. Check if UID/GID 1000 exists and delete them to avoid conflicts
# 3. Create lerobotuser and set permissions
RUN apt-get update && apt-get install -y \
    sudo \
    python3 python3-pip python3-venv python3-dev \ 
    build-essential git && \
    if getent passwd ${USER_ID} ; then userdel -f $(getent passwd ${USER_ID} | cut -d: -f1); fi && \
    if getent group ${GROUP_ID} ; then groupdel $(getent group ${GROUP_ID} | cut -d: -f1); fi && \
    groupadd -g ${GROUP_ID} lerobotuser && \
    useradd -m -u ${USER_ID} -g lerobotuser -s /bin/bash lerobotuser && \
    usermod -aG dialout,tty lerobotuser && \
    echo "lerobotuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \
    rm -rf /var/lib/apt/lists/*

# Install system dependencies for LeRobot, cameras, and robotics
RUN apt-get update && apt-get install -y --no-install-recommends \
    git \
    cmake \
    vim \
    build-essential \
    libgl1 \
    libglx-mesa0 \
    libglib2.0-0 \
    ffmpeg \
    v4l-utils \
    usbutils \
    speech-dispatcher \
    speech-dispatcher-espeak-ng \
    espeak-ng \
    pulseaudio-utils \
    cpuid \
    pciutils \
    && rm -rf /var/lib/apt/lists/*

##############################################################
# Edge Control for Industrial (ECI) Repositories
##############################################################

# Install wget and prerequisites
RUN apt-get update && apt-get install -y wget gnupg

# Add Intel ECI GPG key
RUN wget -O- https://eci.intel.com/repos/gpg-keys/GPG-PUB-KEY-INTEL-ECI.gpg \
    | tee /usr/share/keyrings/eci-archive-keyring.gpg > /dev/null

# 3. Add the ECI APT repository (binary + source)
RUN bash -c ' \
    . /etc/os-release && \
    echo "deb [signed-by=/usr/share/keyrings/eci-archive-keyring.gpg] https://eci.intel.com/repos/${VERSION_CODENAME} isar main" \
        > /etc/apt/sources.list.d/eci.list && \
    echo "deb-src [signed-by=/usr/share/keyrings/eci-archive-keyring.gpg] https://eci.intel.com/repos/${VERSION_CODENAME} isar main" \
        >> /etc/apt/sources.list.d/eci.list \
'

# Add apt pinning rules
RUN bash -c ' \
    echo -e "Package: *\nPin: origin eci.intel.com\nPin-Priority: 1000" \
        > /etc/apt/preferences.d/isar && \
    echo -e "\nPackage: libflann*\nPin: version 1.19.*\nPin-Priority: -1\n\nPackage: flann*\nPin: version 1.19.*\nPin-Priority: -1" \
        >> /etc/apt/preferences.d/isar \
'

# Update apt
RUN apt-get update


##############################################################
# oneAPI Repositories
##############################################################

# Add Intel oneAPI GPG key
RUN wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB \
    | gpg --dearmor \
    | tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null

# Add the oneAPI APT repository
RUN echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] \
https://apt.repos.intel.com/oneapi all main" \
    > /etc/apt/sources.list.d/oneAPI.list

# Add apt pinning for oneAPI runtimes
RUN bash -c ' \
    echo -e "Package: intel-oneapi-runtime-*\nPin: version 2025.1.*\nPin-Priority: 1001" \
        > /etc/apt/preferences.d/oneapi \
'

# Update apt
RUN apt-get update


##############################################################
# OpenVino Repository
##############################################################
# Add OpenVINO APT repositories for Ubuntu 24.04
RUN echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] \
https://apt.repos.intel.com/openvino/2023 ubuntu22 main" \
    > /etc/apt/sources.list.d/intel-openvino-2023.list

RUN echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] \
https://apt.repos.intel.com/openvino/2024 ubuntu22 main" \
    > /etc/apt/sources.list.d/intel-openvino-2024.list


# Update apt
RUN apt-get update


##############################################################
# Mesa Graphics
##############################################################
# Upgrade system 
RUN apt-get update && apt-get full-upgrade -y

#Install Mesa graphics stack
RUN apt-get install -y \
    vainfo \
    libegl-mesa0 \
    libgl1-mesa-dri \
    libgbm1 \
    libglx-mesa0 \
    mesa-libgallium \
    mesa-va-drivers \
    mesa-vdpau-drivers \
    mesa-vulkan-drivers \
    xwayland


##############################################################
# Intel® Level Zero and OpenCL™ Graphics
##############################################################
# Install Intel Level Zero + OpenCL GPU runtime and dependencies
RUN apt-get update && apt-get install -y \
    libgtk-3-0 \
    libgl1 \
    clinfo \
    libze1 \
    libigdgmm12 \
    libigc1 \
    libigdfcl1 \
    intel-opencl-icd

# Install Intel PTI GPU tools (optional but useful for debugging)
RUN apt-get install -y \
    intel-pti-gpu-samples \
    intel-pti-gpu-tracers


# Install OpenVino
RUN pip install --break-system-packages --no-cache-dir openvino openvino-dev

# Set the working directory
WORKDIR /workspace

# In some images the /workspace directory defaults with readme files, 
# examples, etc. Let's ensure the dir is empty before we clone and install: 
RUN rm -rf ./* && \
    git clone https://github.com/huggingface/lerobot.git . && \
    git checkout 4eecbad32b0380c64bd5574bbf74e56e5255bdea

# 1. Install the specific version-controlled dependencies to resolve "Dependency Hell"
# Note: numpy < 2.2.0 is the "sweet spot" for LeRobot + OpenVINO
RUN pip install --no-cache-dir --break-system-packages \
    "numpy>=2.0.0,<2.2.0" \
    "intel-extension-for-pytorch==2.5.0" \
    "opencv-python-headless>=4.10.0.84" \
    "pyrealsense2"

# 2. Install the XPU-specific PyTorch binaries
RUN pip install --no-cache-dir --break-system-packages \
    torch==2.10.0+xpu \
    torchvision==0.25.0+xpu \
    --index-url https://download.pytorch.org/whl/xpu

# 3. Finalize LeRobot installation (using -e . to install the cloned repo)
# We use --no-deps if you want to ensure it doesn't overwrite your manual torch/numpy fixes
RUN pip install --no-cache-dir --break-system-packages -e . 

  
    # 2. Install LeRobot. 
    # IMPORTANT: We use -e to install the local repo, 
    # but we must ensure it doesn't pull in a newer NumPy.
RUN  pip install --break-system-packages --no-cache-dir \
        transformers \
        accelerate \
        timm \
        einops \
        num2words \
        -e ".[feetech, dynamixel, aloha, intelrealsense, async]" 

# 4. Final verification check
RUN python3 -c "import torch; import lerobot; print('XPU:', torch.xpu.is_available())"

# Set the LeRobot home directory to your mounted volume path
ENV HF_LEROBOT_HOME=/data/lerobot_cache

USER lerobotuser

# Entry point
CMD ["/bin/bash"]


