62 lines
2.6 KiB
Python
62 lines
2.6 KiB
Python
import uuid
|
||
from django.db import models
|
||
from django.conf import settings
|
||
|
||
|
||
class SplatJob(models.Model):
|
||
class Status(models.TextChoices):
|
||
QUEUED = "queued", "Queued"
|
||
RUNNING = "running", "Running"
|
||
SUCCEEDED = "succeeded", "Succeeded"
|
||
FAILED = "failed", "Failed"
|
||
|
||
class Step(models.TextChoices):
|
||
EXTRACTING_FRAMES = "extracting_frames", "Extracting frames"
|
||
RUNNING_COLMAP = "running_colmap", "Running COLMAP"
|
||
TRAINING_GSPLAT = "training_gsplat", "Training gsplat"
|
||
EXPORTING = "exporting", "Exporting .ksplat"
|
||
QUALITY_CHECK = "quality_check", "Quality check"
|
||
|
||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||
splat = models.OneToOneField("splats.Splat", on_delete=models.CASCADE, related_name="job")
|
||
submitted_by = models.ForeignKey(
|
||
settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, related_name="splat_jobs"
|
||
)
|
||
|
||
status = models.CharField(max_length=20, choices=Status.choices, default=Status.QUEUED, db_index=True)
|
||
current_step = models.CharField(max_length=30, choices=Step.choices, blank=True, default="")
|
||
|
||
# 0–100 overall progress, updated by the RunPod webhook on each step transition
|
||
progress = models.PositiveSmallIntegerField(default=0)
|
||
|
||
# RunPod serverless job ID — used to poll status and match incoming webhooks
|
||
runpod_job_id = models.CharField(max_length=255, blank=True, default="", db_index=True)
|
||
celery_task_id = models.CharField(max_length=255, blank=True, default="")
|
||
|
||
# Number of times this job has been requeued after a transient failure
|
||
retry_count = models.PositiveSmallIntegerField(default=0)
|
||
|
||
error_message = models.TextField(blank=True, default="")
|
||
|
||
# Structured log output from each pipeline step, keyed by Step value.
|
||
# Populated by the RunPod webhook on each step completion.
|
||
# Example: {"extracting_frames": {"frames": 1350, "duration_s": 8.2}, ...}
|
||
pipeline_logs = models.JSONField(default=dict, blank=True)
|
||
|
||
# COLMAP sparse reconstruction quality signal.
|
||
# Low point count (< ~500) usually means the splat will be poor quality.
|
||
colmap_points = models.PositiveIntegerField(null=True, blank=True)
|
||
|
||
queued_at = models.DateTimeField(auto_now_add=True)
|
||
started_at = models.DateTimeField(null=True, blank=True)
|
||
finished_at = models.DateTimeField(null=True, blank=True)
|
||
|
||
def __str__(self):
|
||
return f"Job {self.id} for splat {self.splat_id} [{self.status}]"
|
||
|
||
class Meta:
|
||
db_table = "splat_jobs"
|
||
indexes = [
|
||
models.Index(fields=["status", "queued_at"]),
|
||
]
|