fix: send VectorEngine edit images as file parts
This commit is contained in:
@@ -234,9 +234,11 @@ fn send_multipart_edit_request_with_curl_blocking(
|
||||
|
||||
for reference_image in reference_images {
|
||||
form.part("image")
|
||||
.contents(reference_image.bytes.as_slice())
|
||||
.buffer(
|
||||
reference_image.file_name.as_str(),
|
||||
reference_image.bytes.clone(),
|
||||
)
|
||||
.content_type(reference_image.mime_type.as_str())
|
||||
.filename(reference_image.file_name.as_str())
|
||||
.add()?;
|
||||
}
|
||||
|
||||
@@ -275,15 +277,15 @@ fn perform_curl_request(mut easy: Easy) -> Result<VectorEngineCurlResponse, curl
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::vector_engine::types::ReferenceImage;
|
||||
use std::time::Duration;
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
net::TcpListener,
|
||||
sync::oneshot,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
async fn vector_engine_curl_transport_posts_json_request() {
|
||||
let (base_url, server) = start_single_response_server().await;
|
||||
let (base_url, server, request_rx) = start_single_response_server().await;
|
||||
let response = send_vector_engine_json_request_with_curl(
|
||||
format!("{base_url}/v1/images/generations").as_str(),
|
||||
"test-key",
|
||||
@@ -295,12 +297,17 @@ mod tests {
|
||||
|
||||
assert_eq!(response.status, 200);
|
||||
assert_eq!(response.body, "{\"data\":[]}");
|
||||
let request = request_rx
|
||||
.await
|
||||
.expect("mock server should capture request");
|
||||
let request_text = String::from_utf8_lossy(request.as_slice());
|
||||
assert!(request_text.contains("Content-Type: application/json"));
|
||||
server.abort();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn vector_engine_curl_transport_posts_multipart_request() {
|
||||
let (base_url, server) = start_single_response_server().await;
|
||||
let (base_url, server, request_rx) = start_single_response_server().await;
|
||||
let response = send_vector_engine_multipart_edit_request_with_curl(
|
||||
format!("{base_url}/v1/images/edits").as_str(),
|
||||
"test-key",
|
||||
@@ -320,16 +327,28 @@ mod tests {
|
||||
|
||||
assert_eq!(response.status, 200);
|
||||
assert_eq!(response.body, "{\"data\":[]}");
|
||||
let request = request_rx
|
||||
.await
|
||||
.expect("mock server should capture request");
|
||||
let request_text = String::from_utf8_lossy(request.as_slice());
|
||||
assert!(request_text.contains("name=\"image\"; filename=\"reference.png\""));
|
||||
assert!(request_text.contains("Content-Type: image/png"));
|
||||
assert!(request_text.contains("reference"));
|
||||
server.abort();
|
||||
}
|
||||
|
||||
async fn start_single_response_server() -> (String, tokio::task::JoinHandle<()>) {
|
||||
async fn start_single_response_server() -> (
|
||||
String,
|
||||
tokio::task::JoinHandle<()>,
|
||||
oneshot::Receiver<Vec<u8>>,
|
||||
) {
|
||||
let listener = TcpListener::bind("127.0.0.1:0")
|
||||
.await
|
||||
.expect("mock server should bind");
|
||||
let addr = listener
|
||||
.local_addr()
|
||||
.expect("mock server addr should be readable");
|
||||
let (request_tx, request_rx) = oneshot::channel();
|
||||
let server = tokio::spawn(async move {
|
||||
let Ok((mut stream, _)) = listener.accept().await else {
|
||||
return;
|
||||
@@ -348,7 +367,31 @@ mod tests {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
let header_end = request
|
||||
.windows(4)
|
||||
.position(|window| window == b"\r\n\r\n")
|
||||
.map(|index| index + 4)
|
||||
.unwrap_or(request.len());
|
||||
let headers = String::from_utf8_lossy(&request[..header_end]);
|
||||
let content_length = headers
|
||||
.lines()
|
||||
.find_map(|line| {
|
||||
line.strip_prefix("Content-Length:")
|
||||
.or_else(|| line.strip_prefix("content-length:"))
|
||||
})
|
||||
.and_then(|value| value.trim().parse::<usize>().ok())
|
||||
.unwrap_or_default();
|
||||
let expected_len = header_end + content_length;
|
||||
while request.len() < expected_len {
|
||||
let Ok(read) = stream.read(&mut buffer).await else {
|
||||
return;
|
||||
};
|
||||
if read == 0 {
|
||||
break;
|
||||
}
|
||||
request.extend_from_slice(&buffer[..read]);
|
||||
}
|
||||
let _ = request_tx.send(request);
|
||||
let body = "{\"data\":[]}";
|
||||
let response = format!(
|
||||
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}",
|
||||
@@ -358,6 +401,6 @@ mod tests {
|
||||
let _ = stream.write_all(response.as_bytes()).await;
|
||||
});
|
||||
|
||||
(format!("http://{addr}"), server)
|
||||
(format!("http://{addr}"), server, request_rx)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user