Spaces:
Running
on
Zero
Running
on
Zero
Add stage information to API status responses
Browse files- Add stage field to JobInfo class to track current processing stage
- Update update_job_status function to include stage parameter
- Add stage tracking at each milestone in process_generation_job
- Include stage in API status response for better client feedback
- Update API documentation with stage values and examples
- Stages: queued, initializing, preprocessing, shape_generation, face_reduction, texture_generation, completed, failed
- API_README.md +12 -1
- gradio_app.py +13 -9
API_README.md
CHANGED
@@ -76,6 +76,7 @@ Check the status of a generation job.
|
|
76 |
{
|
77 |
"status": "completed|processing|queued|failed",
|
78 |
"progress": 0-100,
|
|
|
79 |
"model_urls": {
|
80 |
"glb": "url_to_glb_file"
|
81 |
}
|
@@ -88,6 +89,16 @@ Check the status of a generation job.
|
|
88 |
- `completed`: Job completed successfully
|
89 |
- `failed`: Job failed with an error
|
90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
## Usage Examples
|
92 |
|
93 |
### Python Example
|
@@ -124,7 +135,7 @@ while True:
|
|
124 |
print(f"Generation failed: {data.get('error')}")
|
125 |
break
|
126 |
|
127 |
-
print(f"Progress: {data['progress']}%")
|
128 |
time.sleep(5)
|
129 |
```
|
130 |
|
|
|
76 |
{
|
77 |
"status": "completed|processing|queued|failed",
|
78 |
"progress": 0-100,
|
79 |
+
"stage": "current_processing_stage",
|
80 |
"model_urls": {
|
81 |
"glb": "url_to_glb_file"
|
82 |
}
|
|
|
89 |
- `completed`: Job completed successfully
|
90 |
- `failed`: Job failed with an error
|
91 |
|
92 |
+
**Stage Values:**
|
93 |
+
- `queued`: Job is waiting to be processed
|
94 |
+
- `initializing`: Setting up job and converting images
|
95 |
+
- `preprocessing`: Preparing images and options
|
96 |
+
- `shape_generation`: Generating 3D mesh from images
|
97 |
+
- `face_reduction`: Optimizing mesh geometry
|
98 |
+
- `texture_generation`: Creating textures for the 3D model
|
99 |
+
- `completed`: Job finished successfully
|
100 |
+
- `failed`: Job failed with an error
|
101 |
+
|
102 |
## Usage Examples
|
103 |
|
104 |
### Python Example
|
|
|
135 |
print(f"Generation failed: {data.get('error')}")
|
136 |
break
|
137 |
|
138 |
+
print(f"Progress: {data['progress']}% - Stage: {data['stage']}")
|
139 |
time.sleep(5)
|
140 |
```
|
141 |
|
gradio_app.py
CHANGED
@@ -82,6 +82,7 @@ class JobInfo:
|
|
82 |
self.job_id = job_id
|
83 |
self.status = JobStatus.QUEUED
|
84 |
self.progress = 0
|
|
|
85 |
self.start_time = time.time()
|
86 |
self.end_time = None
|
87 |
self.error_message = None
|
@@ -101,12 +102,14 @@ def create_job() -> str:
|
|
101 |
return job_id
|
102 |
|
103 |
|
104 |
-
def update_job_status(job_id: str, status: JobStatus, progress: int = None, error_message: str = None):
|
105 |
"""Update job status and progress."""
|
106 |
if job_id in jobs:
|
107 |
jobs[job_id].status = status
|
108 |
if progress is not None:
|
109 |
jobs[job_id].progress = progress
|
|
|
|
|
110 |
if error_message is not None:
|
111 |
jobs[job_id].error_message = error_message
|
112 |
if status in [JobStatus.COMPLETED, JobStatus.FAILED]:
|
@@ -132,7 +135,7 @@ def process_generation_job(job_id: str, images: Dict[str, str], options: Dict[st
|
|
132 |
global face_reduce_worker, tex_pipeline, HAS_TEXTUREGEN, SAVE_DIR
|
133 |
|
134 |
try:
|
135 |
-
update_job_status(job_id, JobStatus.PROCESSING, progress=10)
|
136 |
|
137 |
# Convert base64 images to PIL Images
|
138 |
pil_images = {}
|
@@ -144,7 +147,7 @@ def process_generation_job(job_id: str, images: Dict[str, str], options: Dict[st
|
|
144 |
should_remesh = options.get("should_remesh", True)
|
145 |
should_texture = options.get("should_texture", True)
|
146 |
|
147 |
-
update_job_status(job_id, JobStatus.PROCESSING, progress=20)
|
148 |
|
149 |
# Generate 3D mesh
|
150 |
# For non-MV mode, use the front image as the main image, or the first available image
|
@@ -169,7 +172,7 @@ def process_generation_job(job_id: str, images: Dict[str, str], options: Dict[st
|
|
169 |
randomize_seed=False,
|
170 |
)
|
171 |
|
172 |
-
update_job_status(job_id, JobStatus.PROCESSING, progress=50)
|
173 |
|
174 |
# Export white mesh
|
175 |
white_mesh_path = export_mesh(mesh, save_folder, textured=False, type='obj')
|
@@ -178,7 +181,7 @@ def process_generation_job(job_id: str, images: Dict[str, str], options: Dict[st
|
|
178 |
mesh = face_reduce_worker(mesh)
|
179 |
reduced_mesh_path = export_mesh(mesh, save_folder, textured=False, type='obj')
|
180 |
|
181 |
-
update_job_status(job_id, JobStatus.PROCESSING, progress=70)
|
182 |
|
183 |
# Texture generation if enabled
|
184 |
textured_mesh_path = None
|
@@ -215,7 +218,7 @@ def process_generation_job(job_id: str, images: Dict[str, str], options: Dict[st
|
|
215 |
# If texture generation fails, we still have the white mesh as fallback
|
216 |
textured_mesh_path = None
|
217 |
|
218 |
-
update_job_status(job_id, JobStatus.PROCESSING, progress=90)
|
219 |
|
220 |
# Prepare model URLs
|
221 |
model_urls = {}
|
@@ -228,11 +231,11 @@ def process_generation_job(job_id: str, images: Dict[str, str], options: Dict[st
|
|
228 |
|
229 |
# Update job with results
|
230 |
jobs[job_id].model_urls = model_urls
|
231 |
-
update_job_status(job_id, JobStatus.COMPLETED, progress=100)
|
232 |
|
233 |
except Exception as e:
|
234 |
logger.error(f"Job {job_id} failed: {e}")
|
235 |
-
update_job_status(job_id, JobStatus.FAILED, error_message=str(e))
|
236 |
|
237 |
|
238 |
MAX_SEED = 1e7
|
@@ -1245,7 +1248,8 @@ if __name__ == '__main__':
|
|
1245 |
|
1246 |
response = {
|
1247 |
"status": job.status.value,
|
1248 |
-
"progress": job.progress
|
|
|
1249 |
}
|
1250 |
|
1251 |
if job.status == JobStatus.COMPLETED:
|
|
|
82 |
self.job_id = job_id
|
83 |
self.status = JobStatus.QUEUED
|
84 |
self.progress = 0
|
85 |
+
self.stage = "queued"
|
86 |
self.start_time = time.time()
|
87 |
self.end_time = None
|
88 |
self.error_message = None
|
|
|
102 |
return job_id
|
103 |
|
104 |
|
105 |
+
def update_job_status(job_id: str, status: JobStatus, progress: int = None, stage: str = None, error_message: str = None):
|
106 |
"""Update job status and progress."""
|
107 |
if job_id in jobs:
|
108 |
jobs[job_id].status = status
|
109 |
if progress is not None:
|
110 |
jobs[job_id].progress = progress
|
111 |
+
if stage is not None:
|
112 |
+
jobs[job_id].stage = stage
|
113 |
if error_message is not None:
|
114 |
jobs[job_id].error_message = error_message
|
115 |
if status in [JobStatus.COMPLETED, JobStatus.FAILED]:
|
|
|
135 |
global face_reduce_worker, tex_pipeline, HAS_TEXTUREGEN, SAVE_DIR
|
136 |
|
137 |
try:
|
138 |
+
update_job_status(job_id, JobStatus.PROCESSING, progress=10, stage="initializing")
|
139 |
|
140 |
# Convert base64 images to PIL Images
|
141 |
pil_images = {}
|
|
|
147 |
should_remesh = options.get("should_remesh", True)
|
148 |
should_texture = options.get("should_texture", True)
|
149 |
|
150 |
+
update_job_status(job_id, JobStatus.PROCESSING, progress=20, stage="preprocessing")
|
151 |
|
152 |
# Generate 3D mesh
|
153 |
# For non-MV mode, use the front image as the main image, or the first available image
|
|
|
172 |
randomize_seed=False,
|
173 |
)
|
174 |
|
175 |
+
update_job_status(job_id, JobStatus.PROCESSING, progress=50, stage="shape_generation")
|
176 |
|
177 |
# Export white mesh
|
178 |
white_mesh_path = export_mesh(mesh, save_folder, textured=False, type='obj')
|
|
|
181 |
mesh = face_reduce_worker(mesh)
|
182 |
reduced_mesh_path = export_mesh(mesh, save_folder, textured=False, type='obj')
|
183 |
|
184 |
+
update_job_status(job_id, JobStatus.PROCESSING, progress=70, stage="face_reduction")
|
185 |
|
186 |
# Texture generation if enabled
|
187 |
textured_mesh_path = None
|
|
|
218 |
# If texture generation fails, we still have the white mesh as fallback
|
219 |
textured_mesh_path = None
|
220 |
|
221 |
+
update_job_status(job_id, JobStatus.PROCESSING, progress=90, stage="texture_generation")
|
222 |
|
223 |
# Prepare model URLs
|
224 |
model_urls = {}
|
|
|
231 |
|
232 |
# Update job with results
|
233 |
jobs[job_id].model_urls = model_urls
|
234 |
+
update_job_status(job_id, JobStatus.COMPLETED, progress=100, stage="completed")
|
235 |
|
236 |
except Exception as e:
|
237 |
logger.error(f"Job {job_id} failed: {e}")
|
238 |
+
update_job_status(job_id, JobStatus.FAILED, stage="failed", error_message=str(e))
|
239 |
|
240 |
|
241 |
MAX_SEED = 1e7
|
|
|
1248 |
|
1249 |
response = {
|
1250 |
"status": job.status.value,
|
1251 |
+
"progress": job.progress,
|
1252 |
+
"stage": job.stage
|
1253 |
}
|
1254 |
|
1255 |
if job.status == JobStatus.COMPLETED:
|