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_detail.html",
|
||||||
job=job,
|
job=job,
|
||||||
options=_template_options(),
|
options=_template_options(),
|
||||||
|
JobStatus=JobStatus,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -2260,6 +2261,16 @@ def delete_job(job_id: str) -> ResponseReturnValue:
|
|||||||
return redirect(url_for("web.index"))
|
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")
|
@web_bp.post("/jobs/clear-finished")
|
||||||
def clear_finished_jobs() -> ResponseReturnValue:
|
def clear_finished_jobs() -> ResponseReturnValue:
|
||||||
_service().clear_finished()
|
_service().clear_finished()
|
||||||
|
|||||||
@@ -413,6 +413,71 @@ class ConversionService:
|
|||||||
self._persist_state()
|
self._persist_state()
|
||||||
return True
|
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:
|
def delete(self, job_id: str) -> bool:
|
||||||
with self._lock:
|
with self._lock:
|
||||||
job = self._jobs.get(job_id)
|
job = self._jobs.get(job_id)
|
||||||
|
|||||||
@@ -42,9 +42,15 @@
|
|||||||
{% if job.result.audio_path %}
|
{% if job.result.audio_path %}
|
||||||
<p><a class="button" href="{{ url_for('web.download_job', job_id=job.id) }}">Download audio</a></p>
|
<p><a class="button" href="{{ url_for('web.download_job', job_id=job.id) }}">Download audio</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if job.status in [JobStatus.PENDING, JobStatus.RUNNING, JobStatus.PAUSED] %}
|
||||||
<form action="{{ url_for('web.cancel_job', job_id=job.id) }}" method="post">
|
<form action="{{ url_for('web.cancel_job', job_id=job.id) }}" method="post">
|
||||||
<button type="submit" class="button button--ghost">Cancel job</button>
|
<button type="submit" class="button button--ghost">Cancel job</button>
|
||||||
</form>
|
</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>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -69,6 +69,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="job-card__footer">
|
<div class="job-card__footer">
|
||||||
<a class="button button--ghost" href="{{ url_for('web.job_detail', job_id=job.id) }}">Inspect</a>
|
<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 %}
|
{% 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>
|
<a class="button button--ghost" href="{{ url_for('web.download_job', job_id=job.id) }}">Download</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Reference in New Issue
Block a user