mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
feat: Add estimated time remaining display and duration formatting to job progress cards
This commit is contained in:
@@ -35,6 +35,21 @@ def datetimeformat(value: float, fmt: str = "%Y-%m-%d %H:%M:%S") -> str:
|
||||
from datetime import datetime
|
||||
return datetime.fromtimestamp(value).strftime(fmt)
|
||||
|
||||
@main_bp.app_template_filter("durationformat")
|
||||
def durationformat(value: Optional[float]) -> str:
|
||||
if value is None:
|
||||
return ""
|
||||
seconds = int(value)
|
||||
if seconds < 60:
|
||||
return f"{seconds}s"
|
||||
minutes = seconds // 60
|
||||
seconds = seconds % 60
|
||||
if minutes < 60:
|
||||
return f"{minutes}m {seconds}s"
|
||||
hours = minutes // 60
|
||||
minutes = minutes % 60
|
||||
return f"{hours}h {minutes}m"
|
||||
|
||||
@main_bp.route("/")
|
||||
def index():
|
||||
pending_id = request.args.get("pending_id")
|
||||
|
||||
+20
-9
@@ -148,13 +148,24 @@ class Job:
|
||||
generate_epub3: bool = False
|
||||
speaker_analysis: Dict[str, Any] = field(default_factory=dict)
|
||||
speaker_analysis_threshold: int = 3
|
||||
analysis_requested: bool = False
|
||||
speaker_voice_languages: List[str] = field(default_factory=list)
|
||||
applied_speaker_config: Optional[str] = None
|
||||
entity_summary: Dict[str, Any] = field(default_factory=dict)
|
||||
manual_overrides: List[Dict[str, Any]] = field(default_factory=list)
|
||||
pronunciation_overrides: List[Dict[str, Any]] = field(default_factory=list)
|
||||
normalization_overrides: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
@property
|
||||
def estimated_time_remaining(self) -> Optional[float]:
|
||||
"""
|
||||
Returns the estimated seconds remaining based on current progress and elapsed time.
|
||||
Returns None if the job hasn't started, is finished, or progress is 0.
|
||||
"""
|
||||
if self.status != JobStatus.RUNNING or not self.started_at or self.progress <= 0:
|
||||
return None
|
||||
|
||||
elapsed = time.time() - self.started_at
|
||||
if elapsed <= 0:
|
||||
return None
|
||||
|
||||
# Estimate total time based on current progress
|
||||
total_estimated = elapsed / self.progress
|
||||
remaining = total_estimated - elapsed
|
||||
return max(0.0, remaining)
|
||||
|
||||
def add_log(self, message: str, level: str = "info") -> None:
|
||||
entry = JobLog(timestamp=time.time(), message=message, level=level)
|
||||
@@ -1589,8 +1600,8 @@ def default_storage_root() -> Path:
|
||||
def build_service(
|
||||
runner: Callable[[Job], None],
|
||||
*,
|
||||
output_root: Optional[Path] = None,
|
||||
uploads_root: Optional[Path] = None,
|
||||
output_root: Optional<Path] = None,
|
||||
uploads_root: Optional<Path] = None,
|
||||
) -> ConversionService:
|
||||
output_root = output_root or default_storage_root()
|
||||
service = ConversionService(
|
||||
|
||||
@@ -1910,6 +1910,17 @@ button.step-indicator__item:focus-visible {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.job-card__progress-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.job-card__eta {
|
||||
color: var(--muted);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.job-card__footer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@@ -26,7 +26,12 @@
|
||||
<div class="progress-bar" style="--progress: {{ progress_value }}%">
|
||||
<div class="progress-bar__fill"></div>
|
||||
</div>
|
||||
<small>{{ progress_value }}% · {{ job.processed_characters }} / {{ job.total_characters or '—' }}</small>
|
||||
<div class="job-card__progress-meta">
|
||||
<small>{{ progress_value }}% · {{ job.processed_characters }} / {{ job.total_characters or '—' }}</small>
|
||||
{% if job.estimated_time_remaining %}
|
||||
<small class="job-card__eta">~{{ job.estimated_time_remaining | durationformat }} remaining</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="job-card__footer">
|
||||
<a class="button button--ghost" href="{{ url_for('jobs.job_detail', job_id=job.id) }}">Details</a>
|
||||
|
||||
Reference in New Issue
Block a user