Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"ms-python.pylint"
],
"settings": {
"python.defaultInterpreterPath": "/venv/bin/python"
"python.defaultInterpreterPath": "/app/.venv/bin/python"
}
}
},
Expand Down
1 change: 0 additions & 1 deletion .devcontainer/post_start.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ echo "Setup completed for workspace: $workspace_folder_basename"



uv sync
uvx prek install --install-hooks

uv run tailwindcss -i ./src/clepsy/frontend/css/app.css -o ./static/app.css
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/checks.yml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
target: production
file: Dockerfile.prod
tags: clepsy:ci
load: true
push: false
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/publish.yml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.prod
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Expand Down
Empty file modified .gitignore
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ repos:
hooks:
- id: check-added-large-files
args: [--maxkb=1024]
exclude: ^test_images/
- id: check-merge-conflict
- id: debug-statements
- id: end-of-file-fixer
Expand Down
Empty file modified .python-version
100644 → 100755
Empty file.
Empty file modified .vscode/extensions.json
100644 → 100755
Empty file.
Empty file modified .vscode/launch.json
100644 → 100755
Empty file.
Empty file modified .vscode/settings.json
100644 → 100755
Empty file.
Empty file modified .vscode/tasks.json
100644 → 100755
Empty file.
Empty file modified Caddyfile
100644 → 100755
Empty file.
109 changes: 0 additions & 109 deletions Dockerfile

This file was deleted.

20 changes: 20 additions & 0 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive \
LC_CTYPE=C.utf8 \
UV_PROJECT_ENVIRONMENT="/app/.venv" \
UV_PYTHON_PREFERENCE=system \
PATH="/app/.venv/bin:$PATH" \
ENVIRONMENT=dev \
PYTHONDONTWRITEBYTECODE=1

RUN --mount=type=cache,target=/var/cache/apt,id=apt-cache,sharing=locked \
--mount=type=cache,target=/var/lib/apt,id=apt-lib,sharing=locked \
mkdir -p /var/lib/apt/lists/partial && \
apt-get update && \
apt-get install --no-install-recommends -y \
tzdata curl build-essential sqlite3 gosu adduser libgl1 libglib2.0-0 && \
rm -rf /var/lib/apt/lists/*

RUN curl -fsSL https://raw.githubusercontent.com/pressly/goose/master/install.sh | sh

WORKDIR /app
49 changes: 49 additions & 0 deletions Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS production


ENV DEBIAN_FRONTEND=noninteractive \
LC_CTYPE=C.utf8 \
UV_PROJECT_ENVIRONMENT="/venv" \
UV_PYTHON_PREFERENCE=system \
PATH="/venv/bin:$PATH" \
UV_COMPILE_BYTECODE=0 \
ENVIRONMENT=prod \
UV_LINK_MODE=copy

# Minimal runtime deps only (no sudo)
RUN --mount=type=cache,target=/var/cache/apt,id=apt-cache,sharing=locked \
--mount=type=cache,target=/var/lib/apt,id=apt-lib,sharing=locked \
mkdir -p /var/lib/apt/lists/partial && \
apt-get update && \
apt-get install --no-install-recommends -y \
rsync tzdata curl build-essential sqlite3 gosu adduser libgl1 libglib2.0-0 && \
rm -rf /var/lib/apt/lists/*

RUN curl -fsSL https://raw.githubusercontent.com/pressly/goose/master/install.sh | sh


WORKDIR /app

RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --locked --no-install-project --no-dev

COPY pyproject.toml uv.lock ./
COPY src/ ./src/
COPY migrations/ ./migrations/
COPY static/ ./static/
COPY scripts/ ./scripts/
COPY baml_src/ ./baml_src/


COPY scripts/ ./
RUN chmod +x /app/scripts/entrypoint.sh /app/scripts/worker_entrypoint.sh /app/scripts/fix_permissions.sh

# Install the project into the prebuilt venv without re-resolving deps
RUN --mount=type=cache,target=/root/.cache/uv,id=uv-cache \
uv sync --locked --no-dev --compile-bytecode

RUN baml-cli generate

ENV DEBIAN_FRONTEND=
Empty file modified LICENSE
100644 → 100755
Empty file.
Empty file modified README.md
100644 → 100755
Empty file.
Empty file modified baml_src/aggregation.baml
100644 → 100755
Empty file.
Empty file modified baml_src/clients.baml
100644 → 100755
Empty file.
Empty file modified baml_src/desktop_check.baml
100644 → 100755
Empty file.
Empty file modified baml_src/desktop_check_validation.baml
100644 → 100755
Empty file.
Empty file modified baml_src/entities.baml
100644 → 100755
Empty file.
Empty file modified baml_src/generators.baml
100644 → 100755
Empty file.
Empty file modified baml_src/interpret_image_ocr.baml
100644 → 100755
Empty file.
Empty file modified baml_src/isolated_timeline_validation.baml
100644 → 100755
Empty file.
Empty file modified baml_src/manual_activity_reconciliation.baml
100644 → 100755
Empty file.
Empty file modified baml_src/productivity_classification.baml
100644 → 100755
Empty file.
Empty file modified baml_src/qc_timeline.baml
100644 → 100755
Empty file.
Empty file modified baml_src/retry_policies.baml
100644 → 100755
Empty file.
Empty file modified baml_src/sessions.baml
100644 → 100755
Empty file.
Empty file modified baml_src/stitch.baml
100644 → 100755
Empty file.
Empty file modified baml_src/tag_classification.baml
100644 → 100755
Empty file.
Empty file modified baml_src/test_model_config.baml
100644 → 100755
Empty file.
Empty file modified docker-compose.ci.override.yml
100644 → 100755
Empty file.
Empty file modified docker-compose.prod.gateway.yml
100644 → 100755
Empty file.
18 changes: 18 additions & 0 deletions docker-compose.prod.local.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Local override for docker-compose.prod.yml
# Build production images locally instead of pulling from registry
#
# Usage:
# docker compose -f docker-compose.prod.yml -f docker-compose.prod.local.yml up --build

services:
clepsy:
build:
context: .
dockerfile: Dockerfile.prod
image: clepsy:local

dramatiq-worker:
build:
context: .
dockerfile: Dockerfile.prod
image: clepsy:local
2 changes: 1 addition & 1 deletion docker-compose.prod.monitoring.yml
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
services:
clepsy:
environment:
GRAFANA_ENABLED: "true"
MONITORING_ENABLED: "true"

valkey-exporter:
image: oliver006/redis_exporter:latest
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.prod.yml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ services:
- static_assets:/shared-static
- caches:/var/lib/clepsy-caches
- paddlex-cache:/root/.paddlex
entrypoint: ["/app/entrypoint.sh"]
entrypoint: ["/app/scripts/entrypoint.sh"]
ports:
- "${CLEPSY_PORT:-8000}:8000"
environment:
Expand Down Expand Up @@ -55,7 +55,7 @@ services:
image: ghcr.io/samgalanakis/clepsy:latest
container_name: dramatiq-worker
networks: [web]
entrypoint: ["/app/worker_entrypoint.sh"]
entrypoint: ["/app/scripts/worker_entrypoint.sh"]
environment:
CLEPSY_UID: "${CLEPSY_UID:-1000}"
CLEPSY_GID: "${CLEPSY_GID:-1000}"
Expand Down
14 changes: 9 additions & 5 deletions docker-compose.yml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ services:
image: clepsy-dev
build:
context: .
dockerfile: Dockerfile
target: builder
dockerfile: Dockerfile.dev
entrypoint: ["sh", "-c", "sleep infinity & wait"]
environment:
GOOSE_DRIVER: sqlite3
GOOSE_DBSTRING: /var/lib/clepsy/db.sqlite3
GOOSE_MIGRATION_DIR: ./migrations
VALKEY_URL: redis://valkey:6379/0
GRAFANA_ENABLED: "true"
MONITORING_ENABLED: "true"
CLEPSY_MODE: dev
CLEPSY_GID : "0"
CLEPSY_UID : "0"

volumes:
- .:/app
Expand Down Expand Up @@ -47,20 +48,23 @@ services:

dramatiq-worker:
image: clepsy-dev
entrypoint: ["sh", "-c", "sleep infinity & wait"]
entrypoint: ["/app/scripts/worker_entrypoint.sh"]
environment:
CLEPSY_UID: "0"
CLEPSY_GID: "0"
VALKEY_URL: redis://valkey:6379/0
dramatiq_prom_host: 0.0.0.0
dramatiq_prom_port: "9191"
prometheus_multiproc_dir: /tmp/dramatiq-prometheus
dramatiq_prom_db: /tmp/dramatiq-prometheus
CLEPSY_MODE: dev
command: bash -lc "mkdir -p /tmp/dramatiq-prometheus && rm -rf /tmp/dramatiq-prometheus/* && uv run dramatiq clepsy.jobs.desktop clepsy.jobs.mobile clepsy.jobs.aggregation clepsy.jobs.sessions clepsy.jobs.goals --processes 2 --threads 4"
volumes:
- .:/app
- db_data_dev:/var/lib/clepsy
restart: unless-stopped
depends_on:
clepsy:
condition: service_started
valkey:
condition: service_healthy

Expand Down
Empty file modified docs/SETUP.md
100644 → 100755
Empty file.
Empty file modified docs/media/architecture.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/media/logo.svg
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified migrations/00001_first.sql
100644 → 100755
Empty file.
Empty file modified ops/grafana/provisioning/dashboards/11835_Redis_Dashboard.json
100644 → 100755
Empty file.
Empty file.
Empty file modified ops/grafana/provisioning/dashboards/18993_Dramatiq.json
100644 → 100755
Empty file.
Empty file modified ops/grafana/provisioning/dashboards/provider.yml
100644 → 100755
Empty file.
Empty file modified ops/grafana/provisioning/datasources/prometheus.yml
100644 → 100755
Empty file.
Empty file modified ops/prometheus.yml
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions pyproject.toml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ dependencies = [
"prometheus-fastapi-instrumentator>=7.1.0",
"opencv-contrib-python-headless>=4.12.0.88",
"paddleocr>=3.3.1",
"paddlepaddle>=3.2.1",
]

[dependency-groups]
Expand Down
10 changes: 9 additions & 1 deletion entrypoint.sh → scripts/entrypoint.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,15 @@ log "Refreshing shared static assets..."
rsync -a --delete --no-perms --no-owner --no-group /app/static/ /shared-static/

log "[prod] Running migrations"
gosu "${PUID}:${PGID}" goose up || true
gosu "${PUID}:${PGID}" goose up

# Initialize JWT secret if not exists (before starting workers)
JWT_SECRET_FILE="/var/lib/clepsy/jwt_secret.txt"
if [ ! -f "$JWT_SECRET_FILE" ] && [ -z "${JWT_SECRET:-}" ]; then
log "Generating JWT secret..."
gosu "${PUID}:${PGID}" uv run python -c "import os, binascii; print(binascii.hexlify(os.urandom(24)).decode())" > "$JWT_SECRET_FILE"
fi

log "[prod] Starting server"
exec gosu "${PUID}:${PGID}" uvicorn clepsy.main:app \
--host 0.0.0.0 \
Expand Down
Empty file modified scripts/fix_permissions.sh
100644 → 100755
Empty file.
File renamed without changes.
Empty file modified src/__init__.py
100644 → 100755
Empty file.
Empty file modified src/clepsy/__init__.py
100644 → 100755
Empty file.
Empty file modified src/clepsy/aggregator_worker.py
100644 → 100755
Empty file.
Empty file modified src/clepsy/auth/auth.py
100644 → 100755
Empty file.
4 changes: 2 additions & 2 deletions src/clepsy/auth/auth_middleware.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ async def check_authentication(self, request: Request, to_authenticate: bool):
request.state.authenticated = True

return True, decoded_token, None
except Exception as e:
except Exception:
if to_authenticate:
logger.debug(f"Invalid token, {e}")
logger.exception("Invalid jwt token")
return False, None, "invalid_token"

async def __call__(self, request: Request, call_next):
Expand Down
Empty file modified src/clepsy/bootstrap.py
100644 → 100755
Empty file.
Empty file modified src/clepsy/central_cache.py
100644 → 100755
Empty file.
20 changes: 17 additions & 3 deletions src/clepsy/config.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,20 @@ def init_master_key(path: Path) -> bytes:
cache_dir = Path("/var/lib/clepsy-caches")


def load_jwt_secret(path: Path) -> str:
"""Load JWT secret from file or environment variable."""
env_secret = os.getenv("JWT_SECRET")
if env_secret:
logger.info("Using JWT secret from environment variable.")
return env_secret

if path.is_file():
logger.info(f"Loading JWT secret from file: {path}")
return path.read_text().strip()

raise FileNotFoundError("JWT secret file not found and JWT_SECRET env var not set.")


class Config(BaseSettings):
log_file_path: Path = Path("/var/lib/clepsy/logs/app.log")
master_key_file_path: Path = Path("/var/lib/clepsy/secret.key")
Expand All @@ -102,9 +116,8 @@ class Config(BaseSettings):
api_host: str = "0.0.0.0"
max_desktop_screenshot_log_interval_seconds: int = 30
cache_dir: Path = cache_dir
jwt_secret: SecretStr = SecretStr(
os.getenv("JWT_SECRET", binascii.hexlify(os.urandom(24)).decode())
)
jwt_secret_file_path: Path = Path("/var/lib/clepsy/jwt_secret.txt")
jwt_secret: SecretStr = SecretStr(load_jwt_secret(jwt_secret_file_path))
jwt_algorithm: str = "HS256"
environment: Literal["dev", "prod"]
boundary_project_id: str | None = os.getenv("BOUNDARY_PROJECT_ID")
Expand All @@ -129,6 +142,7 @@ class Config(BaseSettings):
gliner_cache_dir: Path = cache_dir / "gliner"
valkey_url: str
ap_scheduler_sqlite_db_path: Path = Path("/var/lib/clepsy/apscheduler.sqlite3")
monitoring_enabled: bool = False

@property
def ap_scheduler_db_connection_string(self) -> str:
Expand Down
Empty file modified src/clepsy/db/__init__.py
100644 → 100755
Empty file.
Empty file modified src/clepsy/db/adapters.py
100644 → 100755
Empty file.
Empty file modified src/clepsy/db/converters.py
100644 → 100755
Empty file.
Empty file modified src/clepsy/db/db.py
100644 → 100755
Empty file.
Empty file modified src/clepsy/db/deps.py
100644 → 100755
Empty file.
Empty file modified src/clepsy/db/queries.py
100644 → 100755
Empty file.
Empty file modified src/clepsy/entities.py
100644 → 100755
Empty file.
Loading