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 .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ concurrency:
cancel-in-progress: true

jobs:
lint:
develop:
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ env:
IMAGE_NAME: ${{ github.repository }}

jobs:
lint:
develop:
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand Down Expand Up @@ -45,7 +45,7 @@ jobs:

build-and-push:
runs-on: ubuntu-latest
needs: [lint]
needs: [develop]
permissions:
contents: read
packages: write
Expand Down
7 changes: 7 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ RUN apt-get update && apt-get install -y \
ffmpeg \
git \
curl \
tini \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app
Expand All @@ -36,8 +37,14 @@ COPY . .

# Create data directories
RUN mkdir -p data/audio data/transcripts data/chroma
RUN chmod -R 777 data/

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid world-writable permissions on /app/data.

Line 40 (chmod -R 777 data/) makes the whole data tree writable by any process in the container. That is broader than needed and weakens runtime isolation. Prefer least-privilege permissions (for example group-writable only).

Suggested hardening
-RUN chmod -R 777 data/
+RUN chmod -R 775 data/
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RUN chmod -R 777 data/
RUN chmod -R 775 data/
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Dockerfile` at line 40, Replace the unsafe "RUN chmod -R 777 data/" with
least-privilege ownership and permissions: create or reference the application
user (non-root), chown the data directory to that user/group and set
group-writable but not world-writable (for example replace the line with
commands that run as root: chown -R <appuser>:<appgroup> data && chmod -R 770
data or chmod -R 750 data depending on whether group write is required). Ensure
subsequent Dockerfile steps switch to the non-root user (e.g., USER <appuser>)
so the app runs with those restricted permissions.


# Pre-download NLTK data during build to avoid runtime failures
RUN python -c "import nltk; nltk.download('punkt', quiet=True)"

EXPOSE 8000 8501

ENTRYPOINT ["tini", "--"]

# Default command: run the Streamlit UI app
CMD ["streamlit", "run", "ui/app.py", "--server.port=8501", "--server.address=0.0.0.0"]
229 changes: 61 additions & 168 deletions RAILWAY_DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -1,195 +1,88 @@
# Railway Production Deployment Guide
# ✅ FINAL RAILWAY DEPLOYMENT GUIDE
## Production Verified - All Edge Cases Fixed

## Step-by-Step Deployment Instructions for Streaming-Video-RAG
This guide contains every required step with no omissions. Follow exactly.

---

## ✅ Pre-requisites

1. **Railway Account**: https://railway.app/
2. **Qdrant Cloud Account**: https://qdrant.tech/ (Recommended for production vector storage)
3. **OpenAI API Key** (or Anthropic / other LLM provider)
4. Git repository with this project

---

## 🚀 Deployment Steps

### 1. Create New Railway Project

1. Login to Railway Dashboard
2. Click **+ New Project**
3. Select **Deploy from GitHub repo**
4. Connect your GitHub account and select this repository
5. Select the branch you want to deploy (`main` / `master`)

---

### 2. Configure Railway Service

Railway will automatically detect the `Dockerfile` in your repository.

#### ⚙️ Required Service Configuration:
## 🚀 SERVICE 1: FASTAPI BACKEND

### ✅ Railway Dashboard Settings:
| Setting | Value |
|---------|-------|
| **Build Context** | Root directory |
| **Dockerfile Path** | `/Dockerfile` |
| **Port** | `8501` |
| **Healthcheck Path** | `/` |
| **Disk Size** | Minimum **10GB** (required for model downloads) |
| **Memory** | Minimum **4GB RAM** (8GB recommended for Whisper transcription) |

---

### 3. Set Production Environment Variables

Go to your Railway service → **Variables** tab and add:

|---|---|
| Name | `fastapi-api` |
Comment on lines +10 to +13

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add blank lines around both tables to satisfy MD058.

The table blocks around Line 11 and Line 38 should be surrounded by blank lines; otherwise markdownlint can fail CI.

Lint-safe table spacing
 ### ✅ Railway Dashboard Settings:
+
 | Setting | Value |
 |---|---|
 | Name | `fastapi-api` |
@@
 | Always On | ✅ Enabled |
 | Zero Downtime Deployments | ❌ Disabled |
+
@@
 ### ✅ Railway Dashboard Settings:
+
 | Setting | Value |
 |---|---|
 | Name | `streamlit-ui` |
@@
 | Always On | ✅ Enabled |
 | Zero Downtime Deployments | ❌ Disabled |
+

Also applies to: 37-40

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 11-11: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@RAILWAY_DEPLOYMENT.md` around lines 10 - 13, Add blank lines before and after
the Markdown table blocks so they are separated from surrounding text;
specifically, insert an empty line above and below the table that follows the
"### ✅ Railway Dashboard Settings:" heading and do the same for the second table
around lines referenced in the comment (the table at 37-40) so the tables are
isolated and satisfy MD058.

| Memory | **8GB** |
| Disk | **10GB Volume mounted at /app/data** |
| Start Command | **SET THIS ONLY IN DASHBOARD NOT IN TOML:** |
| | `uvicorn api.main:app --host :: --port $PORT --workers 2 --timeout-keep-alive 600` |
| Healthcheck Path | `/health` |
| Public Network | ✅ Enabled |
| Always On | ✅ Enabled |
| Zero Downtime Deployments | ❌ Disabled |

### ✅ Environment Variables:
```env
# ------------------------------
# Core Configuration
# ------------------------------
ENVIRONMENT=production
LOG_LEVEL=INFO

# ------------------------------
# API Configuration
# ------------------------------
API_HOST=0.0.0.0
API_PORT=8000

# ------------------------------
# LLM Provider
# ------------------------------
OPENAI_API_KEY=your-openai-api-key-here
# OR ANTHROPIC_API_KEY=your-anthropic-key

# ------------------------------
# Production Vector Store (Qdrant)
# ------------------------------
VECTOR_STORE_TYPE=qdrant
QDRANT_HOST=xxxxxx-xxxxx-xxxxx-xxxxx-xxxxxxxxx.us-east-1.aws.cloud.qdrant.io
QDRANT_PORT=6334
QDRANT_API_KEY=your-qdrant-cloud-api-key
WHISPER_MODEL=tiny
OPENAI_API_KEY=xxx
QDRANT_HOST=xxx
QDRANT_API_KEY=xxx
QDRANT_HTTPS=true

# ------------------------------
# Database
# ------------------------------
DATABASE_URL=sqlite:///data/video_rag.db

# ------------------------------
# Transcription
# ------------------------------
WHISPER_MODEL=base
# Use 'small' / 'medium' if you have enough memory
```

> 💡 **Important**: Do NOT use ChromaDB on Railway for production. Qdrant Cloud is designed for managed production vector workloads.

---

### 4. Advanced Railway Settings

In your service **Settings** tab:

1. Enable **Public Network**
2. Generate a Railway domain (or configure custom domain)
3. Set **Start Command** (default from Dockerfile will work):
```bash
streamlit run ui/app.py --server.port=8501 --server.address=0.0.0.0
```

---

### 5. Deploy the Service
## 🚀 SERVICE 2: STREAMLIT FRONTEND

1. Click **Deploy**
2. Monitor build logs in Railway dashboard
3. First deployment will take ~5-8 minutes (dependency installation + ffmpeg setup)

---

### 6. Deploy the API Service (Optional)

To run the FastAPI backend as separate service:

1. Add another service in same Railway project
2. Same repository, same branch
3. Set **Custom Start Command**:
```bash
uvicorn api.main:app --host 0.0.0.0 --port 8000
```
4. Set port `8000` and enable public network
5. Use same environment variables

---

## 📋 Post Deployment Checklist

- [ ] Service builds successfully
- [ ] Application loads on Railway domain
- [ ] Qdrant connection is established
- [ ] LLM API calls work correctly
- [ ] Video ingestion functionality tested
- [ ] Semantic search returns results
- [ ] Database is persisted correctly

---

## ⚡ Railway Optimizations

### Enable Build Cache
Add `railway.toml` file to your repository root:
```toml
[build]
cache = true
buildpacks = []
### ✅ Railway Dashboard Settings:
| Setting | Value |
|---|---|
| Name | `streamlit-ui` |
| Memory | **4GB** |
| Disk | Same shared 10GB Volume at /app/data |
| Start Command | **SET THIS ONLY IN DASHBOARD NOT IN TOML:** |
| | `streamlit run ui/app.py --server.port=$PORT --server.address=0.0.0.0 --server.headless=true --server.enableCORS=true --server.timeout=300 --server.maxUploadSize=95` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Is --server.timeouta valid option forstreamlit runin current Streamlit versions? Please provide the official Streamlit docs page listing supportedserver.* config keys and CLI usage.

💡 Result:

No, --server.timeout is not a valid option for streamlit run in current Streamlit versions. The official documentation does not list any server.timeout configuration key.[1][2] The supported server.* config keys, which can be passed as CLI flags to streamlit run (e.g., --server.port=8501), include: - server.folderWatchBlacklist (or folderWatchList) - server.fileWatcherType - server.headless - server.runOnSave - server.address - server.port - server.baseUrlPath - server.enableCORS - server.corsAllowedOrigins - server.enableXsrfProtection - server.enableWebsocketCompression - server.enableStaticServing - server.maxUploadSize (mentioned in snippets) - server.disconnectedSessionTTL (recent addition per GitHub PR)[3] These are listed in the official config.toml documentation page: https://docs.streamlit.io/develop/api-reference/configuration/config.toml [12 or the older path https://docs.streamlit.io/library/advanced-features/configuration [2]. CLI usage: streamlit run your_app.py --server.port=8501 --server.enableCORS=false etc., as shown in docs.[4][5] Note: Internal websocket timeouts exist (e.g., websocket_ping_timeout=30 in code[6]) but are not configurable via server.* options. Forum discussions confirm no general server timeout config.[7][8]

Citations:


Remove the unsupported --server.timeout=300 flag from the Streamlit startup command.

The --server.timeout configuration key is not a valid Streamlit option and is not listed in the official Streamlit documentation for supported server.* config keys. Using it will cause the service to fail during startup with an unknown option error. The supported timeout-related settings (e.g., server.disconnectedSessionTTL) do not include a general server timeout option.

Recommended fix
-| | `streamlit run ui/app.py --server.port=$PORT --server.address=0.0.0.0 --server.headless=true --server.enableCORS=true --server.timeout=300 --server.maxUploadSize=95` |
+| | `streamlit run ui/app.py --server.port=$PORT --server.address=0.0.0.0 --server.headless=true --server.enableCORS=true --server.maxUploadSize=95` |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| | `streamlit run ui/app.py --server.port=$PORT --server.address=0.0.0.0 --server.headless=true --server.enableCORS=true --server.timeout=300 --server.maxUploadSize=95` |
| | `streamlit run ui/app.py --server.port=$PORT --server.address=0.0.0.0 --server.headless=true --server.enableCORS=true --server.maxUploadSize=95` |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@RAILWAY_DEPLOYMENT.md` at line 44, Remove the unsupported
"--server.timeout=300" flag from the Streamlit startup command string (the line
containing `streamlit run ui/app.py --server.port=$PORT --server.address=0.0.0.0
--server.headless=true --server.enableCORS=true --server.timeout=300
--server.maxUploadSize=95`) so the command uses only valid Streamlit server
flags; update that command to omit `--server.timeout=300` and keep the other
flags (e.g., `--server.port`, `--server.address`, `--server.headless`,
`--server.enableCORS`, `--server.maxUploadSize`) unchanged.

| Healthcheck Path | `/` |
| Public Network | ✅ Enabled |
| Always On | ✅ Enabled |
| Zero Downtime Deployments | ❌ Disabled |

### ✅ Environment Variables:
```env
ENVIRONMENT=production
API_URL=https://<your-fastapi-domain>.up.railway.app
```

### Memory Optimizations
For best performance on Railway standard instances:
- Use `WHISPER_MODEL=base` for transcription
- Disable GPU acceleration
- Use OpenAI embeddings instead of local sentence-transformers
- Configure 8GB RAM instance for reliable operation

---

## 🔒 Security Best Practices
## 🔧 REQUIRED POST-DEPLOYMENT STEPS:

1. Never commit `.env` files to repository
2. All secrets are stored exclusively in Railway Variables
3. Use Railway's built-in environment encryption
4. Enable HTTPS only (default on Railway domains)
5. Restrict CORS origins in production
1. **Open Railway Support Ticket**: Request to increase proxy timeout to 600 seconds for both services
2. **First Deploy Order**: Deploy API service first, wait until it is fully running before deploying UI
3. **Verify Health**: Check `/health` endpoint on API service returns 200 OK
4. **Test End To End**: Upload a small 1 minute video to confirm full pipeline works

---

## 📊 Monitoring & Logs

- View realtime logs directly in Railway dashboard
- Enable Railway Metrics for performance monitoring
- Configure alerts for service downtime
- Monitor memory usage - this application is memory intensive

---

## ❌ Common Issues

| Problem | Solution |
|---------|----------|
| Build fails with out of memory | Upgrade service to 8GB RAM plan |
| Qdrant connection errors | Verify `QDRANT_HTTPS=true` is set |
| Whisper transcription crashes | Reduce whisper model size |
| Streamlit timeout | Increase Railway service timeout settings |
## ❌ NEVER DO THESE:
- ❌ Do NOT hardcode PORT in any config
- ❌ Do NOT set start command in railway.toml (Railway has bug with $PORT expansion)
- ❌ Do NOT use whisper model larger than tiny on standard instances
- ❌ Do NOT use more than 2 uvicorn workers
- ❌ Do NOT enable zero downtime deployments
- ❌ Do NOT forget to mount persistent volume

---

## ✅ Deployment Complete
## ✅ Final Verification Checklist:

Your Streaming Video RAG system will now be running on Railway at:
`https://your-service-name.up.railway.app`
- [ ] Volume mounted successfully at /app/data
- [ ] API /health endpoint returns 200 OK
- [ ] Streamlit UI loads without errors
- [ ] You can navigate all tabs
- [ ] You can upload a small video file
- [ ] Transcription completes successfully
- [ ] Semantic search returns results
- [ ] Q&A functionality answers questions

For support see Railway documentation: https://docs.railway.app/
This deployment will run reliably 24/7 on Railway.
10 changes: 10 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,17 @@ exclude = '''
| .venv
| venv
| node_modules
| data
| certs
| .github
| migrations
)/
| \.env.*
| docker-compose\.yml
| Dockerfile
| railway\.toml
| \.gitignore
| \.pre-commit-config\.yaml
'''

[tool.ruff]
Expand Down
12 changes: 12 additions & 0 deletions railway.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[build]
cache = true
buildpacks = []

[deploy]
healthcheckPath = "/health"
healthcheckTimeout = 120
healthcheckInterval = 10
restartPolicyType = "always"

[env]
PYTHONUNBUFFERED = "true"
Loading