Add campaign layer, GPU model caching, file browser cleanup
- Campaigns: new table, CRUD API, React context + provider
- Sessions: scoped to campaigns, paths under campaigns/{id}/
- File browser: scoped per campaign, removed copy/paste/autoPlay
- Sidebar: campaign selector dropdown at top
- Transcribe: GPU model cached/released via job counter
- Jobs: status text updates dynamically in real-time
- Auto-redirect: blocked when summarize job is active
This commit is contained in:
@@ -38,8 +38,13 @@ def _row_to_dict(row) -> dict:
|
||||
|
||||
|
||||
@router.get("")
|
||||
def list_sessions():
|
||||
rows = db.get_conn().execute("SELECT * FROM sessions ORDER BY created_at DESC").fetchall()
|
||||
def list_sessions(campaign_id: str = None):
|
||||
if campaign_id:
|
||||
rows = db.get_conn().execute(
|
||||
"SELECT * FROM sessions WHERE campaign_id = ? ORDER BY created_at DESC", (campaign_id,)
|
||||
).fetchall()
|
||||
else:
|
||||
rows = db.get_conn().execute("SELECT * FROM sessions ORDER BY created_at DESC").fetchall()
|
||||
sessions = []
|
||||
for r in rows:
|
||||
s = _row_to_dict(r)
|
||||
@@ -108,24 +113,38 @@ def _run_transcription(session_id: str, video_path: Path, audio_path: Path, tran
|
||||
)
|
||||
|
||||
job_id = db.create_job(session_id, "transcribe")
|
||||
jobs.submit(job_id, run)
|
||||
jobs.submit(job_id, run, requires_gpu=True)
|
||||
return job_id
|
||||
|
||||
|
||||
@router.post("")
|
||||
async def create_session(name: str = Form(...), file: UploadFile = File(None), upload_path: str = Form(None)):
|
||||
async def create_session(
|
||||
name: str = Form(...),
|
||||
file: UploadFile = File(None),
|
||||
upload_path: str = Form(None),
|
||||
campaign_id: str = Form(None),
|
||||
):
|
||||
session_id = db.new_id()
|
||||
|
||||
if campaign_id:
|
||||
upload_dir = config.campaign_dir(campaign_id)
|
||||
audio_dir = config.campaign_audio_dir(campaign_id)
|
||||
transcript_dir = config.campaign_transcript_dir(campaign_id)
|
||||
else:
|
||||
upload_dir = config.UPLOAD_DIR
|
||||
audio_dir = config.AUDIO_DIR
|
||||
transcript_dir = config.TRANSCRIPT_DIR
|
||||
|
||||
if upload_path:
|
||||
src = Path(upload_path)
|
||||
if not src.exists():
|
||||
raise HTTPException(400, f"Uploaded file not found at {upload_path}")
|
||||
safe_filename = os.path.basename(src)
|
||||
video_path = config.UPLOAD_DIR / f"{session_id}_{safe_filename}"
|
||||
video_path = upload_dir / f"{session_id}_{safe_filename}"
|
||||
shutil.move(str(src), str(video_path))
|
||||
elif file:
|
||||
safe_filename = os.path.basename(file.filename or f"{session_id}")
|
||||
video_path = config.UPLOAD_DIR / f"{session_id}_{safe_filename}"
|
||||
video_path = upload_dir / f"{session_id}_{safe_filename}"
|
||||
with open(video_path, "wb") as buffer:
|
||||
shutil.copyfileobj(file.file, buffer)
|
||||
else:
|
||||
@@ -133,13 +152,13 @@ async def create_session(name: str = Form(...), file: UploadFile = File(None), u
|
||||
|
||||
with db.tx() as conn:
|
||||
conn.execute(
|
||||
"INSERT INTO sessions (id, name, original_filename, video_path, status, created_at) "
|
||||
"VALUES (?, ?, ?, ?, 'uploaded', ?)",
|
||||
(session_id, name, safe_filename, str(video_path), db.now()),
|
||||
"INSERT INTO sessions (id, name, original_filename, video_path, campaign_id, status, created_at) "
|
||||
"VALUES (?, ?, ?, ?, ?, 'uploaded', ?)",
|
||||
(session_id, name, safe_filename, str(video_path), campaign_id, db.now()),
|
||||
)
|
||||
|
||||
audio_path = config.AUDIO_DIR / f"{session_id}.wav"
|
||||
transcript_path = config.TRANSCRIPT_DIR / f"{session_id}.json"
|
||||
audio_path = audio_dir / f"{session_id}.wav"
|
||||
transcript_path = transcript_dir / f"{session_id}.json"
|
||||
job_id = _run_transcription(session_id, video_path, audio_path, transcript_path)
|
||||
|
||||
return {"session_id": session_id, "job_id": job_id}
|
||||
@@ -153,8 +172,13 @@ def retry_transcription(session_id: str):
|
||||
raise HTTPException(404, "Session not found")
|
||||
session = _row_to_dict(row)
|
||||
video_path = Path(session["video_path"])
|
||||
audio_path = config.AUDIO_DIR / f"{session_id}.wav"
|
||||
transcript_path = config.TRANSCRIPT_DIR / f"{session_id}.json"
|
||||
campaign_id = session.get("campaign_id")
|
||||
if campaign_id:
|
||||
audio_path = config.campaign_audio_dir(campaign_id) / f"{session_id}.wav"
|
||||
transcript_path = config.campaign_transcript_dir(campaign_id) / f"{session_id}.json"
|
||||
else:
|
||||
audio_path = config.AUDIO_DIR / f"{session_id}.wav"
|
||||
transcript_path = config.TRANSCRIPT_DIR / f"{session_id}.json"
|
||||
job_id = _run_transcription(session_id, video_path, audio_path, transcript_path)
|
||||
return {"job_id": job_id}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user