diff --git a/portal/main.py b/portal/main.py index b6cecef..d953f1d 100644 --- a/portal/main.py +++ b/portal/main.py @@ -38,7 +38,7 @@ from .database import ( get_user_by_username, init_db, ) -from .tasks import ensure_user_bucket, transcribe_audio, transcribe_sheetmusic +from .tasks import celery_app, ensure_user_bucket, transcribe_audio, transcribe_sheetmusic from .s3 import list_prefix, list_recent, s3_bucket_name, s3_client from .tools import section_color, section_label, tools_for_user @@ -559,11 +559,12 @@ async def transcriber_transcribe( if user is None: return RedirectResponse("/login", status_code=303) bucket = s3_bucket_name(user.username) + task_id = "" try: - transcribe_audio.delay(bucket, key, user.username) + task_id = transcribe_audio.delay(bucket, key, user.username).id except Exception: logger.warning("could not enqueue transcription (broker down?)", exc_info=True) - return RedirectResponse("/transcriber?status=started", status_code=303) + return RedirectResponse(f"/transcriber?status=started&task={task_id}", status_code=303) @app.post("/transcriber/upload") @@ -582,11 +583,46 @@ async def transcriber_upload( await run_in_threadpool( lambda: s3_client().put_object(Bucket=bucket, Key=key, Body=content) ) + task_id = "" try: - transcribe_audio.delay(bucket, key, user.username) + task_id = transcribe_audio.delay(bucket, key, user.username).id except Exception: logger.warning("could not enqueue transcription after upload", exc_info=True) - return RedirectResponse("/transcriber?status=started", status_code=303) + return RedirectResponse(f"/transcriber?status=started&task={task_id}", status_code=303) + + +@app.get("/api/transcriber/status") +async def transcriber_status(task: str): + from celery.result import AsyncResult + r = AsyncResult(task, app=celery_app) + return {"state": r.state, "result": r.result if r.state == "SUCCESS" else None} + + +@app.post("/transcriber/delete") +async def transcriber_delete(request: Request, key: Annotated[str, Form()]) -> HTMLResponse: + user = await _current_user(request) + if user is None: + return RedirectResponse("/login", status_code=303) + bucket = s3_bucket_name(user.username) + try: + await run_in_threadpool(lambda: s3_client().delete_object(Bucket=bucket, Key=key)) + except Exception: + logger.warning("transcriber delete failed", exc_info=True) + return RedirectResponse("/transcriber", status_code=303) + + +@app.post("/files/delete") +async def files_delete(request: Request, name: Annotated[str, Form()]) -> HTMLResponse: + user = await _current_user(request) + if user is None: + return RedirectResponse("/login", status_code=303) + p = _resolve_shared(user.username, name) + if p is not None: + try: + p.unlink() + except Exception: + logger.warning("files delete failed", exc_info=True) + return RedirectResponse("/files", status_code=303) @app.get("/transcriber/download") @@ -618,11 +654,12 @@ async def transcriber_sheetmusic( if user is None: return RedirectResponse("/login", status_code=303) bucket = s3_bucket_name(user.username) + task_id = "" try: - transcribe_sheetmusic.delay(bucket, key, user.username) + task_id = transcribe_sheetmusic.delay(bucket, key, user.username).id except Exception: logger.warning("could not enqueue sheet-music transcription", exc_info=True) - return RedirectResponse("/transcriber?status=started-mus", status_code=303) + return RedirectResponse(f"/transcriber?status=started-mus&task={task_id}", status_code=303) @app.get("/api/status") diff --git a/portal/templates/files.html b/portal/templates/files.html index 936d4de..8b5bdcd 100644 --- a/portal/templates/files.html +++ b/portal/templates/files.html @@ -38,6 +38,10 @@ 👁 ↓ +
diff --git a/portal/templates/transcriber.html b/portal/templates/transcriber.html index 69e01cd..86ff3fc 100644 --- a/portal/templates/transcriber.html +++ b/portal/templates/transcriber.html @@ -2,13 +2,16 @@ {% block title %}Audio Transcriber — {{ settings.APP_NAME }}{% endblock %} {% block content %}- Turn an audio file into MIDI (via Spotify Basic Pitch). Upload or pick a file from - your bucket, then the transcription worker produces a MIDI you can download. + Turn an audio or video file into MIDI (via Spotify Basic Pitch). Upload or pick a file from + your bucket, then the worker produces a MIDI you can download. Video files get their audio extracted automatically.
- Saved to {{ bucket }} under audio/…. MIDI = Basic Pitch (fast); Sheet music = MuScriptor (MIDI+MusicXML+PDF, slow, needs HF token).
+ Saved to {{ bucket }} under audio/…. MIDI = Basic Pitch (fast); Sheet music = MuScriptor (MIDI+MusicXML+PDF, slower).