This commit is contained in:
2026-05-31 23:30:35 -07:00
parent 431ffdff06
commit 3e50191530
20 changed files with 539 additions and 78 deletions
+53 -15
View File
@@ -3,12 +3,13 @@
Evanescere turns recorded livestreams into suggested, rendered clips:
1. Poll IIS WebDAV for finished recordings.
2. Wait until file size is unchanged across polling cycles.
3. Download the stable source file to Framework-local storage.
4. Remux FLV/H264 to MP4 and extract ASR-ready audio.
5. Transcribe Mandarin audio through a FunASR-compatible API.
6. Ask DeepSeek for ranked timeline-aware clip suggestions.
7. Generate subtitles, render clips, generate thumbnails with optional local image generation and VTuber overlay, and optionally upload.
2. Record files visible during the first scan as a manual-only historical baseline.
3. For files first seen later, wait until file size is unchanged across polling cycles.
4. Download the stable source file to Framework-local storage.
5. Remux FLV/H264 to MP4 and extract ASR-ready audio.
6. Transcribe Mandarin audio through a FunASR-compatible API.
7. Ask DeepSeek for ranked timeline-aware clip suggestions.
8. Generate subtitles, render clips, generate thumbnails with optional local image generation and VTuber overlay, and optionally upload.
The Framework Arch server is the intended production host. The Hyper-V Arch VM can be used for development, API testing, and database/control-plane work.
@@ -28,7 +29,8 @@ Runtime data flow:
```text
IIS WebDAV recordings
-> scheduler polls file size
-> first scan records existing files as manual-only baseline entries
-> later scans poll new file sizes
-> PostgreSQL records video state
-> Redis queues pipeline job
-> worker downloads source to configured storage.local_root
@@ -67,8 +69,8 @@ The checked-in `docker-compose.yml` mounts local `./config.toml` there for the A
## Services And Ports
- Frontend: `http://localhost:3000`
- Backend API: `http://localhost:8000`
- API docs: `http://localhost:8000/docs`
- Backend API: `http://localhost:8080`
- API docs: `http://localhost:8080/docs`
- Redis: `localhost:6379` when exposed by Compose
- PostgreSQL: only started by Compose when using the `local-db` profile
@@ -92,12 +94,14 @@ Run database migrations:
docker compose run --rm api alembic upgrade head
```
Bootstrap existing WebDAV files so old recordings are marked `existing_done` instead of auto-processed:
The scheduler automatically records files visible during its first scan as `existing_done`. Those historical recordings appear in the UI but are not automatically processed. To establish that baseline manually before starting the scheduler:
```bash
docker compose run --rm api evanescere bootstrap-existing
```
In the frontend, click `Sync WebDAV` to perform the same safe first-time baseline import or to discover later files. Select any historical FLV row and click its play button to manually queue a test pipeline run.
Useful test commands:
```bash
@@ -141,7 +145,7 @@ The frontend reads the backend URL from `frontend/public/config.js` at runtime:
```js
window.__EVANESCERE_FRONTEND_CONFIG__ = {
apiBaseUrl: "http://localhost:8000"
apiBaseUrl: "http://192.168.1.44:8080"
};
```
@@ -181,11 +185,11 @@ provider = "frame_overlay"
This uses the extracted frame as the background, then programmatically overlays the title and character PNG using Pillow.
To overlay the VTuber character, use a transparent PNG:
To overlay the VTuber character, place transparent PNG variants in a directory. Evanescere picks one randomly for each thumbnail:
```toml
[thumbnail]
character_overlay_path = "/data/evanescere/assets/vtuber.png"
character_overlay_dir = "/data/evanescere/assets/"
character_scale = 0.42
character_position = "bottom-right"
```
@@ -277,6 +281,8 @@ The full commented example lives in `config.example.toml`. These are the keys th
| `deepseek` | `api_key` | empty | DeepSeek API key. Required when clip suggestion is enabled. |
| `deepseek` | `model` | `deepseek-v4-pro` | Model used for clip suggestion. |
| `deepseek` | `temperature` | `0.2` | Sampling temperature for clip suggestion. |
| `llm_prompt` | `system` | VTuber clip editor prompt | Custom system prompt for clip selection. The required JSON schema is appended by code. |
| `llm_prompt` | `user` | timestamped transcript prompt | Custom user prompt template. Supports documented placeholders. |
| `defaults` | `suggest_enabled` | `true` | Initial setting for automatic LLM clip suggestion. |
| `defaults` | `render_enabled` | `true` | Initial setting for automatic rendering. |
| `defaults` | `upload_enabled` | `true` | Initial setting for automatic upload after render. For testing, set false. |
@@ -285,11 +291,12 @@ The full commented example lives in `config.example.toml`. These are the keys th
| `clip` | `min_seconds` | `30` | Minimum LLM clip duration accepted by backend. |
| `clip` | `max_seconds` | `360` | Maximum LLM clip duration accepted by backend. |
| `clip` | `transcript_chunk_seconds` | `900` | Transcript seconds sent to DeepSeek per request. |
| `clip` | `max_candidates_total` | `20` | Maximum suggestions kept across the entire transcript after overlap deduplication. |
| `thumbnail` | `enabled` | `true` | Enables thumbnail generation during clip render. |
| `thumbnail` | `provider` | `frame_overlay` | `frame_overlay` or `command`. |
| `thumbnail` | `width` | `1920` | Final thumbnail width in pixels. |
| `thumbnail` | `height` | `1080` | Final thumbnail height in pixels. |
| `thumbnail` | `character_overlay_path` | empty | Optional transparent PNG of the VTuber character. |
| `thumbnail` | `character_overlay_dir` | `/data/evanescere/assets/` | Directory of transparent VTuber PNG variants. One is selected randomly per thumbnail. |
| `thumbnail` | `character_scale` | `0.42` | Character overlay height as a fraction of final thumbnail height. |
| `thumbnail` | `character_position` | `bottom-right` | Character placement. |
| `thumbnail` | `title_enabled` | `true` | Draws the clip title onto the final thumbnail. |
@@ -324,12 +331,42 @@ docker compose run --rm api
Useful API endpoints for generated files:
- `POST /webdav/scan`
- `GET /videos/{video_id}/artifacts`
- `GET /clips/{clip_id}/artifacts`
- `GET /artifacts/{artifact_id}`
Thumbnail outputs are visible through the artifact endpoints. Upload command payloads include `thumbnail` when a `thumbnail_final` artifact exists.
## Custom LLM Prompt
Edit `[llm_prompt]` in your private `config.toml` to tune clip selection without rebuilding containers:
```toml
[llm_prompt]
system = """
Your custom editorial guidance.
"""
user = """
Choose up to {max_candidates} clips between {min_clip_seconds} and {max_clip_seconds} seconds.
Stream range: {chunk_start_sec}-{chunk_end_sec}
Transcript:
{transcript}
"""
```
Available user-prompt placeholders:
- `{max_candidates}`
- `{min_clip_seconds}`
- `{max_clip_seconds}`
- `{chunk_start_sec}`
- `{chunk_end_sec}`
- `{transcript}`
The backend appends its strict JSON response schema to the system message so custom prompt wording cannot accidentally remove the machine-readable output contract.
## Debugging
Set verbose logs in `config.toml`:
@@ -352,6 +389,7 @@ docker compose logs -f api
What to look for:
- Scheduler logs `webdav propfind done`, `new webdav file observed`, and `webdav file stable`.
- On first startup, scheduler logs `webdav baseline missing` and stores all currently visible recordings as `existing_done`.
- Worker logs `pipeline start`, `prepare media`, `transcription start`, `clip suggestion start`, `render start`, and `upload start`.
- ffmpeg command failures include the failing command and stderr tail.
- DeepSeek logs include transcript chunk bounds, character counts, candidate counts, and usage when returned by the SDK.
@@ -371,4 +409,4 @@ This is intentionally noisy and should usually stay off in production.
- FunASR/ROCm setup is intentionally outside the main Compose file for now. Benchmark the Framework host manually before binding the project to a specific GPU runtime.
- The uploader adapter is deliberately small. `[upload].adapter = "command"` is enough to integrate a Bilibili uploader later without changing the pipeline core.
- Existing recordings should be bootstrapped before scheduler-driven production runs, otherwise old stable files may be queued as new work.
- Existing recordings are automatically baselined on the first scheduler scan. The explicit `evanescere bootstrap-existing` command remains available when you want to establish or refresh the baseline before starting services.