Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
53875da
feat(render): add one-click Render deploy template
Ho1yShif Jul 17, 2026
e36c483
docs(README): update admin password instructions and add CORS configu…
Ho1yShif Jul 17, 2026
a916975
fix(render): fail hosted deploy when admin auth isn't seeded
Ho1yShif Jul 18, 2026
8566dfc
docs(README): clarify OpenAI API key restrictions for chat completions
Ho1yShif Jul 18, 2026
6da1029
fix(render): stage SearXNG settings template outside /tmp
Ho1yShif Jul 18, 2026
f279c22
chore(render): group services under an odysseus project
Ho1yShif Jul 18, 2026
1fdf6b4
feat: one-click Render deploy template + opt-in public demo mode (#2)
Ho1yShif Jul 20, 2026
f86e666
fix(favicon): serve /favicon.ico at root instead of redirecting to login
Ho1yShif Jul 20, 2026
42d060b
docs(README): update chat setup instructions for OpenAI API key
Ho1yShif Jul 20, 2026
c974930
docs(env): update .env.example with new environment variables and des…
Ho1yShif Jul 20, 2026
e4f6c54
fix(render.yaml): update previews generation setting to string format
Ho1yShif Jul 20, 2026
2b86c61
chore: point deploy button at new repo
Ho1yShif Jul 20, 2026
7da1219
chore: correct deploy button link
Ho1yShif Jul 20, 2026
d00dc1f
Update README by removing image and adding link
Ho1yShif Jul 20, 2026
d2ff539
docs(README): add architecture section with service diagram
Ho1yShif Jul 21, 2026
07ecf77
chore: fix arrow alignment in readme
Ho1yShif Jul 21, 2026
e8a5fa4
chore(deps): move test tooling out of the production image (#4)
Ho1yShif Jul 21, 2026
ba09412
feat: implement demo mode session management and rate limiting
Ho1yShif Aug 11, 2026
660bc2e
refactor: make model-catalog edits additive and unify src.demo imports
Ho1yShif Aug 11, 2026
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
38 changes: 38 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ LLM_HOST=localhost
# Do not commit real keys. Keep this commented until needed.
# OPENAI_API_KEY=your_openai_api_key_here

# Model seeded as the default chat endpoint on first boot (OpenAI). Not a secret.
# Change here or in the app's model picker. Matches render.yaml's default.
# OPENAI_DEFAULT_MODEL=gpt-5.6-sol

# Research service LLM endpoint
# RESEARCH_LLM_ENDPOINT=http://localhost:8000/v1/chat/completions

Expand All @@ -49,6 +53,14 @@ SEARXNG_INSTANCE=http://localhost:8080
# and stores it in the searxng-data volume.
# SEARXNG_SECRET=

# Cloud web-search providers (all optional; the bundled SearXNG needs no key).
# Add one only to enrich research beyond SearXNG. Do not commit real keys.
# DATA_BRAVE_API_KEY=your_brave_search_api_key_here # https://brave.com/search/api/
# TAVILY_API_KEY=your_tavily_api_key_here # https://tavily.com/
# SERPER_API_KEY=your_serper_api_key_here # https://serper.dev/
# GOOGLE_API_KEY=your_google_api_key_here # Google Programmable Search
# GOOGLE_PSE_CX=your_programmable_search_engine_id_here

# ============================================================
# Database
# ============================================================
Expand Down Expand Up @@ -84,6 +96,14 @@ SEARXNG_INSTANCE=http://localhost:8080
# by a trusted reverse proxy or private access gateway.
# SECURE_COOKIES=true

# Trusted proxy hops in front of the app, read from the RIGHT of X-Forwarded-For.
# Every IP-keyed rate limiter (auth login/signup/setup and the demo caps) uses it.
# 0 = no proxy, app is directly internet-facing (XFF is ignored, real TCP peer used)
# 1 = one trusted edge proxy (Render's default topology)
# N = N trusted proxies
# Leaving 1 on a proxy-less deploy lets clients spoof XFF and bypass IP limits.
# TRUSTED_PROXY_HOPS=1

# Optional: pre-seed the first admin password during setup.
# Do not commit a real password.
# ODYSSEUS_ADMIN_PASSWORD=change_me_before_first_boot
Expand Down Expand Up @@ -130,6 +150,24 @@ SEARXNG_INSTANCE=http://localhost:8080
# FASTEMBED_MODEL=sentence-transformers/all-MiniLM-L6-v2
# FASTEMBED_CACHE_PATH= # defaults to ~/.cache/fastembed

# Hugging Face token — only for downloading gated Hugging Face models. Optional.
# Do not commit real tokens. https://huggingface.co/settings/tokens
# HF_TOKEN=your_huggingface_token_here

# ============================================================
# Demo mode (opt-in public showcase — default OFF)
# ============================================================
# DEMO=false keeps the full authenticated app (this is the default). DEMO=true
# opens a public, no-signup, locked-down chat demo that spends OPENAI_API_KEY.
# The caps below bound burn RATE, not total dollars — set a monthly usage limit
# on your OpenAI project for the true ceiling. See the README "Demo mode" section.
# DEMO=false
# DEMO_MODEL=gpt-5.6-luna # cheap OpenAI tier pinned for the demo path
# DEMO_RATE_LIMIT_PER_MINUTE=10 # chat requests/min per client IP; 0 disables
# DEMO_MAX_MESSAGES_PER_SESSION=30 # messages per visitor cookie session; 0 disables
# DEMO_MAX_MESSAGES_PER_IP_PER_DAY=200 # hard per-IP daily ceiling (the real backstop); 0 disables
# DEMO_MAX_OUTPUT_TOKENS=512 # output-token cap per demo LLM call

# ============================================================
# Google OAuth2 (Google Workspace / .edu email accounts)
# ============================================================
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ jobs:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.11"
python-version: "3.14"
# Byte-compile sources — catches syntax errors without installing deps.
- run: python -m compileall -q app.py core routes src services scripts tests

Expand Down Expand Up @@ -138,9 +138,9 @@ jobs:
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
if: steps.docs-check.outputs.docs_only != 'true'
with:
python-version: "3.11"
python-version: "3.14"
cache: pip
- run: pip install -r requirements.txt
- run: pip install -r requirements.txt -r requirements-dev.txt
if: steps.docs-check.outputs.docs_only != 'true'
- run: mkdir -p data # sqlite DB lives at ./data/app.db
if: steps.docs-check.outputs.docs_only != 'true'
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Manual development uses Python 3.11+:
```bash
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install -r requirements.txt -r requirements-dev.txt # drop -dev to run the app without test tooling
python -m uvicorn app:app --host 127.0.0.1 --port 7000
```

Expand Down
38 changes: 38 additions & 0 deletions Dockerfile.render
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Slim image for hosting Odysseus on Render (render.com).
#
# Deliberately drops the local-model / GPU / image-upscaling / host-Docker
# tooling from the main Dockerfile (Real-ESRGAN wheel build, torch, opencv,
# cmake, build-essential, nodejs/npm, the Docker CLI) — none of it runs on
# Render's managed platform — so builds are fast and the image stays small.
# Core chat, agents, research, documents, email, notes, and calendar (via cloud
# LLM APIs, SearXNG web search, and ChromaDB) are unaffected.
FROM python:3.14-slim

# Runtime shared libs only:
# libmagic1 -> python-magic content-based MIME sniffing (src/upload_handler.py)
# libgomp1 -> onnxruntime, used by fastembed for local ONNX embeddings
RUN apt-get update && apt-get install -y --no-install-recommends \
libmagic1 \
libgomp1 \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Install Python deps first for layer caching.
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

# python-magic resolves libmagic at import time; keep it image-only (paired with
# the libmagic1 system lib installed above) exactly as the main Dockerfile does.
RUN pip install --no-cache-dir python-magic==0.4.27

# Copy app code.
COPY . .

# Data / log / cache dirs. /app/data is backed by a persistent Render disk.
RUN mkdir -p data logs services/cache/search

COPY docker/entrypoint.render.sh /usr/local/bin/entrypoint.render.sh
RUN chmod +x /usr/local/bin/entrypoint.render.sh

ENTRYPOINT ["/usr/local/bin/entrypoint.render.sh"]
Loading
Loading