mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-19 23:00:45 -07:00
feat(history): add "Clear failed" button to wipe failed generations (#412)
When the model wasn't loaded, the app was closed mid-run, or a generation otherwise errored out, the resulting "Failed" rows accumulate in history and there was no way to remove them in bulk — individual delete was the only option. Adds a header row above the history list (only rendered when at least one failed generation is present) with a "Clear failed" button that opens a confirmation dialog, then calls a new DELETE /history/failed endpoint which sweeps all status='failed' rows (plus their version files / audio files on disk). Closes jamiepine/voicebox#410 Co-authored-by: Claude Opus 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
73170d0e92
commit
0aa19a9994
@@ -264,6 +264,43 @@ async def delete_generation(
|
||||
return True
|
||||
|
||||
|
||||
async def delete_failed_generations(db: Session) -> int:
|
||||
"""
|
||||
Delete every generation whose status is 'failed'.
|
||||
|
||||
Used by the "Clear failed" action in the UI so users can tidy up
|
||||
history after the model wasn't loaded, the app was closed mid-run,
|
||||
or a generation otherwise errored out (see issue #410).
|
||||
|
||||
Returns:
|
||||
Number of generations deleted.
|
||||
"""
|
||||
from . import versions as versions_mod
|
||||
|
||||
failed = db.query(DBGeneration).filter(DBGeneration.status == "failed").all()
|
||||
count = 0
|
||||
for generation in failed:
|
||||
# Clean up version files/rows first.
|
||||
versions_mod.delete_versions_for_generation(generation.id, db)
|
||||
|
||||
# Remove the main audio file if it somehow made it to disk.
|
||||
if generation.audio_path:
|
||||
audio_path = config.resolve_storage_path(generation.audio_path)
|
||||
if audio_path is not None and audio_path.exists():
|
||||
try:
|
||||
audio_path.unlink()
|
||||
except OSError:
|
||||
# Best-effort cleanup — don't abort the whole sweep
|
||||
# if a single file can't be removed.
|
||||
pass
|
||||
|
||||
db.delete(generation)
|
||||
count += 1
|
||||
|
||||
db.commit()
|
||||
return count
|
||||
|
||||
|
||||
async def delete_generations_by_profile(
|
||||
profile_id: str,
|
||||
db: Session,
|
||||
|
||||
Reference in New Issue
Block a user