mirror of
https://github.com/mudler/LocalAI.git
synced 2026-07-07 23:07:34 -04:00
fix(diffusers,vllm-omni,tinygrad): save generated images as PNG explicitly (#10729)
The image backends call PIL Image.save(request.dst) without a format, so Pillow infers the encoder from the file extension. The core passes an absolute staging path ending in .tmp (e.g. /staging/localai-output-*.tmp), which Pillow can't map to a format, raising "unknown file extension: .tmp" and crashing the worker right after a successful GPU inference. Pass format="PNG" explicitly. LocalAI serves generated images as PNG regardless of the temporary path, so this is always correct and no longer depends on the extension of the destination the core happens to allocate. diffusers is the reported backend (#10727); vllm-omni and tinygrad carry the identical latent crash for any .tmp staging destination. Closes #10727 Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
@@ -864,8 +864,13 @@ class BackendServicer(backend_pb2_grpc.BackendServicer):
|
||||
**kwargs
|
||||
).images[0]
|
||||
|
||||
# save the result
|
||||
image.save(request.dst)
|
||||
# save the result. Save as PNG explicitly instead of letting Pillow
|
||||
# infer the encoder from the extension: the core passes an absolute
|
||||
# staging path ending in .tmp (e.g. /staging/localai-output-*.tmp),
|
||||
# which Pillow can't map to a format and would raise
|
||||
# "unknown file extension: .tmp". LocalAI serves generated images as
|
||||
# PNG regardless of the temp path.
|
||||
image.save(request.dst, format="PNG")
|
||||
|
||||
return backend_pb2.Result(message="Media generated", success=True)
|
||||
|
||||
|
||||
@@ -670,7 +670,10 @@ class BackendServicer(backend_pb2_grpc.BackendServicer):
|
||||
arr = img_tensor.numpy()
|
||||
image = Image.fromarray(arr)
|
||||
dst = request.dst or os.path.join(tempfile.gettempdir(), "tinygrad_image.png")
|
||||
image.save(dst)
|
||||
# Force PNG rather than letting Pillow guess from the extension: the
|
||||
# core passes a staging path ending in .tmp, which Pillow can't map
|
||||
# to a format ("unknown file extension: .tmp").
|
||||
image.save(dst, format="PNG")
|
||||
return backend_pb2.Result(success=True, message=dst)
|
||||
except Exception as exc:
|
||||
import traceback
|
||||
|
||||
@@ -337,9 +337,11 @@ class BackendServicer(backend_pb2_grpc.BackendServicer):
|
||||
if not images or len(images) == 0:
|
||||
return backend_pb2.Result(success=False, message="Empty images list")
|
||||
|
||||
# Save image
|
||||
# Save image. Force PNG rather than letting Pillow guess from the
|
||||
# extension: the core passes a staging path ending in .tmp, which
|
||||
# Pillow can't map to a format ("unknown file extension: .tmp").
|
||||
output_image = images[0]
|
||||
output_image.save(request.dst)
|
||||
output_image.save(request.dst, format="PNG")
|
||||
return backend_pb2.Result(message="Image generated successfully", success=True)
|
||||
|
||||
except Exception as err:
|
||||
|
||||
Reference in New Issue
Block a user