Added doker compose
This commit is contained in:
3
.env_example
Normal file
3
.env_example
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
OLLAMA_URL=https://ollama.host.com
|
||||||
|
OLLAMA_AUTH="Basic <BASE64 Auth string>"
|
||||||
|
#OLLAMA_AUTH="Bearer <TOKEN>"
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,4 @@
|
|||||||
/target
|
/target
|
||||||
|
/inbox
|
||||||
|
/storage
|
||||||
|
.env
|
||||||
|
|||||||
54
README.md
54
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-client-secret` | `FURUMI_PLAYER_OIDC_CLIENT_SECRET` | — | OIDC client secret |
|
||||||
| `--oidc-redirect-url` | `FURUMI_PLAYER_OIDC_REDIRECT_URL` | — | OIDC redirect URL |
|
| `--oidc-redirect-url` | `FURUMI_PLAYER_OIDC_REDIRECT_URL` | — | OIDC redirect URL |
|
||||||
| `--oidc-session-secret` | `FURUMI_PLAYER_OIDC_SESSION_SECRET` | *(random)* | Session HMAC secret |
|
| `--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
|
## Docker
|
||||||
|
|
||||||
Pre-built images are available on Docker Hub:
|
Pre-built images are available on Docker Hub:
|
||||||
|
|||||||
60
docker-compose.yml
Normal file
60
docker-compose.yml
Normal file
@@ -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:
|
||||||
@@ -32,6 +32,10 @@ pub struct Args {
|
|||||||
#[arg(long, env = "FURUMI_AGENT_OLLAMA_MODEL", default_value = "qwen3:14b")]
|
#[arg(long, env = "FURUMI_AGENT_OLLAMA_MODEL", default_value = "qwen3:14b")]
|
||||||
pub ollama_model: String,
|
pub ollama_model: String,
|
||||||
|
|
||||||
|
/// Authorization header value for Ollama API (e.g. "Bearer <token>" or "Basic <base64>")
|
||||||
|
#[arg(long, env = "FURUMI_AGENT_OLLAMA_AUTH")]
|
||||||
|
pub ollama_auth: Option<String>,
|
||||||
|
|
||||||
/// Inbox scan interval in seconds
|
/// Inbox scan interval in seconds
|
||||||
#[arg(long, env = "FURUMI_AGENT_POLL_INTERVAL_SECS", default_value_t = 30)]
|
#[arg(long, env = "FURUMI_AGENT_POLL_INTERVAL_SECS", default_value_t = 30)]
|
||||||
pub poll_interval_secs: u64,
|
pub poll_interval_secs: u64,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ pub async fn normalize(
|
|||||||
&state.config.ollama_model,
|
&state.config.ollama_model,
|
||||||
&state.system_prompt,
|
&state.system_prompt,
|
||||||
&user_message,
|
&user_message,
|
||||||
|
state.config.ollama_auth.as_deref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -125,6 +126,7 @@ async fn call_ollama(
|
|||||||
model: &str,
|
model: &str,
|
||||||
system_prompt: &str,
|
system_prompt: &str,
|
||||||
user_message: &str,
|
user_message: &str,
|
||||||
|
auth: Option<&str>,
|
||||||
) -> anyhow::Result<String> {
|
) -> anyhow::Result<String> {
|
||||||
let client = reqwest::Client::builder()
|
let client = reqwest::Client::builder()
|
||||||
.timeout(std::time::Duration::from_secs(120))
|
.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...");
|
tracing::info!(%url, model, prompt_len = user_message.len(), "Calling Ollama API...");
|
||||||
|
|
||||||
let start = std::time::Instant::now();
|
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();
|
let elapsed = start.elapsed();
|
||||||
|
|
||||||
if !resp.status().is_success() {
|
if !resp.status().is_success() {
|
||||||
|
|||||||
Reference in New Issue
Block a user