Dockerizing the app (WIP)
This commit is contained in:
@@ -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
|
||||||
@@ -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"]
|
||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "LocalAgent",
|
||||||
|
"type": "openai",
|
||||||
|
"baseURL": "http://host.docker.internal:8000",
|
||||||
|
"apiKey": "sk-8b00d72c417740ea96efd9c3eeddd148",
|
||||||
|
"model": "local-deepseek-agent",
|
||||||
|
"custom": true
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user