| --- |
| title: footclip |
| sdk: docker |
| emoji: π |
| colorFrom: red |
| colorTo: blue |
| --- |
| # β½ FootClip AI β Football Highlight Generator API |
|
|
| Automatically generates professional highlight reels from full match videos using **YOLOv8** computer vision and **audio crowd-excitement analysis**. |
|
|
| --- |
|
|
| ## π Deploy on Hugging Face Spaces |
|
|
| ### Step-by-Step: |
|
|
| 1. Go to [huggingface.co/spaces](https://huggingface.co/spaces) β **Create new Space** |
| 2. Choose **Docker** as the SDK |
| 3. Select **T4 GPU** (free tier works, GPU recommended) |
| 4. Upload all 6 files: |
| - `main.py` |
| - `pipeline.py` |
| - `models.py` |
| - `requirements.txt` |
| - `Dockerfile` |
| - `README.md` |
| 5. The Space auto-builds and starts on **port 7860** |
| 6. Your API is live at: `https://<your-username>-<space-name>.hf.space` |
|
|
| --- |
|
|
| ## π‘ API Endpoints |
|
|
| ### Base URL |
| ``` |
| https://<your-username>-<space-name>.hf.space |
| ``` |
|
|
| --- |
|
|
| ### `GET /api/health` |
| Check if the server is running. |
|
|
| ```bash |
| curl https://your-space.hf.space/api/health |
| ``` |
|
|
| Response: |
| ```json |
| {"status": "ok", "device": "cuda", "workspace": "/app/workspace"} |
| ``` |
|
|
| --- |
|
|
| ### `POST /api/upload` |
| Upload a local video file. |
|
|
| ```bash |
| curl -X POST https://your-space.hf.space/api/upload \ |
| -F "file=@match_video.mp4" |
| ``` |
|
|
| Response: |
| ```json |
| {"filename": "a1b2c3d4_match_video.mp4", "path": "/app/workspace/uploads/a1b2c3d4_match_video.mp4"} |
| ``` |
|
|
| --- |
|
|
| ### `POST /api/process` |
| Start highlight generation. |
|
|
| **With YouTube URL:** |
| ```bash |
| curl -X POST https://your-space.hf.space/api/process \ |
| -H "Content-Type: application/json" \ |
| -d '{ |
| "video_url": "https://www.youtube.com/watch?v=VIDEO_ID", |
| "highlight_duration": 10, |
| "style": "dynamic", |
| "output_quality": "720p", |
| "team_home": "Barcelona", |
| "team_away": "Real Madrid", |
| "match_date": "2024-10-26", |
| "fast_mode": false |
| }' |
| ``` |
|
|
| **With uploaded file (use path from /api/upload):** |
| ```bash |
| curl -X POST https://your-space.hf.space/api/process \ |
| -H "Content-Type: application/json" \ |
| -d '{ |
| "video_url": "/app/workspace/uploads/a1b2c3d4_match_video.mp4", |
| "highlight_duration": 8, |
| "style": "goals_only", |
| "output_quality": "1080p" |
| }' |
| ``` |
|
|
| **Parameters:** |
|
|
| | Parameter | Type | Default | Description | |
| |-----------|------|---------|-------------| |
| | `video_url` | string | required | YouTube URL, direct URL, or local path | |
| | `highlight_duration` | int | 10 | Target duration in minutes (3-20) | |
| | `style` | string | "dynamic" | `dynamic`, `broadcast`, `goals_only`, `tactical` | |
| | `output_quality` | string | "720p" | `480p`, `720p`, `1080p` | |
| | `team_home` | string | null | Home team name (for intro card) | |
| | `team_away` | string | null | Away team name (for intro card) | |
| | `match_date` | string | null | Match date (for intro card) | |
| | `fast_mode` | bool | false | Audio-only analysis (~80% quality, no GPU needed) | |
| | `frame_sample_rate` | int | 5 | Analyze every Nth frame (higher = faster) | |
| | `pre_buffer` | float | 3.0 | Seconds before each event | |
| | `post_buffer` | float | 5.0 | Seconds after each event | |
|
|
| Response: |
| ```json |
| {"job_id": "abc123def456", "status": "queued"} |
| ``` |
|
|
| --- |
|
|
| ### `GET /api/status/{job_id}` |
| Poll for job progress. |
| |
| ```bash |
| curl https://your-space.hf.space/api/status/abc123def456 |
| ``` |
| |
| Response (processing): |
| ```json |
| { |
| "job_id": "abc123def456", |
| "status": "processing", |
| "progress": 0.45, |
| "stage": "cv", |
| "message": "Running CV analysis (chunk 2/4)...", |
| "result": null |
| } |
| ``` |
| |
| Response (done): |
| ```json |
| { |
| "job_id": "abc123def456", |
| "status": "done", |
| "progress": 1.0, |
| "stage": "done", |
| "message": "β
Done in 12.3 min β 15 clips, 9.5 min highlight", |
| "result": { |
| "output_path": "/app/workspace/output/abc123def456.mp4", |
| "duration": 570.0, |
| "clips_count": 15, |
| "events_detected": 47, |
| "processing_time": 738.2, |
| "fast_mode": false, |
| "goals_detected": 0 |
| } |
| } |
| ``` |
| |
| --- |
|
|
| ### `GET /api/download/{job_id}` |
| Download the final highlight MP4. |
| |
| ```bash |
| curl -O https://your-space.hf.space/api/download/abc123def456 |
| ``` |
| |
| --- |
| |
| ### `GET /api/jobs` |
| List all jobs. |
| |
| ```bash |
| curl https://your-space.hf.space/api/jobs |
| ``` |
| |
| --- |
| |
| ## π Full Workflow Example (Python) |
| |
| ```python |
| import requests |
| import time |
| |
| BASE = "https://your-space.hf.space" |
| |
| # 1. Start processing |
| resp = requests.post(f"{BASE}/api/process", json={ |
| "video_url": "https://www.youtube.com/watch?v=VIDEO_ID", |
| "highlight_duration": 10, |
| "style": "dynamic", |
| "output_quality": "720p", |
| "team_home": "Barcelona", |
| "team_away": "Real Madrid", |
| }) |
| job_id = resp.json()["job_id"] |
| print(f"Job started: {job_id}") |
| |
| # 2. Poll status |
| while True: |
| status = requests.get(f"{BASE}/api/status/{job_id}").json() |
| print(f"[{status['progress']:.0%}] {status['stage']}: {status['message']}") |
| if status["status"] in ("done", "error"): |
| break |
| time.sleep(10) |
| |
| # 3. Download |
| if status["status"] == "done": |
| video = requests.get(f"{BASE}/api/download/{job_id}") |
| with open("highlights.mp4", "wb") as f: |
| f.write(video.content) |
| print("β
Saved highlights.mp4") |
| else: |
| print(f"β Error: {status['message']}") |
| ``` |
| |
| --- |
|
|
| ## β‘ Styles Explained |
|
|
| | Style | Best For | |
| |-------|----------| |
| | **dynamic** | Fast-paced, exciting highlights with crowd reactions | |
| | **broadcast** | Balanced TV-style highlights | |
| | **goals_only** | Only the most significant goal-like moments | |
| | **tactical** | Player formations, set pieces, tactical moments | |
| |
| --- |
| |
| ## π‘ Tips |
| |
| - **Fast Mode**: Set `fast_mode: true` for quick results without GPU (audio-only analysis) |
| - **Large videos**: Auto-compressed if >2GB, auto-chunked if >10 min |
| - **GPU**: T4 GPU processes ~90 min match in ~15 min. CPU takes 3-5x longer |
| - The API docs are also available at `https://your-space.hf.space/docs` (Swagger UI) |