Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions core/plugin/builtin_plugins/kira-ai/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,8 @@ async def handle(self, value: str, **kwargs) -> list[BaseMessageElement]:
if not ref_file.is_file():
message_logger.warning(f"Image reference not found: {ref_file}, skipped")
continue
img_extension = ref_file.suffix.lstrip(".")
bs64 = await image_to_base64(str(ref_file))
ref_images.append(Image(image=bs64, name=p, mime=f"image/{img_extension}"))
ref_images.append(Image(image=bs64, name=p))
try:
image_client = self.ctx.provider_mgr.get_default_image()
except ValueError as exc:
Expand Down Expand Up @@ -207,13 +206,12 @@ async def handle(self, value: str, **kwargs) -> list[BaseMessageElement]:
else:
ref_file = get_data_path() / ref_img_path
if ref_file.is_file():
img_extension = ref_file.suffix.lstrip(".")
bs64 = await image_to_base64(str(ref_file))
image_client = self.ctx.provider_mgr.get_default_image()
if not image_client:
message_logger.error("Failed to get image client, please set default image model in Configuration")
return []
img_res = await image_to_image(image_client, value, image=Image(image=bs64, name=ref_img_path, mime=f"image/{img_extension}"))
img_res = await image_to_image(image_client, value, image=Image(image=bs64, name=ref_img_path))
if img_res:
return [img_res]
message_logger.warning("Invalid selfie image result")
Expand Down
2 changes: 2 additions & 0 deletions core/provider/src/openai/model_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ def _image_file_from_data_url(

mime_type, *parameters = header.removeprefix("data:").split(";")
mime_type = mime_type.lower()
if mime_type == "image/jpg":
mime_type = "image/jpeg"
if "base64" not in {parameter.lower() for parameter in parameters}:
raise ValueError("Image Data URL must contain Base64 data")

Expand Down
27 changes: 27 additions & 0 deletions tests/test_openai_image_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,30 @@ async def test_image_edit_requires_input_image():
await client.image_to_image("edit it", [])

edit.assert_not_awaited()


@pytest.mark.asyncio
@pytest.mark.parametrize("mime", ["image/jpg", "image/JPG", "image/jpeg"])
@pytest.mark.parametrize("source", ["data_url", "base64"])
async def test_image_edit_normalizes_jpeg_mime(mime, source):
jpeg_bytes = b"\xff\xd8\xff\xe0jpeg"
encoded = base64.b64encode(jpeg_bytes).decode()
image = (
Image(image=f"data:{mime};base64,{encoded}")
if source == "data_url"
else Image(image=encoded, mime=mime)
)
edit = AsyncMock(
return_value=SimpleNamespace(
data=[SimpleNamespace(url=None, b64_json=PNG_BASE64)]
)
)
client = _configured_client(SimpleNamespace(edit=edit))

result = await client.image_to_image("edit it", image)

assert result.image == PNG_BASE64
edit.assert_awaited_once()
assert edit.await_args.kwargs["image"] == (
"image_0.jpg", jpeg_bytes, "image/jpeg"
)
Loading