mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
feat: Add retry functionality for jobs and update UI to support job retries
This commit is contained in:
@@ -2225,6 +2225,7 @@ def job_detail(job_id: str) -> str:
|
||||
"job_detail.html",
|
||||
job=job,
|
||||
options=_template_options(),
|
||||
JobStatus=JobStatus,
|
||||
)
|
||||
|
||||
|
||||
@@ -2260,6 +2261,16 @@ def delete_job(job_id: str) -> ResponseReturnValue:
|
||||
return redirect(url_for("web.index"))
|
||||
|
||||
|
||||
@web_bp.post("/jobs/<job_id>/retry")
|
||||
def retry_job(job_id: str) -> ResponseReturnValue:
|
||||
new_job = _service().retry(job_id)
|
||||
if request.headers.get("HX-Request"):
|
||||
return _render_jobs_panel()
|
||||
if new_job:
|
||||
return redirect(url_for("web.job_detail", job_id=new_job.id))
|
||||
return redirect(url_for("web.job_detail", job_id=job_id))
|
||||
|
||||
|
||||
@web_bp.post("/jobs/clear-finished")
|
||||
def clear_finished_jobs() -> ResponseReturnValue:
|
||||
_service().clear_finished()
|
||||
|
||||
@@ -413,6 +413,71 @@ class ConversionService:
|
||||
self._persist_state()
|
||||
return True
|
||||
|
||||
def retry(self, job_id: str) -> Optional[Job]:
|
||||
with self._lock:
|
||||
job = self._jobs.get(job_id)
|
||||
if job is None:
|
||||
return None
|
||||
if job.status not in {JobStatus.COMPLETED, JobStatus.FAILED, JobStatus.CANCELLED}:
|
||||
job.add_log(
|
||||
"Retry requested while job still active; ignoring.",
|
||||
level="warning",
|
||||
)
|
||||
return None
|
||||
|
||||
stored_path = job.stored_path
|
||||
if not isinstance(stored_path, Path):
|
||||
stored_path = Path(str(stored_path))
|
||||
|
||||
if not stored_path.exists():
|
||||
job.add_log(
|
||||
f"Retry requested but source file is missing: {stored_path}",
|
||||
level="error",
|
||||
)
|
||||
return None
|
||||
|
||||
new_job = self.enqueue(
|
||||
original_filename=job.original_filename,
|
||||
stored_path=stored_path,
|
||||
language=job.language,
|
||||
voice=job.voice,
|
||||
speed=job.speed,
|
||||
use_gpu=job.use_gpu,
|
||||
subtitle_mode=job.subtitle_mode,
|
||||
output_format=job.output_format,
|
||||
save_mode=job.save_mode,
|
||||
output_folder=job.output_folder,
|
||||
replace_single_newlines=job.replace_single_newlines,
|
||||
subtitle_format=job.subtitle_format,
|
||||
total_characters=job.total_characters,
|
||||
chapters=job.chapters,
|
||||
save_chapters_separately=job.save_chapters_separately,
|
||||
merge_chapters_at_end=job.merge_chapters_at_end,
|
||||
separate_chapters_format=job.separate_chapters_format,
|
||||
silence_between_chapters=job.silence_between_chapters,
|
||||
save_as_project=job.save_as_project,
|
||||
voice_profile=job.voice_profile,
|
||||
max_subtitle_words=job.max_subtitle_words,
|
||||
metadata_tags=job.metadata_tags,
|
||||
cover_image_path=job.cover_image_path,
|
||||
cover_image_mime=job.cover_image_mime,
|
||||
chapter_intro_delay=job.chapter_intro_delay,
|
||||
chunk_level=job.chunk_level,
|
||||
chunks=job.chunks,
|
||||
speakers=job.speakers,
|
||||
speaker_mode=job.speaker_mode,
|
||||
generate_epub3=job.generate_epub3,
|
||||
speaker_analysis=job.speaker_analysis,
|
||||
speaker_analysis_threshold=job.speaker_analysis_threshold,
|
||||
analysis_requested=job.analysis_requested,
|
||||
)
|
||||
|
||||
new_job.speaker_voice_languages = list(job.speaker_voice_languages)
|
||||
new_job.applied_speaker_config = job.applied_speaker_config
|
||||
new_job.add_log(f"Retry created from job {job.id}", level="info")
|
||||
job.add_log(f"Retry scheduled as job {new_job.id}", level="info")
|
||||
return new_job
|
||||
|
||||
def delete(self, job_id: str) -> bool:
|
||||
with self._lock:
|
||||
job = self._jobs.get(job_id)
|
||||
|
||||
@@ -42,9 +42,15 @@
|
||||
{% if job.result.audio_path %}
|
||||
<p><a class="button" href="{{ url_for('web.download_job', job_id=job.id) }}">Download audio</a></p>
|
||||
{% endif %}
|
||||
{% if job.status in [JobStatus.PENDING, JobStatus.RUNNING, JobStatus.PAUSED] %}
|
||||
<form action="{{ url_for('web.cancel_job', job_id=job.id) }}" method="post">
|
||||
<button type="submit" class="button button--ghost">Cancel job</button>
|
||||
</form>
|
||||
{% elif job.status in [JobStatus.COMPLETED, JobStatus.FAILED, JobStatus.CANCELLED] %}
|
||||
<form action="{{ url_for('web.retry_job', job_id=job.id) }}" method="post">
|
||||
<button type="submit" class="button">Retry job</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -69,6 +69,9 @@
|
||||
</div>
|
||||
<div class="job-card__footer">
|
||||
<a class="button button--ghost" href="{{ url_for('web.job_detail', job_id=job.id) }}">Inspect</a>
|
||||
{% if job.status in [JobStatus.COMPLETED, JobStatus.FAILED, JobStatus.CANCELLED] %}
|
||||
<button type="button" class="button button--ghost" hx-post="{{ url_for('web.retry_job', job_id=job.id) }}" hx-target="#jobs-panel" hx-swap="innerHTML">Retry</button>
|
||||
{% endif %}
|
||||
{% if job.status == JobStatus.COMPLETED and job.result.audio_path %}
|
||||
<a class="button button--ghost" href="{{ url_for('web.download_job', job_id=job.id) }}">Download</a>
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user