From f4fa01ef7ec58272b1be6c9018b5b702f4317cb8 Mon Sep 17 00:00:00 2001 From: AB-UK Date: Wed, 18 Mar 2026 13:04:13 +0000 Subject: [PATCH] Added doker compose --- .env_example | 3 ++ .gitignore | 3 ++ README.md | 54 ++++++++++++++++++++++++- docker-compose.yml | 60 ++++++++++++++++++++++++++++ furumi-agent/src/config.rs | 4 ++ furumi-agent/src/ingest/normalize.rs | 8 +++- 6 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 .env_example create mode 100644 docker-compose.yml diff --git a/.env_example b/.env_example new file mode 100644 index 0000000..bd16954 --- /dev/null +++ b/.env_example @@ -0,0 +1,3 @@ +OLLAMA_URL=https://ollama.host.com +OLLAMA_AUTH="Basic " +#OLLAMA_AUTH="Bearer " diff --git a/.gitignore b/.gitignore index ea8c4bf..eeb9a57 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ /target +/inbox +/storage +.env diff --git a/README.md b/README.md index 522a653..bf06c3c 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,59 @@ All options can be set via CLI flags or environment variables. | `--oidc-client-secret` | `FURUMI_PLAYER_OIDC_CLIENT_SECRET` | — | OIDC client secret | | `--oidc-redirect-url` | `FURUMI_PLAYER_OIDC_REDIRECT_URL` | — | OIDC redirect URL | | `--oidc-session-secret` | `FURUMI_PLAYER_OIDC_SESSION_SECRET` | *(random)* | Session HMAC secret | - + +## Docker Compose + +The easiest way to run the entire backend stack (PostgreSQL, Agent, Web Player, and gRPC Server) is using Docker Compose. + +### Quick Start + +1. **Prepare directories**: + ```bash + mkdir -p inbox storage + ``` +2. **Start the services**: + ```bash + docker compose up -d + ``` +3. **Check logs**: + ```bash + docker compose logs -f + ``` + +The following services will be available: +- **Web Player**: [http://localhost:8085](http://localhost:8085) +- **Agent Admin UI**: [http://localhost:8090](http://localhost:8090) +- **Metrics**: [http://localhost:9090/metrics](http://localhost:9090/metrics) + +> [!NOTE] +> The Agent expects Ollama to be running. By default, it tries to connect to the host at `http://localhost:11434`. + +### Reference Commands + +- **Start**: `docker compose up -d` +- **Stop**: `docker compose stop` +- **Stop and remove containers**: `docker compose down` +- **Clear database and storage**: `docker compose down -v` + +### Environment Variables + +To configure the Agent (especially for remote Ollama or private models) and database, create an `.env` file in the root directory: + +```env +# Database +POSTGRES_PASSWORD=secure-password + +# LLM (Ollama) +OLLAMA_URL=http://your-ollama-host:11434 +OLLAMA_AUTH="Bearer your-token" + +# Server Security +FURUMI_TOKEN=secure-server-token +``` + +For more options, refer to the [Configuration](#configuration) section. + ## Docker Pre-built images are available on Docker Hub: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4632462 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,60 @@ +services: + db: + image: postgres:17-alpine + container_name: furumi-db + environment: + POSTGRES_DB: ${POSTGRES_DB:-furumi} + POSTGRES_USER: ${POSTGRES_USER:-furumi} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-furumi} + volumes: + - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U furumi -d furumi"] + interval: 5s + timeout: 5s + retries: 5 + + agent: + build: + context: . + dockerfile: Dockerfile.agent + container_name: furumi-agent + depends_on: + db: + condition: service_healthy + ports: + - "8090:8090" + environment: + FURUMI_AGENT_DATABASE_URL: "postgres://${POSTGRES_USER:-furumi}:${POSTGRES_PASSWORD:-furumi}@db:5432/${POSTGRES_DB:-furumi}" + FURUMI_AGENT_INBOX_DIR: "/inbox" + FURUMI_AGENT_STORAGE_DIR: "/storage" + FURUMI_AGENT_OLLAMA_URL: "${OLLAMA_URL:-http://host.docker.internal:11434}" + FURUMI_AGENT_OLLAMA_AUTH: "${OLLAMA_AUTH:-CHANGE-ME}" + FURUMI_PLAYER_BIND: "0.0.0.0:8090" + volumes: + - ./inbox:/inbox + - ./storage:/storage + extra_hosts: + - "host.docker.internal:host-gateway" + restart: always + + web-player: + build: + context: . + dockerfile: Dockerfile.web-player + container_name: furumi-web-player + depends_on: + db: + condition: service_healthy + ports: + - "8085:8085" + environment: + FURUMI_PLAYER_DATABASE_URL: "postgres://${POSTGRES_USER:-furumi}:${POSTGRES_PASSWORD:-furumi}@db:5432/${POSTGRES_DB:-furumi}" + FURUMI_PLAYER_STORAGE_DIR: "/storage" + FURUMI_PLAYER_BIND: "0.0.0.0:8085" + volumes: + - ./storage:/storage + restart: always + +volumes: + pgdata: diff --git a/furumi-agent/src/config.rs b/furumi-agent/src/config.rs index 1eff005..2427c08 100644 --- a/furumi-agent/src/config.rs +++ b/furumi-agent/src/config.rs @@ -32,6 +32,10 @@ pub struct Args { #[arg(long, env = "FURUMI_AGENT_OLLAMA_MODEL", default_value = "qwen3:14b")] pub ollama_model: String, + /// Authorization header value for Ollama API (e.g. "Bearer " or "Basic ") + #[arg(long, env = "FURUMI_AGENT_OLLAMA_AUTH")] + pub ollama_auth: Option, + /// Inbox scan interval in seconds #[arg(long, env = "FURUMI_AGENT_POLL_INTERVAL_SECS", default_value_t = 30)] pub poll_interval_secs: u64, diff --git a/furumi-agent/src/ingest/normalize.rs b/furumi-agent/src/ingest/normalize.rs index e3571c4..50e8c60 100644 --- a/furumi-agent/src/ingest/normalize.rs +++ b/furumi-agent/src/ingest/normalize.rs @@ -22,6 +22,7 @@ pub async fn normalize( &state.config.ollama_model, &state.system_prompt, &user_message, + state.config.ollama_auth.as_deref(), ) .await?; @@ -125,6 +126,7 @@ async fn call_ollama( model: &str, system_prompt: &str, user_message: &str, + auth: Option<&str>, ) -> anyhow::Result { let client = reqwest::Client::builder() .timeout(std::time::Duration::from_secs(120)) @@ -151,7 +153,11 @@ async fn call_ollama( tracing::info!(%url, model, prompt_len = user_message.len(), "Calling Ollama API..."); let start = std::time::Instant::now(); - let resp = client.post(&url).json(&request).send().await?; + let mut req = client.post(&url).json(&request); + if let Some(auth_header) = auth { + req = req.header("Authorization", auth_header); + } + let resp = req.send().await?; let elapsed = start.elapsed(); if !resp.status().is_success() {