Merge pull request #2 from BusyBee3333/codex/add-setup-files-for-backend-deployment
Add local backend setup documentation and docker compose stack
This commit is contained in:
commit
85b04e116d
145
README.md
145
README.md
@ -1,2 +1,143 @@
|
|||||||
# beatmatchr
|
# beatmatchr backend
|
||||||
# beatmatchr
|
|
||||||
|
A lightweight FastAPI service that powers beatmatchr. This guide walks through
|
||||||
|
the steps required to run the backend locally.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Python 3.10 or newer installed and available on your `PATH`.
|
||||||
|
- [`ffmpeg`](https://ffmpeg.org/) installed (macOS: `brew install ffmpeg`,
|
||||||
|
Ubuntu/Debian: `sudo apt install ffmpeg`).
|
||||||
|
- Docker and Docker Compose (v2) for running Postgres and Redis.
|
||||||
|
|
||||||
|
## 1. Create and activate a virtual environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -m venv .venv
|
||||||
|
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Install Python dependencies
|
||||||
|
|
||||||
|
With the virtual environment active, install the requirements:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Start Postgres and Redis via Docker Compose
|
||||||
|
|
||||||
|
A `docker-compose.yml` file is provided at the repository root. Launch the
|
||||||
|
services in the background:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
This spins up:
|
||||||
|
|
||||||
|
- Postgres on port `5432` with database/user/password `beatmatchr`.
|
||||||
|
- Redis on port `6379` for task queue usage.
|
||||||
|
|
||||||
|
If you need to tear everything down (including volumes), run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Configure environment variables
|
||||||
|
|
||||||
|
Export environment variables that the backend expects. The defaults line up with
|
||||||
|
`docker-compose.yml`, so you can simply create a `.env` file (or export them in
|
||||||
|
your shell):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export POSTGRES_USER=beatmatchr
|
||||||
|
export POSTGRES_PASSWORD=beatmatchr
|
||||||
|
export POSTGRES_DB=beatmatchr
|
||||||
|
export POSTGRES_HOST=localhost
|
||||||
|
export POSTGRES_PORT=5432
|
||||||
|
export REDIS_HOST=localhost
|
||||||
|
export REDIS_PORT=6379
|
||||||
|
export REDIS_DB=0
|
||||||
|
export CELERY_BROKER_URL=redis://localhost:6379/0
|
||||||
|
export CELERY_RESULT_BACKEND=redis://localhost:6379/0
|
||||||
|
```
|
||||||
|
|
||||||
|
Feel free to adjust these if you change the Docker Compose configuration.
|
||||||
|
|
||||||
|
## 5. Run database migrations / initialize tables
|
||||||
|
|
||||||
|
If you have Alembic migrations configured, apply them with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
alembic upgrade head
|
||||||
|
```
|
||||||
|
|
||||||
|
If migrations are not available yet, you can run your project-specific database
|
||||||
|
bootstrap script (for example `python -m backend.db init_db`) to create tables
|
||||||
|
manually. Ensure the `DATABASE_URL` environment variable is pointing at the
|
||||||
|
Postgres instance from the Docker Compose stack.
|
||||||
|
|
||||||
|
## 6. Start the FastAPI application
|
||||||
|
|
||||||
|
Launch the app with `uvicorn` (hot reload optional):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn backend.main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
The API will be available at <http://localhost:8000/>.
|
||||||
|
|
||||||
|
## 7. Start the Celery/RQ worker
|
||||||
|
|
||||||
|
For Celery, point to the Celery app defined in your project (replace the module
|
||||||
|
path if needed):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
celery -A backend.worker.celery_app worker --loglevel=info
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using RQ instead of Celery, start a worker referencing the same Redis
|
||||||
|
instance:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rq worker beatmatchr --url redis://localhost:6379/0
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Example API usage
|
||||||
|
|
||||||
|
Replace `PROJECT_ID` with the UUID returned from the *create project* call.
|
||||||
|
|
||||||
|
### Create a project
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "http://localhost:8000/projects" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name": "Demo Project", "description": "My first beatmatch"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Upload audio to a project
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "http://localhost:8000/projects/PROJECT_ID/audio" \
|
||||||
|
-F "file=@/path/to/local/file.wav"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add a source clip by URL
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "http://localhost:8000/projects/PROJECT_ID/sources" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"url": "https://example.com/audio.mp3", "start": 0, "end": 30}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fetch lyrics for a track
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl "http://localhost:8000/projects/PROJECT_ID/lyrics"
|
||||||
|
```
|
||||||
|
|
||||||
|
With the services running and environment variables configured, you should be
|
||||||
|
able to follow the steps above to interact with the beatmatchr backend locally.
|
||||||
|
|||||||
@ -1,7 +1,64 @@
|
|||||||
|
"""Application configuration utilities."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
|
||||||
|
class Settings:
|
||||||
|
"""Configuration values loaded from environment variables.
|
||||||
|
|
||||||
|
The defaults are tuned for local development and match the docker-compose
|
||||||
|
configuration provided in this repository. Each value can be overridden by
|
||||||
|
setting the corresponding environment variable before starting the
|
||||||
|
application.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.postgres_user: str = os.getenv("POSTGRES_USER", "beatmatchr")
|
||||||
|
self.postgres_password: str = os.getenv("POSTGRES_PASSWORD", "beatmatchr")
|
||||||
|
self.postgres_db: str = os.getenv("POSTGRES_DB", "beatmatchr")
|
||||||
|
self.postgres_host: str = os.getenv("POSTGRES_HOST", "localhost")
|
||||||
|
self.postgres_port: int = int(os.getenv("POSTGRES_PORT", "5432"))
|
||||||
|
|
||||||
|
self.redis_host: str = os.getenv("REDIS_HOST", "localhost")
|
||||||
|
self.redis_port: int = int(os.getenv("REDIS_PORT", "6379"))
|
||||||
|
self.redis_db: int = int(os.getenv("REDIS_DB", "0"))
|
||||||
|
|
||||||
|
self.database_url: str = os.getenv(
|
||||||
|
"DATABASE_URL",
|
||||||
|
(
|
||||||
|
"postgresql+asyncpg://"
|
||||||
|
f"{self.postgres_user}:{self.postgres_password}"
|
||||||
|
f"@{self.postgres_host}:{self.postgres_port}/{self.postgres_db}"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
redis_base_url = f"redis://{self.redis_host}:{self.redis_port}/{self.redis_db}"
|
||||||
|
self.redis_url: str = os.getenv("REDIS_URL", redis_base_url)
|
||||||
|
self.celery_broker_url: str = os.getenv("CELERY_BROKER_URL", self.redis_url)
|
||||||
|
self.celery_result_backend: str = os.getenv(
|
||||||
|
"CELERY_RESULT_BACKEND", self.redis_url
|
||||||
|
)
|
||||||
|
|
||||||
|
def dict(self) -> Dict[str, Any]:
|
||||||
|
"""Return the settings as a plain dictionary (useful for debugging)."""
|
||||||
|
|
||||||
|
return {
|
||||||
|
"postgres_user": self.postgres_user,
|
||||||
|
"postgres_password": self.postgres_password,
|
||||||
|
"postgres_db": self.postgres_db,
|
||||||
|
"postgres_host": self.postgres_host,
|
||||||
|
"postgres_port": self.postgres_port,
|
||||||
|
"database_url": self.database_url,
|
||||||
|
"redis_host": self.redis_host,
|
||||||
|
"redis_port": self.redis_port,
|
||||||
|
"redis_db": self.redis_db,
|
||||||
|
"redis_url": self.redis_url,
|
||||||
|
"celery_broker_url": self.celery_broker_url,
|
||||||
|
"celery_result_backend": self.celery_result_backend,
|
||||||
|
}
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
@ -47,6 +104,9 @@ class Settings(BaseSettings):
|
|||||||
|
|
||||||
@lru_cache()
|
@lru_cache()
|
||||||
def get_settings() -> Settings:
|
def get_settings() -> Settings:
|
||||||
|
"""Return a cached instance of :class:`Settings`."""
|
||||||
|
|
||||||
|
return Settings()
|
||||||
"""Return cached application settings instance."""
|
"""Return cached application settings instance."""
|
||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
|
|||||||
36
docker-compose.yml
Normal file
36
docker-compose.yml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:15
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: beatmatchr
|
||||||
|
POSTGRES_PASSWORD: beatmatchr
|
||||||
|
POSTGRES_DB: beatmatchr
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U beatmatchr"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- redis-data:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres-data:
|
||||||
|
redis-data:
|
||||||
12
requirements.txt
Normal file
12
requirements.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
fastapi>=0.110
|
||||||
|
uvicorn[standard]>=0.24
|
||||||
|
sqlalchemy>=2.0
|
||||||
|
asyncpg>=0.29
|
||||||
|
databases[postgresql]>=0.7
|
||||||
|
alembic>=1.12
|
||||||
|
aiofiles>=23.2
|
||||||
|
pydantic>=2.0
|
||||||
|
celery>=5.3
|
||||||
|
redis>=5.0
|
||||||
|
rq>=1.15
|
||||||
|
python-dotenv>=1.0
|
||||||
Loading…
x
Reference in New Issue
Block a user