diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..020b9ec --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +__pycache__ +*.pyc +*.pyo +*.pyd +*.egg-info +dist/ +build/ +.git +.env +.assets +node_modules/ +bridge/dist/ +workspace/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8132747 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim + +# Install Node.js 20 for the WhatsApp bridge +RUN apt-get update && \ + apt-get install -y --no-install-recommends curl ca-certificates gnupg git && \ + mkdir -p /etc/apt/keyrings && \ + curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ + echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list && \ + apt-get update && \ + apt-get install -y --no-install-recommends nodejs && \ + apt-get purge -y gnupg && \ + apt-get autoremove -y && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +# Install Python dependencies first (cached layer) +COPY pyproject.toml README.md LICENSE ./ +RUN mkdir -p nanobot bridge && touch nanobot/__init__.py && \ + uv pip install --system --no-cache . && \ + rm -rf nanobot bridge + +# Copy the full source and install +COPY nanobot/ nanobot/ +COPY bridge/ bridge/ +RUN uv pip install --system --no-cache . + +# Build the WhatsApp bridge +WORKDIR /app/bridge +RUN npm install && npm run build +WORKDIR /app + +# Create config directory +RUN mkdir -p /root/.nanobot + +# Gateway default port +EXPOSE 18790 + +ENTRYPOINT ["nanobot"] +CMD ["status"] diff --git a/README.md b/README.md index f120e3b..55c6091 100644 --- a/README.md +++ b/README.md @@ -247,6 +247,20 @@ nanobot gateway ## ⚙️ Configuration +Config file: `~/.nanobot/config.json` + +### Providers + +| Provider | Purpose | Get API Key | +|----------|---------|-------------| +| `openrouter` | LLM (recommended, access to all models) | [openrouter.ai](https://openrouter.ai) | +| `anthropic` | LLM (Claude direct) | [console.anthropic.com](https://console.anthropic.com) | +| `openai` | LLM (GPT direct) | [platform.openai.com](https://platform.openai.com) | +| `groq` | LLM + **Voice transcription** (Whisper) | [console.groq.com](https://console.groq.com) | +| `gemini` | LLM (Gemini direct) | [aistudio.google.com](https://aistudio.google.com) | + +> **Note**: Groq provides free voice transcription via Whisper. If configured, Telegram voice messages will be automatically transcribed. +
Full config example @@ -260,6 +274,9 @@ nanobot gateway "providers": { "openrouter": { "apiKey": "sk-or-v1-xxx" + }, + "groq": { + "apiKey": "gsk_xxx" } }, "channels": { @@ -313,6 +330,30 @@ nanobot cron remove
+## 🐳 Docker + +Build and run nanobot in a container: + +```bash +# Build the image +docker build -t nanobot . + +# Initialize config (first time only) +docker run -v ~/.nanobot:/root/.nanobot --rm nanobot onboard + +# Edit config on host to add API keys +vim ~/.nanobot/config.json + +# Run gateway (connects to Telegram/WhatsApp) +docker run -v ~/.nanobot:/root/.nanobot -p 18790:18790 nanobot gateway + +# Or run a single command +docker run -v ~/.nanobot:/root/.nanobot --rm nanobot agent -m "Hello!" +docker run -v ~/.nanobot:/root/.nanobot --rm nanobot status +``` + +> **Tip**: Mount `~/.nanobot` so your config and workspace persist across container restarts. + ## 📁 Project Structure ``` diff --git a/test_docker.sh b/test_docker.sh new file mode 100755 index 0000000..a90e080 --- /dev/null +++ b/test_docker.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +set -euo pipefail + +IMAGE_NAME="nanobot-test" + +echo "=== Building Docker image ===" +docker build -t "$IMAGE_NAME" . + +echo "" +echo "=== Running 'nanobot onboard' ===" +docker run --name nanobot-test-run "$IMAGE_NAME" onboard + +echo "" +echo "=== Running 'nanobot status' ===" +STATUS_OUTPUT=$(docker commit nanobot-test-run nanobot-test-onboarded > /dev/null && \ + docker run --rm nanobot-test-onboarded status 2>&1) || true + +echo "$STATUS_OUTPUT" + +echo "" +echo "=== Validating output ===" +PASS=true + +check() { + if echo "$STATUS_OUTPUT" | grep -q "$1"; then + echo " PASS: found '$1'" + else + echo " FAIL: missing '$1'" + PASS=false + fi +} + +check "nanobot Status" +check "Config:" +check "Workspace:" +check "Model:" +check "OpenRouter API:" +check "Anthropic API:" +check "OpenAI API:" + +echo "" +if $PASS; then + echo "=== All checks passed ===" +else + echo "=== Some checks FAILED ===" + exit 1 +fi + +# Cleanup +echo "" +echo "=== Cleanup ===" +docker rm -f nanobot-test-run 2>/dev/null || true +docker rmi -f nanobot-test-onboarded 2>/dev/null || true +docker rmi -f "$IMAGE_NAME" 2>/dev/null || true +echo "Done."