KaiWu commited on
Commit
bfe7d22
·
1 Parent(s): 2aa101f

Add GLB preview extraction for Lux3D zip outputs

Browse files
agent_core/outputs.py CHANGED
@@ -120,6 +120,7 @@ def write_lux3d_manifest(
120
  image_path: Path,
121
  requested_output_path: str,
122
  output_path: Path | None,
 
123
  busid: str | int | None,
124
  status: int | None,
125
  result_url: str | None,
@@ -136,6 +137,7 @@ def write_lux3d_manifest(
136
  "image_path": workspace_relative(image_path),
137
  "requested_output_path": requested_output_path,
138
  "output_path": workspace_relative(output_path) if output_path else None,
 
139
  "busid": busid,
140
  "status": status,
141
  "result_url": result_url,
 
120
  image_path: Path,
121
  requested_output_path: str,
122
  output_path: Path | None,
123
+ preview_path: Path | None,
124
  busid: str | int | None,
125
  status: int | None,
126
  result_url: str | None,
 
137
  "image_path": workspace_relative(image_path),
138
  "requested_output_path": requested_output_path,
139
  "output_path": workspace_relative(output_path) if output_path else None,
140
+ "preview_path": workspace_relative(preview_path) if preview_path else None,
141
  "busid": busid,
142
  "status": status,
143
  "result_url": result_url,
agent_core/tools/lux3d_tool.py CHANGED
@@ -8,6 +8,7 @@ import time
8
  import urllib.error
9
  import urllib.parse
10
  import urllib.request
 
11
  from pathlib import Path
12
 
13
  from agent_core.config import (
@@ -154,6 +155,45 @@ def download_lux3d_result(result_url: str, output_path: Path) -> None:
154
  output_path.write_bytes(data)
155
 
156
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  def run_generate_3d_model(
158
  image_path: str,
159
  output_path: str | None = None,
@@ -165,6 +205,7 @@ def run_generate_3d_model(
165
  status = None
166
  result_url = None
167
  output = None
 
168
  poll_count = 0
169
  run_dir = None
170
  run_id = None
@@ -213,6 +254,7 @@ def run_generate_3d_model(
213
  output_name = requested_output_name or infer_lux3d_output_name(result_url)
214
  output = run_dir / output_name
215
  download_lux3d_result(result_url, output)
 
216
  manifest_path = write_lux3d_manifest(
217
  run_dir=run_dir,
218
  run_id=run_id,
@@ -220,6 +262,7 @@ def run_generate_3d_model(
220
  image_path=image,
221
  requested_output_path=requested_output_path,
222
  output_path=output,
 
223
  busid=busid,
224
  status=status,
225
  result_url=result_url,
@@ -232,6 +275,7 @@ def run_generate_3d_model(
232
  "run_id": run_id,
233
  "run_dir": workspace_relative(run_dir),
234
  "output_path": workspace_relative(output),
 
235
  "manifest_path": workspace_relative(manifest_path),
236
  "latest_path": workspace_relative(output_root / "latest"),
237
  "busid": busid,
@@ -257,6 +301,7 @@ def run_generate_3d_model(
257
  image_path=image,
258
  requested_output_path=requested_output_path,
259
  output_path=output,
 
260
  busid=busid,
261
  status=status,
262
  result_url=result_url,
 
8
  import urllib.error
9
  import urllib.parse
10
  import urllib.request
11
+ import zipfile
12
  from pathlib import Path
13
 
14
  from agent_core.config import (
 
155
  output_path.write_bytes(data)
156
 
157
 
158
+ def safe_zip_target(extract_dir: Path, member_name: str) -> Path:
159
+ target = (extract_dir / member_name).resolve()
160
+ if not target.is_relative_to(extract_dir.resolve()):
161
+ raise RuntimeError(f"Unsafe path in Lux3D zip result: {member_name}")
162
+ return target
163
+
164
+
165
+ def extract_lux3d_glb_preview(zip_path: Path, run_dir: Path) -> Path:
166
+ extract_dir = run_dir / "extracted"
167
+ try:
168
+ with zipfile.ZipFile(zip_path) as archive:
169
+ glb_members = sorted(
170
+ (
171
+ item
172
+ for item in archive.infolist()
173
+ if not item.is_dir() and Path(item.filename).suffix.lower() == ".glb"
174
+ ),
175
+ key=lambda item: item.filename,
176
+ )
177
+ if not glb_members:
178
+ raise RuntimeError(f"Lux3D zip result did not include a .glb file: {workspace_relative(zip_path)}")
179
+
180
+ member = glb_members[0]
181
+ preview_path = safe_zip_target(extract_dir, member.filename)
182
+ preview_path.parent.mkdir(parents=True, exist_ok=True)
183
+ preview_path.write_bytes(archive.read(member))
184
+ return preview_path
185
+ except zipfile.BadZipFile as exc:
186
+ raise RuntimeError(f"Lux3D result is not a valid zip file: {workspace_relative(zip_path)}") from exc
187
+
188
+
189
+ def resolve_lux3d_preview_path(output_path: Path, run_dir: Path) -> Path | None:
190
+ if zipfile.is_zipfile(output_path):
191
+ return extract_lux3d_glb_preview(output_path, run_dir)
192
+ if output_path.suffix.lower() == ".glb":
193
+ return output_path
194
+ return None
195
+
196
+
197
  def run_generate_3d_model(
198
  image_path: str,
199
  output_path: str | None = None,
 
205
  status = None
206
  result_url = None
207
  output = None
208
+ preview = None
209
  poll_count = 0
210
  run_dir = None
211
  run_id = None
 
254
  output_name = requested_output_name or infer_lux3d_output_name(result_url)
255
  output = run_dir / output_name
256
  download_lux3d_result(result_url, output)
257
+ preview = resolve_lux3d_preview_path(output, run_dir)
258
  manifest_path = write_lux3d_manifest(
259
  run_dir=run_dir,
260
  run_id=run_id,
 
262
  image_path=image,
263
  requested_output_path=requested_output_path,
264
  output_path=output,
265
+ preview_path=preview,
266
  busid=busid,
267
  status=status,
268
  result_url=result_url,
 
275
  "run_id": run_id,
276
  "run_dir": workspace_relative(run_dir),
277
  "output_path": workspace_relative(output),
278
+ "preview_path": workspace_relative(preview) if preview else None,
279
  "manifest_path": workspace_relative(manifest_path),
280
  "latest_path": workspace_relative(output_root / "latest"),
281
  "busid": busid,
 
301
  image_path=image,
302
  requested_output_path=requested_output_path,
303
  output_path=output,
304
+ preview_path=preview,
305
  busid=busid,
306
  status=status,
307
  result_url=result_url,