diff --git a/Dockerfile b/Dockerfile index 6cf543d..9fd8e4e 100755 --- a/Dockerfile +++ b/Dockerfile @@ -2,6 +2,11 @@ FROM python:3.12-slim WORKDIR /app +# Point HuggingFace cache at the mounted data volume so from_pretrained() +# finds models downloaded by launch.sh into data/models/hub/ +ENV HF_HOME=/app/data/models +ENV HF_HUB_OFFLINE=1 + # Install system dependencies RUN apt-get update && apt-get install -y \ sox \ @@ -9,9 +14,11 @@ RUN apt-get update && apt-get install -y \ libsox-fmt-all \ ffmpeg \ git \ + libportaudio2 \ && rm -rf /var/lib/apt/lists/* -# Install Python dependencies +# Install Python dependencies (Force transformers 4.57.3 for offline Qwen3 ASR to work) +RUN pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu130 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt && \ pip install --no-deps git+https://github.com/rekuenkdr/Qwen3-TTS-streaming.git@97da215 diff --git a/Dockerfile_gpu b/Dockerfile_gpu index 11a382e..08d2d86 100644 --- a/Dockerfile_gpu +++ b/Dockerfile_gpu @@ -11,15 +11,22 @@ RUN apt-get update && apt-get install -y \ libsox-dev \ libsox-fmt-all \ ffmpeg \ + libportaudio2 \ && rm -rf /var/lib/apt/lists/* WORKDIR /app +# Point HuggingFace cache at the mounted data volume so from_pretrained() +# finds models downloaded by launch.sh into data/models/hub/ +ENV HF_HOME=/app/data/models +ENV HF_HUB_OFFLINE=1 + # Set Environment Variables for llama-cpp-python CUDA build ENV CMAKE_ARGS="-DGGML_CUDA=on" ENV FORCE_CMAKE=1 -# Install Python dependencies +# Install Python dependencies (Force transformers 4.57.3 for offline Qwen3 ASR to work) +RUN pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu130 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt && \ pip install --no-deps git+https://github.com/rekuenkdr/Qwen3-TTS-streaming.git@97da215 && \ diff --git a/compose.yml b/compose.yml index 61370ae..7600534 100755 --- a/compose.yml +++ b/compose.yml @@ -6,6 +6,7 @@ services: env_file: - .env container_name: fulloch-ai + network_mode: host devices: - /dev/snd:/dev/snd group_add: diff --git a/compose_gpu.yml b/compose_gpu.yml index e45e50a..b0d76a0 100755 --- a/compose_gpu.yml +++ b/compose_gpu.yml @@ -2,10 +2,12 @@ services: # Fulloch AI - GPU app: build: - context: . + context: . + dockerfile: Dockerfile_gpu env_file: - .env container_name: fulloch-ai + network_mode: host devices: - /dev/snd:/dev/snd group_add: diff --git a/launch.sh b/launch.sh index 20e84f9..a502e73 100755 --- a/launch.sh +++ b/launch.sh @@ -25,14 +25,54 @@ TTS_TINY_DIR="$HUB_DIR/models--hexgrad--Kokoro-82M" TTS_DIR="$HUB_DIR/models--Qwen--Qwen3-TTS-12Hz-1.7B-Base" # 1. Ensure Dependencies are installed -if ! command -v huggingface-cli &> /dev/null; then - echo "⬇️ huggingface-cli not found. Installing..." - pip install -U "huggingface_hub[cli]" +echo "🔍 Checking dependencies..." + +# Check for curl +if ! command -v curl &> /dev/null; then + echo "❌ curl not found. Please install curl first." + echo " e.g. sudo apt install curl" + exit 1 fi +# Check for wget +if ! command -v wget &> /dev/null; then + echo "❌ wget not found. Please install wget first." + echo " e.g. sudo apt install wget" + exit 1 +fi + +# Check for docker and docker compose +if ! command -v docker &> /dev/null; then + echo "❌ docker not found. Please install Docker first." + echo " See https://docs.docker.com/engine/install/" + exit 1 +fi + +if ! docker compose version &> /dev/null; then + echo "❌ docker compose not found. Please install the Docker Compose plugin." + echo " See https://docs.docker.com/compose/install/" + exit 1 +fi + +# Check for hf (install via standalone installer if missing) +if ! command -v hf &> /dev/null; then + echo "⬇️ hf not found. Installing via standalone installer..." + curl -LsSf https://hf.co/cli/install.sh | bash + # Source updated PATH so hf is available in this session + export PATH="$HOME/.local/bin:$PATH" + if ! command -v hf &> /dev/null; then + echo "❌ hf still not found after install." + echo " Try running: curl -LsSf https://hf.co/cli/install.sh | bash" + echo " Then restart your shell and run ./launch.sh again." + exit 1 + fi +fi + +echo "✅ All dependencies found." + # 2. Create Directory Structure echo "📂 Checking directory structure..." -mkdir -p "$HUB_DIR" +mkdir -p "$HUB_DIR" "$GRAMMAR_DIR" # 2a. Check for config.yml CONFIG_FILE="$(pwd)/data/config.yml" @@ -51,6 +91,23 @@ else echo "✅ config.yml exists." fi +# 2b. Check for .env +ENV_FILE="$(pwd)/.env" +ENV_EXAMPLE="$(pwd)/.env.example" + +if [ ! -f "$ENV_FILE" ]; then + echo "📝 .env not found. Creating from template..." + cp "$ENV_EXAMPLE" "$ENV_FILE" + echo "" + echo "⚠️ Please edit .env with your credentials before continuing." + echo " See .env.example for documentation on each variable." + echo "" + echo " Run ./launch.sh again when ready." + exit 0 +else + echo "✅ .env exists." +fi + # 3. Check and Download json.gbnf if [ ! -f "$GRAMMAR_DIR/json.gbnf" ]; then if ask_download "json.gbnf (grammar file)"; then @@ -68,9 +125,8 @@ fi if [ ! -f "$BASE_DIR/$QWEN_FILE" ]; then if ask_download "Qwen3 4B SLM (2.5GB)"; then echo "⬇️ Downloading $QWEN_FILE..." - huggingface-cli download "$QWEN_REPO" "$QWEN_FILE" \ - --local-dir "$BASE_DIR" \ - --local-dir-use-symlinks False + hf download "$QWEN_REPO" "$QWEN_FILE" \ + --local-dir "$BASE_DIR" else echo "⏭️ Skipping Qwen3 SLM" fi @@ -82,7 +138,7 @@ fi if [ ! -d "$TTS_DIR" ]; then if ask_download "Qwen3 TTS (3.4GB)"; then echo "⬇️ Downloading Qwen3 TTS..." - huggingface-cli download Qwen/Qwen3-TTS-12Hz-1.7B-Base \ + hf download Qwen/Qwen3-TTS-12Hz-1.7B-Base \ --cache-dir "$HUB_DIR" else echo "⏭️ Skipping Qwen3 TTS" @@ -95,7 +151,7 @@ fi if [ ! -d "$TTS_TINY_DIR" ]; then if ask_download "Kokoro-82M TTS Tiny (200MB)"; then echo "⬇️ Downloading Kokoro-82M..." - huggingface-cli download hexgrad/Kokoro-82M \ + hf download hexgrad/Kokoro-82M \ --cache-dir "$HUB_DIR" else echo "⏭️ Skipping Kokoro-82M" @@ -108,7 +164,7 @@ fi if [ ! -d "$ASR_DIR" ]; then if ask_download "Qwen3 ASR (3.4GB)"; then echo "⬇️ Downloading Qwen3 ASR..." - huggingface-cli download Qwen/Qwen3-ASR-1.7B \ + hf download Qwen/Qwen3-ASR-1.7B \ --cache-dir "$HUB_DIR" else echo "⏭️ Skipping Qwen3 ASR" @@ -121,7 +177,7 @@ fi if [ ! -d "$ASR_TINY_DIR" ]; then if ask_download "Moonshine Tiny ASR (60MB)"; then echo "⬇️ Downloading Moonshine Tiny..." - huggingface-cli download UsefulSensors/moonshine-tiny \ + hf download UsefulSensors/moonshine-tiny \ --cache-dir "$HUB_DIR" else echo "⏭️ Skipping Moonshine Tiny" @@ -134,15 +190,13 @@ fi read -p "Are you using a GPU? (y/n): " response response=${response,,} if [[ "$response" == "y" || "$response" == "yes" ]]; then - mv Dockerfile Dockerfile_cpu - mv Dockerfile_gpu Dockerfile - mv compose.yml compose_cpu.yml - mv compose_gpu.yml compose.yml + COMPOSE_FILE="compose_gpu.yml" echo "✅ Using GPU enabled containers" else + COMPOSE_FILE="compose.yml" echo "✅ Using default containers" fi # 8. Launch Docker Compose echo "🚀 All files checked. Starting services..." -docker compose up -d +docker compose -f "$COMPOSE_FILE" up -d diff --git a/requirements.txt b/requirements.txt index 89808d5..b86cd2d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,17 +4,17 @@ setuptools==80.9.0 xmltodict==1.0.2 word2number==1.1 beautifulsoup4==4.14.2 +python-dotenv==1.2.1 # Audio processing sounddevice>=0.5.0 soundfile>=0.13.0 # AI and ML -torch>=2.4.0 -torchaudio>=2.4.0 -transformers==4.57.3 +transformers==4.57.6 kokoro>=0.9.4 accelerate==1.12.0 +onnxruntime>=1.18.0 llama_cpp_python>=0.3.16 qwen-asr==0.0.6 @@ -28,6 +28,6 @@ spotipy==2.25.1 pyairtouch==3.1.0 thinqconnect==1.0.8 bscpylgtv==0.5.0 -google-auth==2.0.0 -google-auth-oauthlib==0.4.0 -google-api-python-client==2.0.0 +google-api-python-client==2.187.0 +google-auth==2.41.1 +google-auth-oauthlib==1.2.3