Dockerizing the app (WIP)

This commit is contained in:
2025-12-09 16:12:58 +01:00
parent da3d6f123d
commit 52d568e924
10 changed files with 370 additions and 0 deletions

57
brain/.dockerignore Normal file
View File

@@ -0,0 +1,57 @@
# Git
.git
.gitignore
.gitea
# Python
__pycache__
*.pyc
*.pyo
*.pyd
.Python
*.so
.pytest_cache
.coverage
htmlcov
.tox
.nox
.hypothesis
# Virtual environments
venv
.venv
env
.env
.env.*
# IDE
.vscode
.idea
*.swp
*.swo
.qodo
# Build
build
dist
*.egg-info
# Documentation
docs/
*.md
!README.md
# Tests
tests/
pytest.ini
# Data (will be mounted as volumes)
memory_data/
logs/
*.log
# Misc
*.bak
*.tmp
.DS_Store
Thumbs.db

91
brain/Dockerfile Normal file
View File

@@ -0,0 +1,91 @@
# Dockerfile for Agent Media
# Multi-stage build for smaller image size
# ===========================================
# Stage 1: Builder
# ===========================================
FROM python:3.12.7-slim as builder
# STFU (please)
ENV DEBIAN_FRONTEND=noninteractive
# Install build dependencies (needs root)
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Install Poetry globally (needs root)
RUN pip install --no-cache-dir poetry
# Copy dependency files (as root for now)
COPY pyproject.toml poetry.lock* /tmp/
# Install dependencies as root (to avoid permission issues with system packages)
WORKDIR /tmp
RUN poetry config virtualenvs.create false \
&& poetry install --only main --no-root --no-cache
# Create non-root user
RUN useradd -m -u 1000 -s /bin/bash appuser
# Switch to non-root user
USER appuser
# Set working directory (owned by appuser)
WORKDIR /home/appuser/app
# ===========================================
# Stage 2: Runtime
# ===========================================
FROM python:3.12.7-slim as runtime
# Install runtime dependencies (needs root)
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean
# Create non-root user
RUN useradd -m -u 1000 -s /bin/bash appuser
# Create data directories (needs root for /data)
RUN mkdir -p /data/memory /data/logs \
&& chown -R appuser:appuser /data
# Switch to non-root user
USER appuser
# Set working directory (owned by appuser)
WORKDIR /home/appuser/app
# Copy Python packages from builder stage
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
# Copy application code (already owned by appuser)
COPY --chown=appuser:appuser agent/ ./agent/
COPY --chown=appuser:appuser application/ ./application/
COPY --chown=appuser:appuser domain/ ./domain/
COPY --chown=appuser:appuser infrastructure/ ./infrastructure/
COPY --chown=appuser:appuser app.py .
# Create volumes for persistent data
VOLUME ["/data/memory", "/data/logs"]
# Expose port
EXPOSE 8000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
# Environment variables (can be overridden)
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONPATH=/home/appuser/app \
LLM_PROVIDER=deepseek \
MEMORY_STORAGE_DIR=/data/memory
# Run the application
CMD ["python", "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@@ -0,0 +1,16 @@
{
"name": "add_torrent_by_index",
"description": "Ajoute un torrent à la file d'attente de qBittorrent en utilisant l'index (1-basé) d'un résultat de recherche précédent (par exemple, 'download the 3rd one').",
"parameters": {
"type": "object",
"properties": {
"index": {
"type": "integer",
"description": "L'index (1-basé) du torrent dans les derniers résultats de recherche."
}
},
"required": [
"index"
]
}
}

View File

@@ -0,0 +1,16 @@
{
"name": "find_media_imdb_id",
"description": "Trouve l'ID IMDb et les informations d'un film ou d'une série télévisée à partir de son titre en utilisant l'API TMDB. À utiliser comme première étape avant de chercher des torrents.",
"parameters": {
"type": "object",
"properties": {
"media_title": {
"type": "string",
"description": "Le titre exact du média à rechercher (par exemple, 'Inception', 'Breaking Bad')."
}
},
"required": [
"media_title"
]
}
}

View File

@@ -0,0 +1,16 @@
{
"name": "find_torrent",
"description": "Recherche des fichiers torrent pour un titre de média donné. Les résultats sont stockés dans la mémoire de l'agent pour une référence ultérieure par index (e.g., 'download the 3rd one').",
"parameters": {
"type": "object",
"properties": {
"media_title": {
"type": "string",
"description": "Le titre du média pour lequel rechercher des torrents (par exemple, 'Inception 2010')."
}
},
"required": [
"media_title"
]
}
}

View File

@@ -0,0 +1,16 @@
{
"name": "set_language",
"description": "Définit la langue de la conversation pour l'agent.",
"parameters": {
"type": "object",
"properties": {
"language": {
"type": "string",
"description": "Le code de la langue (par exemple, 'en' pour Anglais, 'fr' pour Français, 'es' pour Espagnol)."
}
},
"required": [
"language"
]
}
}

34
docker-compose.yml Normal file
View File

@@ -0,0 +1,34 @@
version: "3.4"
services:
# Da brain
agent-brain:
build:
context: ./brain
dockerfile: Dockerfile
env_file: .env
ports:
- "8000:8000"
volumes:
# Persistent data volumes (outside container /app)
- agent-memory:/data/memory
- agent-logs:/data/logs
# Development: mount code for hot reload (comment out in production)
# - ./brain:/app
# Da face
frontend:
build:
context: ./librechat
dockerfile: Dockerfile
ports:
- "3080:3080"
depends_on:
- agent-brain
# Named volumes for persistent data
volumes:
agent-memory:
driver: local
agent-logs:
driver: local

4
librechat/Dockerfile Normal file
View File

@@ -0,0 +1,4 @@
FROM ghcr.io/danny-avila/librechat:latest
COPY librechat.yaml /app/librechat.yaml
COPY librechat_providers.js /app/librechat_providers.js

110
librechat/librechat.yaml Normal file
View File

@@ -0,0 +1,110 @@
# For more information, see the Configuration Guide:
# https://www.librechat.ai/docs/configuration/librechat_yaml
version: 1.2.1
cache: true
endpoints:
custom:
# Deepseek
- name: "Deepseek"
apiKey: "${DEEPSEEK_API_KEY}"
baseURL: "https://api.deepseek.com/v1"
models:
default: ["deepseek-chat", "deepseek-coder", "deepseek-reasoner"]
fetch: false
titleConvo: true
titleModel: "deepseek-chat"
modelDisplayLabel: "Deepseek"
streamRate: 1
tools:
- toolName: media_finder
pluginKey: "media_finder_key"
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/find_media_imdb_id.json"
auth:
type: none
# Outil 2: find_torrent
- toolName: torrent_search
pluginKey: "torrent_search_key"
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/find_torrent.json"
auth:
type: none
# Outil 3: add_torrent_by_index
- toolName: torrent_downloader
pluginKey: "torrent_downloader_key"
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/add_torrent_by_index.json"
auth:
type: none
# Outil 4: set_language
- toolName: lang_setter
pluginKey: "lang_setter_key"
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/set_language.json"
auth:
type: none
# Backend Local Agent
- name: "Local Agent"
apiKey: "dummy_key"
baseURL: "http://host.docker.internal:8000/v1"
models:
default: ["local-deepseek-agent"]
fetch: false
titleConvo: false
titleModel: "current_model"
forcePrompt: true
modelDisplayLabel: "Local Agent"
streamRate: 1
tools:
- toolName: media_finder
pluginKey: "media_finder_key"
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/find_media_imdb_id.json"
auth:
type: none
# Outil 2: find_torrent
- toolName: torrent_search
pluginKey: "torrent_search_key"
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/find_torrent.json"
auth:
type: none
# Outil 3: add_torrent_by_index
- toolName: torrent_downloader
pluginKey: "torrent_downloader_key"
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/add_torrent_by_index.json"
auth:
type: none
# Outil 4: set_language
- toolName: lang_setter
pluginKey: "lang_setter_key"
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/set_language.json"
auth:
type: none

View File

@@ -0,0 +1,10 @@
[
{
"name": "LocalAgent",
"type": "openai",
"baseURL": "http://host.docker.internal:8000",
"apiKey": "sk-8b00d72c417740ea96efd9c3eeddd148",
"model": "local-deepseek-agent",
"custom": true
}
]