Skip to content
Open
Show file tree
Hide file tree
Changes from 8 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
138 changes: 60 additions & 78 deletions .github/workflows/ui-lint-and-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ jobs:

- name: Build UI
working-directory: "application/ui"
env:
PUBLIC_API_BASE_URL: ""
Copy link
Contributor Author

@jpggvilaca jpggvilaca Oct 10, 2025

Choose a reason for hiding this comment

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

to avoid setting http://localhost:7680/api/... to our baseUrl, so the UI use relative urls

run: npm run build

- name: Compress build
Expand Down Expand Up @@ -353,84 +355,64 @@ jobs:
path: application/ui/playwright-report/
retention-days: 30

# e2e-tests:
# name: E2E Tests
# needs:
# - check_paths
# - build
# - generate-openapi-spec
# if: needs.check_paths.outputs.run_workflow == 'true'
# permissions:
# contents: read
# timeout-minutes: 30
# runs-on: ubuntu-latest
# container:
# image: mcr.microsoft.com/playwright:v1.54.0-noble@sha256:18d6adb6aaccf1b0f30eba890069972e089138e4a59ddb5303d7e7290e4e38b6
# steps:
# - name: Checkout code
# uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
# with:
# persist-credentials: false

# - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
# with:
# node-version-file: application/ui/.nvmrc

# - name: Set up Python
# uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
# with:
# python-version: "3.13"

# - name: Install uv
# uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
# with:
# version: "0.8.8"
# enable-cache: false

# - name: Install OpenCV dependencies
# run: |
# apt-get update
# apt-get install -y libgl1 libglib2.0-0

# - name: Setup Backend
# working-directory: application/backend
# run: |
# uv sync --frozen --all-extras

# - name: Download UI build
# uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
# with:
# name: ui-dist
# path: application/ui

# - name: Download OpenAPI spec
# uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
# with:
# name: openapi-spec
# path: application/ui/src/api

# - name: Unpack build
# working-directory: "application/ui"
# run: tar -xzf dist.tar.gz

# - name: Install dependencies
# working-directory: "application/ui"
# run: npm ci

# - name: Build OpenAPI type definitions
# working-directory: "application/ui"
# run: npm run build:api

# - name: Run E2E tests
# working-directory: application/ui
# run: npm run test:e2e

# - name: Upload E2E results
# uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
# if: always()
# with:
# name: e2e-test-results
# path: application/ui/playwright-report/
e2e-tests:
name: E2E Tests
needs:
- check_paths
- build
- generate-openapi-spec
if: needs.check_paths.outputs.run_workflow == 'true'
permissions:
contents: read
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false

- name: Download UI build
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: ui-dist
path: application/ui

- name: Unpack build
working-directory: application/ui
run: tar -xzf dist.tar.gz

- name: Install dependencies
working-directory: application/ui
run: npm ci
Comment on lines +370 to +387
Copy link
Contributor

Choose a reason for hiding this comment

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

All this is unnecessary imho. We already have a Dockerfile that includes both the server and the UI, and a GHA workflow build.yaml to build it. I would expect the e2e workflow to use that image to spin up a container and run the tests on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree


- name: Run E2E tests with Docker Compose
working-directory: application/docker
env:
E2E_ASSETS_S3_URL: ${{ vars.E2E_ASSETS_S3_URL }}
run: |
docker compose --profile e2e up \
Copy link
Contributor Author

Choose a reason for hiding this comment

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

the important change is this one.

--abort-on-container-exit \
--exit-code-from playwright-e2e

- name: Copy test results from container
if: always()
working-directory: application/docker
run: |
# Results are already mounted, just ensure they're visible
ls -la ../ui/playwright-report/ || true

- name: Upload E2E results
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always()
with:
name: e2e-test-results
path: application/ui/playwright-report/

- name: Cleanup
if: always()
working-directory: application/docker
run: docker compose --profile e2e down -v

required_check:
name: Required Check ui-lint-and-test
Expand Down
1 change: 1 addition & 0 deletions application/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

# Backend files
!backend/app
!backend/run.sh
Copy link
Contributor Author

Choose a reason for hiding this comment

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

because we need to copy this bad boy now

Copy link
Contributor

Choose a reason for hiding this comment

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

No, we shouldn't copy it. Can you motivate the need for the copy?

!backend/pyproject.toml
!backend/uv.lock

Expand Down
104 changes: 104 additions & 0 deletions application/backend/readme.md
Copy link
Contributor

Choose a reason for hiding this comment

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

With the current pace of development, I'm afraid this readme.md will be largely obsolete in a couple of weeks. I intentionally kept it short so that we don't have to constantly update it.

Original file line number Diff line number Diff line change
@@ -1,3 +1,107 @@
# Geti Tune

Geti Tune is a full-stack application for efficiently fine-tuning state-of-the-art computer vision models for tasks like classification, detection, and segmentation.

## Quick Start

### Basic Usage

```bash
# Start the server (development mode)
./run.sh
```

### E2E Testing Setup

```bash
# Full E2E setup with database seeding and test file downloads
DATABASE_FILE=geti_tune_e2e.db SEED_DB=true DOWNLOAD_FILES=true ./run.sh

Choose a reason for hiding this comment

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

Just wondering why a db_file name should be different for e2e tests setup?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The goal was to also be able to run these locally, and since some tests require seeding, we need a temporary DB that we can setup/destroy after every run


# Or use the convenience script
./start_e2e.sh
```

## Configuration

### What `run.sh` Does

1. **Loads configuration** from environment variables
2. **Seeds database** (if `SEED_DB=true`):
- Creates a test project with labels
- Sets up pipeline with video source and model
3. **Downloads test files** (if `DOWNLOAD_FILES=true`):
- Test video: `data/media/video.mp4`
- Model files: `data/projects/.../model.xml` and `model.bin`
4. **Starts the FastAPI server** on `http://localhost:7860`

### Test Assets

By default, test assets are downloaded from a public URL. In CI/GitHub Actions, a repository variable `E2E_ASSETS_S3_URL` can be set to use a private asset location.

## Docker

The backend can also run in Docker:

```bash
cd ../docker

# Build and run E2E backend
docker compose --profile e2e up backend-e2e

# Or run full E2E stack
docker compose --profile e2e up --abort-on-container-exit
```

The Docker setup uses the same `run.sh` script for consistency.

## API Documentation

Once the server is running, visit:
- http://localhost:7860/docs

## Development

### Requirements

- Python 3.13+
- `uv` CLI tool for dependency management
- SQLite (included with Python)

### Project Structure

```
backend/
├── app/
│ ├── main.py # FastAPI application entry point
│ ├── cli.py # CLI commands (init-db, seed)
│ ├── api/ # API endpoints
│ ├── core/ # Core functionality (scheduler, lifecycle)
│ ├── db/ # Database models and migrations
│ ├── entities/ # Business logic entities
│ ├── repositories/ # Data access layer
│ ├── schemas/ # Pydantic schemas
│ ├── services/ # Business logic services
│ ├── webrtc/ # WebRTC streaming
│ └── workers/ # Background workers
├── data/ # Runtime data (database, media, models)
├── run.sh # Main startup script
```

## Troubleshooting

### Port already in use

```bash
lsof -ti:7860 | xargs kill -9
```

### Database locked

```bash
rm data/geti_tune.db
./run.sh
```

### Test file download fails

Check that `E2E_ASSETS_S3_URL` is accessible or verify the public URL is working. The script will exit with an error if downloads fail.
88 changes: 57 additions & 31 deletions application/backend/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,62 @@ set -euo pipefail
# run.sh - Script to run the Geti Tune FastAPI server
#
# Features:
# - Optionally seed the database before starting the server by setting:
# SEED_DB=true
# - Optionally download test video and model files before starting the server by setting:
# DOWNLOAD_FILES=true
# - Optionally seed the database (SEED_DB=true)
# - Optionally download test files (DOWNLOAD_FILES=true)
# - Configure database file name (DATABASE_FILE)
#
# Usage:
# SEED_DB=true DOWNLOAD_FILES=true ./run.sh # Seed database, download data and launch the server
# ./run.sh # Run server without seeding or downloading files
# SEED_DB=true DOWNLOAD_FILES=true ./run.sh # Seed and download
# DATABASE_FILE=geti_tune_e2e.db SEED_DB=true ./run.sh # Use E2E database
# ./run.sh # Run with defaults
#
# Environment variables:
# SEED_DB If set to "true", runs `uv run app/cli seed` before starting the server.
# DOWNLOAD_FILES If set to "true", downloads test video and model files if not already present.
# APP_MODULE Python module to run (default: app/main.py)
# UV_CMD Command to launch Uvicorn (default: "uv run")
# SEED_DB If set to "true", runs database initialization and seeding
# DOWNLOAD_FILES If set to "true", downloads test video and model files
# DATABASE_FILE Name of the database file (default: geti_tune.db)
# E2E_ASSETS_S3_URL Base URL for E2E assets
#
# Requirements:
# - 'uv' CLI tool (Uvicorn) installed and available in PATH
# - Python modules and dependencies installed correctly
# - 'uv' CLI tool installed and available in PATH
# -----------------------------------------------------------------------------

SEED_DB=${SEED_DB:-false}
DOWNLOAD_FILES=${DOWNLOAD_FILES:-false}
DATABASE_FILE=${DATABASE_FILE:-geti_tune.db}
APP_MODULE=${APP_MODULE:-app/main.py}
UV_CMD=${UV_CMD:-uv run}
E2E_ASSETS_BASE_URL=${E2E_ASSETS_S3_URL:-https://storage.geti.intel.com/test-data/geti-tune}

export PYTHONUNBUFFERED=1
export PYTHONPATH=.
export DATABASE_FILE

DB_PATH="data/${DATABASE_FILE}"

echo "====================================="
echo "Starting Geti Tune Backend"
echo "Database: $DB_PATH"
echo "Assets URL: $E2E_ASSETS_BASE_URL"
echo "====================================="

if [[ "$SEED_DB" == "true" ]]; then
echo "Seeding the database..."
rm data/geti_tune.db || true
# Remove existing database if it exists
if [ -f "$DB_PATH" ]; then
echo "Removing existing database: $DB_PATH"
rm "$DB_PATH"
fi
echo "Initializing database..."
$UV_CMD app/cli.py init-db
echo "Seeding database with test data..."
$UV_CMD app/cli.py seed --with-model=True
fi

# URLs and target paths
VIDEO_URL="https://storage.geti.intel.com/test-data/geti-tune/media/card-video.mp4"
VIDEO_URL="${E2E_ASSETS_BASE_URL}/media/card-video.mp4"
VIDEO_TARGET="data/media/video.mp4"
MODEL_XML_URL="https://storage.geti.intel.com/test-data/geti-tune/models/ssd-card-detection.xml"
MODEL_BIN_URL="https://storage.geti.intel.com/test-data/geti-tune/models/ssd-card-detection.bin"
MODEL_XML_URL="${E2E_ASSETS_BASE_URL}/models/ssd-card-detection.xml"
MODEL_BIN_URL="${E2E_ASSETS_BASE_URL}/models/ssd-card-detection.bin"
MODEL_TARGET_DIR="data/projects/9d6af8e8-6017-4ebe-9126-33aae739c5fa/models/977eeb18-eaac-449d-bc80-e340fbe052ad"
MODEL_XML_TARGET="$MODEL_TARGET_DIR/model.xml"
MODEL_BIN_TARGET="$MODEL_TARGET_DIR/model.bin"
Expand All @@ -54,26 +70,36 @@ if [[ "$DOWNLOAD_FILES" == "true" ]]; then
# Download video
if [ ! -f "$VIDEO_TARGET" ]; then
mkdir -p "$(dirname "$VIDEO_TARGET")"
echo "Downloading test video..."
curl -fL "$VIDEO_URL" -o "$VIDEO_TARGET"
echo "Downloading test video from $VIDEO_URL..."
if curl -fL "$VIDEO_URL" -o "$VIDEO_TARGET"; then
echo "✓ Video downloaded successfully"
else
echo "✗ Failed to download video from $VIDEO_URL"
exit 1
fi
else
echo "Test video already exists at $VIDEO_TARGET"
echo "Test video already exists at $VIDEO_TARGET"
fi
# Download model XML
if [ ! -f "$MODEL_XML_TARGET" ]; then
mkdir -p "$MODEL_TARGET_DIR"
echo "Downloading model XML..."
curl -fL "$MODEL_XML_URL" -o "$MODEL_XML_TARGET"
else
echo "Model XML already exists at $MODEL_XML_TARGET"

# Verify video file is valid (has content)
if [ ! -s "$VIDEO_TARGET" ]; then
echo "✗ Error: Video file is empty at $VIDEO_TARGET"
exit 1
fi
# Download model BIN
if [ ! -f "$MODEL_BIN_TARGET" ]; then

# Download model files
if [ ! -f "$MODEL_XML_TARGET" ]; then
mkdir -p "$MODEL_TARGET_DIR"
echo "Downloading model BIN..."
curl -fL "$MODEL_BIN_URL" -o "$MODEL_BIN_TARGET"
echo "Downloading model files..."
if curl -fL "$MODEL_XML_URL" -o "$MODEL_XML_TARGET" && \
curl -fL "$MODEL_BIN_URL" -o "$MODEL_BIN_TARGET"; then
echo "✓ Model files downloaded successfully"
else
echo "✗ Failed to download model files"
exit 1
fi
else
echo "Model BIN already exists at $MODEL_BIN_TARGET"
echo "Model files already exist"
fi
fi

Expand Down
Loading
Loading