Use patched async-openai library to work around a few upstream issues

Related to:

- CreateImageEditRequest forces an application/octet-stream content type
  for images (https://github.com/64bit/async-openai/issues/364)

- CreateImageEditRequest only deals with a single image
  (https://github.com/64bit/async-openai/issues/363)

This is a continuation of 8f86289373
and fixes the Image Editing feature for OpenAI.
This commit is contained in:
Slavi Pantaleev
2025-05-10 09:59:27 +03:00
parent ac4f2080ce
commit de958208b2
4 changed files with 13 additions and 10 deletions

6
Cargo.lock generated
View File

@@ -228,8 +228,7 @@ dependencies = [
[[package]] [[package]]
name = "async-openai" name = "async-openai"
version = "0.28.1" version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/etkecc/async-openai?branch=async-openai-v0.28.1-patched#856953c2d4485342df625fd0525363362075e8a8"
checksum = "14d76e2f5af19477d6254415acc95ba97c6cc6f3b1e3cb4676b7f0fab8194298"
dependencies = [ dependencies = [
"async-openai-macros", "async-openai-macros",
"backoff", "backoff",
@@ -254,8 +253,7 @@ dependencies = [
[[package]] [[package]]
name = "async-openai-macros" name = "async-openai-macros"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/etkecc/async-openai?branch=async-openai-v0.28.1-patched#856953c2d4485342df625fd0525363362075e8a8"
checksum = "0289cba6d5143bfe8251d57b4a8cac036adf158525a76533a7082ba65ec76398"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@@ -17,7 +17,7 @@ path = "src/lib.rs"
[dependencies] [dependencies]
anthropic = "=0.0.8" anthropic = "=0.0.8"
anyhow = "1.0.*" anyhow = "1.0.*"
async-openai = "0.28.*" async-openai = { git = "https://github.com/etkecc/async-openai", branch = "async-openai-v0.28.1-patched" }
base64 = "0.22.*" base64 = "0.22.*"
chrono = { version = "0.4.*", default-features = false, features = ["std", "now"] } chrono = { version = "0.4.*", default-features = false, features = ["std", "now"] }
# We'd rather not depend on this, but we cannot use the ruma-events EventContent macro without it. # We'd rather not depend on this, but we cannot use the ruma-events EventContent macro without it.

View File

@@ -58,6 +58,7 @@ impl From<ImageSource> for async_openai::types::ImageInput {
async_openai::types::ImageInput::from_vec_u8( async_openai::types::ImageInput::from_vec_u8(
value.filename, value.filename,
value.bytes, value.bytes,
value.mime_type.to_string(),
) )
} }
} }

View File

@@ -6,7 +6,7 @@ use async_openai::{
types::{ types::{
ChatCompletionRequestMessage, CreateChatCompletionRequestArgs, CreateImageRequestArgs, ChatCompletionRequestMessage, CreateChatCompletionRequestArgs, CreateImageRequestArgs,
CreateSpeechRequestArgs, CreateTranscriptionRequestArgs, CreateImageEditRequestArgs, CreateSpeechRequestArgs, CreateTranscriptionRequestArgs, CreateImageEditRequestArgs,
ImageInput, ImageModel, DallE2ImageSize, ImageResponseFormat, Image, ImageModel, DallE2ImageSize, ImageResponseFormat, Image,
}, },
}; };
@@ -209,6 +209,7 @@ impl ControllerTrait for Controller {
.file(async_openai::types::AudioInput::from_vec_u8( .file(async_openai::types::AudioInput::from_vec_u8(
filename, filename,
media, media,
mime_type.to_string(),
)) ))
.language(language.clone()) .language(language.clone())
.build()?; .build()?;
@@ -368,11 +369,14 @@ impl ControllerTrait for Controller {
)); ));
}; };
let Some(first_image) = images.into_iter().next() else { if images.is_empty() {
return Err(anyhow::anyhow!("No image sources provided")); return Err(anyhow::anyhow!("No image sources provided"));
}; }
let image_input: ImageInput = first_image.into(); let mut image_inputs = Vec::new();
for image in images {
image_inputs.push(image.into());
}
let dalle2_size = match image_generation_config.size { let dalle2_size = match image_generation_config.size {
async_openai::types::ImageSize::S256x256 => Some(DallE2ImageSize::S256x256), async_openai::types::ImageSize::S256x256 => Some(DallE2ImageSize::S256x256),
@@ -397,7 +401,7 @@ impl ControllerTrait for Controller {
let mut request_builder = CreateImageEditRequestArgs::default(); let mut request_builder = CreateImageEditRequestArgs::default();
request_builder request_builder
.image(image_input) .image(image_inputs)
.prompt(prompt.to_owned()) .prompt(prompt.to_owned())
.model(model); .model(model);