Skip to content

Commit 4eab34c

Browse files
authored
Merge pull request #466 from calesthio/codex/backlog-recovery-20260802
Recover bounded defects from the latest PR backlog
2 parents c36e412 + 9482edd commit 4eab34c

68 files changed

Lines changed: 1912 additions & 375 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 69 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,72 +2,103 @@
22
# Copy this to .env and fill in your keys
33

44
# --- Image + video gateway ---
5-
FAL_KEY= # FLUX images, Google Veo video, Kling video, MiniMax video, Recraft images
6-
# Get one at https://fal.ai/dashboard/keys
7-
FAL_AI_API_KEY= # Alias for FAL_KEY (some SDKs/docs use this name); either one is read.
5+
# FLUX images, Google Veo video, Kling video, MiniMax video, Recraft images.
6+
# Get one at https://fal.ai/dashboard/keys
7+
FAL_KEY=
8+
# Alias for FAL_KEY (some SDKs/docs use this name); either one is read.
9+
FAL_AI_API_KEY=
810

911
# --- Replicate ---
10-
REPLICATE_API_TOKEN= # Replicate-hosted video gen (seedance_replicate). Needed to make the
11-
# Replicate-backed Seedance path selectable alongside the fal.ai one.
12-
# Get one at https://replicate.com/account/api-tokens
12+
# Replicate-hosted video gen (seedance_replicate). Needed to make the
13+
# Replicate-backed Seedance path selectable alongside the fal.ai one.
14+
# Get one at https://replicate.com/account/api-tokens
15+
REPLICATE_API_TOKEN=
1316

1417
# --- Higgsfield ---
15-
HIGGSFIELD_API_KEY= # Higgsfield Cloud key (higgsfield_video). Pair with the secret below,
16-
HIGGSFIELD_API_SECRET= # or use the combined HIGGSFIELD_KEY="<key>:<secret>" form instead.
18+
# Higgsfield Cloud key (higgsfield_video). Pair with the secret below,
19+
# or use the combined HIGGSFIELD_KEY="<key>:<secret>" form instead.
20+
HIGGSFIELD_API_KEY=
21+
HIGGSFIELD_API_SECRET=
1722
# HIGGSFIELD_KEY= # Combined key:secret — set this INSTEAD of the _KEY/_SECRET pair if you prefer.
1823

1924
# --- Kling official direct API ---
20-
KLING_API_KEY= # Official Kling API key; enables video, image, TTS, avatar, lip sync
21-
KLING_API_BASE_URL= # Optional endpoint override; leave blank for default https://api-singapore.klingai.com
22-
# Mainland China accounts can use https://api-beijing.klingai.com
25+
# Official Kling API key; enables video, image, TTS, avatar, lip sync.
26+
KLING_API_KEY=
27+
# Optional endpoint override; leave blank for default https://api-singapore.klingai.com
28+
# Mainland China accounts can use https://api-beijing.klingai.com
29+
KLING_API_BASE_URL=
2330

2431
# --- Google (one key unlocks image gen + TTS + video) ---
25-
GOOGLE_API_KEY= # Google Imagen images, Google Cloud TTS (700+ voices, 50+ languages),
26-
# Gemini Omni video (generation + conversational editing, paid tier)
27-
# Get one at https://aistudio.google.com/apikey
32+
# Google Imagen images, Google Cloud TTS (700+ voices, 50+ languages),
33+
# Gemini Omni video (generation + conversational editing, paid tier).
34+
# Get one at https://aistudio.google.com/apikey
35+
GOOGLE_API_KEY=
2836
# GEMINI_API_KEY= # Alias for GOOGLE_API_KEY (takes precedence when both are set)
2937
# Alternative to the API key: service-account JSON auth.
3038
# TTS uses Cloud Text-to-Speech; Imagen routes to Vertex AI.
31-
GOOGLE_APPLICATION_CREDENTIALS= # path to a service-account JSON key file
32-
GOOGLE_CLOUD_PROJECT= # GCP project id (required for Imagen via Vertex AI)
33-
GOOGLE_CLOUD_LOCATION= # Vertex AI region, default us-central1
39+
# Path to a service-account JSON key file.
40+
GOOGLE_APPLICATION_CREDENTIALS=
41+
# GCP project id (required for Imagen via Vertex AI).
42+
GOOGLE_CLOUD_PROJECT=
43+
# Vertex AI region, default us-central1.
44+
GOOGLE_CLOUD_LOCATION=
3445

3546
# --- Voice ---
36-
ELEVENLABS_API_KEY= # TTS narration, music generation, sound effects
37-
OPENAI_API_KEY= # OpenAI TTS fallback and GPT Image 2 image generation
38-
XAI_API_KEY= # Grok image generation/editing and Grok video generation
39-
DOUBAO_SPEECH_API_KEY= # Volcengine Doubao Speech TTS (new console API Key)
40-
DOUBAO_SPEECH_VOICE_TYPE= # Default Doubao speaker/voice type, e.g. zh_female_vv_uranus_bigtts
47+
# TTS narration, music generation, sound effects.
48+
ELEVENLABS_API_KEY=
49+
# OpenAI TTS fallback and GPT Image 2 image generation.
50+
OPENAI_API_KEY=
51+
# Grok image generation/editing and Grok video generation.
52+
XAI_API_KEY=
53+
# Volcengine Doubao Speech TTS (new console API Key).
54+
DOUBAO_SPEECH_API_KEY=
55+
# Default Doubao speaker/voice type, e.g. zh_female_vv_uranus_bigtts.
56+
DOUBAO_SPEECH_VOICE_TYPE=
4157
# Piper local voices do not require env vars; install `piper-tts` via pip
4258

4359
# --- DashScope (Alibaba Cloud Bailian) ---
44-
DASHSCOPE_API_KEY= # Qwen image gen (qwen-image-2.0-pro), TTS (qwen3-tts-flash), ASR with word timestamps (qwen3-asr-flash-filetrans)
45-
# Get one at https://dashscope.aliyun.com/
60+
# Qwen image gen (qwen-image-2.0-pro), TTS (qwen3-tts-flash), ASR with word timestamps (qwen3-asr-flash-filetrans).
61+
# Get one at https://dashscope.aliyun.com/
62+
DASHSCOPE_API_KEY=
4663

4764
# --- Music ---
48-
SUNO_API_KEY= # Suno AI music generation (full songs, instrumentals, any genre)
65+
# Suno AI music generation (full songs, instrumentals, any genre).
66+
SUNO_API_KEY=
4967

5068
# --- Video Generation ---
51-
HEYGEN_API_KEY= # HeyGen API (VEO, Sora, Runway, Kling, Seedance via single key)
52-
RUNWAY_API_KEY= # Runway Gen-4 (direct API, alternative to fal.ai routing)
53-
VOLC_ACCESSKEY= # Volcengine Jimeng (即梦 AI) video generation via official API (HMAC-SHA256 V4 signing)
54-
VOLC_SECRETKEY= # Secret Access Key paired with VOLC_ACCESSKEY. Get both at https://console.volcengine.com/iam/keymanage
55-
VIDEO_GEN_LOCAL_ENABLED= # Set to "true" for local video gen (needs GPU + diffusers)
56-
VIDEO_GEN_LOCAL_MODEL= # Local model: wan2.1-1.3b, wan2.1-14b, hunyuan-1.5, ltx2-local, cogvideo-5b
57-
MODAL_LTX2_ENDPOINT_URL= # Modal self-hosted LTX-2 endpoint (optional)
69+
# HeyGen API (VEO, Sora, Runway, Kling, Seedance via single key).
70+
HEYGEN_API_KEY=
71+
# Runway Gen-4 (direct API, alternative to fal.ai routing).
72+
RUNWAY_API_KEY=
73+
# Volcengine Jimeng (即梦 AI) video generation via official API (HMAC-SHA256 V4 signing).
74+
VOLC_ACCESSKEY=
75+
# Secret Access Key paired with VOLC_ACCESSKEY. Get both at https://console.volcengine.com/iam/keymanage
76+
VOLC_SECRETKEY=
77+
# Set to "true" for local video gen (needs GPU + diffusers).
78+
VIDEO_GEN_LOCAL_ENABLED=
79+
# Local model: wan2.1-1.3b, wan2.1-14b, hunyuan-1.5, ltx2-local, cogvideo-5b.
80+
VIDEO_GEN_LOCAL_MODEL=
81+
# Modal self-hosted LTX-2 endpoint (optional).
82+
MODAL_LTX2_ENDPOINT_URL=
5883

5984
# --- Stock Media ---
60-
PEXELS_API_KEY= # Pexels stock footage/images (free)
61-
PIXABAY_API_KEY= # Pixabay stock footage/images (free)
62-
UNSPLASH_ACCESS_KEY= # Unsplash stock images (free developer key)
85+
# Pexels stock footage/images (free).
86+
PEXELS_API_KEY=
87+
# Pixabay stock footage/images (free).
88+
PIXABAY_API_KEY=
89+
# Unsplash stock images (free developer key).
90+
UNSPLASH_ACCESS_KEY=
6391

6492
# --- Analysis ---
65-
HF_TOKEN= # HuggingFace token — enables speaker diarization in transcriber
93+
# HuggingFace token — enables speaker diarization in transcriber.
94+
HF_TOKEN=
6695
# Speech-to-text: optional Azure AI Speech (Fast Transcription). When set, the
6796
# agent prefers azure_stt for cloud STT; the local faster-whisper transcriber
6897
# remains the default offline path.
69-
AZURE_SPEECH_KEY= # Azure AI Speech resource key ('Keys and Endpoint' page)
70-
AZURE_SPEECH_REGION= # Speech resource region, e.g. eastus
98+
# Azure AI Speech resource key ('Keys and Endpoint' page).
99+
AZURE_SPEECH_KEY=
100+
# Speech resource region, e.g. eastus.
101+
AZURE_SPEECH_REGION=
71102
# AZURE_SPEECH_ENDPOINT= # Optional: full custom endpoint URL (overrides region)
72103

73104
# --- Avatar (local installs) ---

AGENT_GUIDE.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -528,9 +528,10 @@ Music is a critical part of any video. **Surface the music situation to the user
528528

529529
Check music availability in this order and present the options:
530530

531-
1. **User music library (`music_library/`):** Check if this folder exists and contains tracks. If so, list available tracks with durations and let the user pick one.
532-
2. **Music generation APIs:** Check which music tools are available via the registry (`registry.get_by_capability("music_generation")`). Report their status honestly — include quota status if known.
533-
3. **Royalty-free sources:** Note if the user can provide their own track (e.g., from YouTube Audio Library, Jamendo, or other free sources). Offer the `music_library/` drop path.
531+
1. **User music library:** Check `registry.get_by_capability("music_library")` and inspect `music_library/`. If tracks exist, list durations and let the user pick one.
532+
2. **Royalty-free search:** Check `registry.get_by_capability("music_search")` for configured search/download tools. Report licensing constraints and whether a key is required.
533+
3. **Music generation APIs:** Check `registry.get_by_capability("music_generation")`. Report status, quota, cost, and quality tradeoffs honestly.
534+
4. **Bring your own:** Note that the user can provide a track (for example from YouTube Audio Library or Jamendo) through the `music_library/` drop path.
534535

535536
**Always present the user with explicit choices:**
536537
- Use a track from their library (which one?)

backlot/server.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import asyncio
1111
import json
1212
import time
13+
from contextlib import asynccontextmanager, suppress
1314
from pathlib import Path
1415
from typing import Optional
1516

@@ -147,18 +148,22 @@ async def _watch_projects() -> None:
147148
hub.publish(pid)
148149

149150

150-
def create_app() -> FastAPI:
151-
app = FastAPI(title="Backlot", docs_url=None, redoc_url=None)
151+
@asynccontextmanager
152+
async def _lifespan(app: FastAPI):
153+
"""Own and cleanly stop the project watcher with FastAPI's lifespan API."""
154+
155+
task = asyncio.create_task(_watch_projects())
156+
app.state.watch_task = task
157+
try:
158+
yield
159+
finally:
160+
task.cancel()
161+
with suppress(asyncio.CancelledError):
162+
await task
152163

153-
@app.on_event("startup")
154-
async def _startup() -> None:
155-
app.state.watch_task = asyncio.create_task(_watch_projects())
156164

157-
@app.on_event("shutdown")
158-
async def _shutdown() -> None:
159-
task = getattr(app.state, "watch_task", None)
160-
if task:
161-
task.cancel()
165+
def create_app() -> FastAPI:
166+
app = FastAPI(title="Backlot", docs_url=None, redoc_url=None, lifespan=_lifespan)
162167

163168
# ---- API ----------------------------------------------------------
164169

backlot/state.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import json
1111
import re
12+
from functools import lru_cache
1213
from pathlib import Path
1314
from typing import Any, Optional
1415

@@ -59,6 +60,7 @@ def _rel(project_dir: Path, path: Path) -> str:
5960
# Pipeline / stages
6061
# ---------------------------------------------------------------------------
6162

63+
@lru_cache(maxsize=32)
6264
def _load_pipeline_meta(pipeline_type: Optional[str]) -> dict[str, Any]:
6365
"""Stage order + gate flags from the manifest; graceful fallback."""
6466
if pipeline_type and pipeline_type != "unknown":

0 commit comments

Comments
 (0)