midjourney image upload works!

This commit is contained in:
Brandon Thomas committed 2025-08-15 01:38:02 -04:00
1 parent ec97e3aa51
commit 0388c3bbb8
6 files changed
+111 -7

No files matched your search

@@ -41,6 +41,12 @@ pub enum MidjourneyApiError {
backend_hostname: Option<String>,
},
/// Eg. when downloading images
UnknownHttpFailure {
status_code: u16,
body: String,
},
/// Cloudflare errors.
CloudflareError(CloudflareError),
@@ -81,6 +87,9 @@ impl Display for MidjourneyApiError {
Self::TooManyRequests(msg) => write!(f, "Too many requests: {}", msg),
Self::InternalServerError {body, backend_hostname} =>
write!(f, "Internal Server Error; backend hostname: {:?} ; body: {}; ", backend_hostname, body),
Self::UnknownHttpFailure {status_code, body} =>
write!(f, "Unknown HTTP failure; status code: {}; body: {}", status_code, body),
// Deserialization errors
// Server response handling errors
Self::DeserializationError(error) => write!(f, "Deserialization error: {}", error),
// Network errors
@@ -0,0 +1,70 @@
use crate::error::midjourney_api_error::MidjourneyApiError;
use crate::error::midjourney_client_error::MidjourneyClientError;
use crate::error::midjourney_error::MidjourneyError;
use crate::utils::get_image_url::get_image_url;
use cloudflare_errors::filter_cloudflare_errors::filter_cloudflare_errors;
use wreq::Client;
use wreq_util::Emulation;
#[derive(Clone)]
pub struct ImageDownloaderClient {
client: Client,
}
impl ImageDownloaderClient {
pub fn create() -> Result<Self, MidjourneyClientError> {
Ok(Self {
client: Client::builder()
.emulation(Emulation::Firefox139)
.build()
.map_err(|err| MidjourneyClientError::WreqError(err))?
})
}
pub async fn download_image(&self, job_id: &str, image_index: u8) -> anyhow::Result<Vec<u8>, MidjourneyError> {
let url = get_image_url(job_id, image_index)?;
// TODO: Cookies
// TODO: Cache control headers?
let mut http_request = self.client.get(url)
//.header("Referrer-Policy", "origin-when-cross-origin")
//.header("content-type", "application/json")
//.header("sec-fetch-user", "?1")
//.header("upgrade-insecure-requests", "1");
.header("Referrer", "https://www.midjourney.com/")
.header("accept", "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8")
.header("accept-language", "en-US,en;q=0.8")
.header("priority", "i")
.header("sec-ch-ua-mobile", "?0")
.header("sec-fetch-dest", "image")
.header("sec-fetch-mode", "no-cors")
.header("sec-fetch-site", "same-site");
let http_request = http_request
.build()
.map_err(|err| MidjourneyClientError::WreqError(err))?;
let response = self.client.execute(http_request)
.await
.map_err(|e| MidjourneyApiError::NetworkError(e.to_string()))?;
let status = response.status();
let response_bytes = response.bytes().await
.map_err(|e| MidjourneyApiError::NetworkError(e.to_string()))?;
if !status.is_success() {
let response_body = String::from_utf8_lossy(&response_bytes).to_string();
if let Err(err) = filter_cloudflare_errors(status.as_u16(), &response_body) {
return Err(MidjourneyApiError::CloudflareError(err).into());
}
return Err(MidjourneyApiError::UnknownHttpFailure {
status_code: status.as_u16(),
body: response_body,
}.into());
}
Ok(response_bytes.to_vec())
}
}
@@ -1 +1,2 @@
pub mod get_image_url;
pub mod get_image_url;
pub mod image_downloader_client;
@@ -18,6 +18,7 @@ use std::io::Write;
use std::path::PathBuf;
use tauri::AppHandle;
use url::Url;
use midjourney_client::utils::image_downloader_client::ImageDownloaderClient;
use storyteller_client::media_files::upload_image_media_file_from_file::{upload_image_media_file_from_file, UploadImageFromFileArgs};
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
@@ -66,7 +67,14 @@ async fn polling_loop(
}
// TODO: Graceful wait, fix this long function body
let storyteller_creds = storyteller_creds_manager.get_credentials_required()?;
let storyteller_creds = match storyteller_creds_manager.get_credentials()? {
Some(creds) => creds,
None => {
error!("No Storyteller credentials found. Cannot proceed with Midjourney polling.");
tokio::time::sleep(std::time::Duration::from_millis(10_000)).await;
continue;
}
};
let cookies = creds.maybe_copy_cookie_store()?;
@@ -150,6 +158,8 @@ async fn polling_loop(
// TODO: If we introduce another job polling mechanism, we may need to handle concurrency.
let image_downloader = ImageDownloaderClient::create()?;
for (midjourney_job_id, local_task) in local_tasks_by_midjourney_job_id.iter() {
let midjourney_item = match midjourney_items_by_id.get(midjourney_job_id) {
Some(item) => item,
@@ -158,7 +168,13 @@ async fn polling_loop(
for index in 0..4 {
info!("Downloading generated Midjourney file...");
let download_path = download_midjourney_image(midjourney_job_id, index, app_data_root).await?;
let download_path = download_midjourney_image(
&image_downloader,
midjourney_job_id,
index,
app_data_root
).await?;
info!("Uploading to backend...");
@@ -6,13 +6,21 @@ use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use url::Url;
use midjourney_client::utils::image_downloader_client::ImageDownloaderClient;
pub async fn download_midjourney_image(job_id: &str, index: u8, app_data_root: &AppDataRoot) -> AnyhowResult<PathBuf> {
pub async fn download_midjourney_image(
image_downloader: &ImageDownloaderClient,
job_id: &str,
index: u8,
app_data_root: &AppDataRoot
) -> AnyhowResult<PathBuf> {
let url = get_image_url(job_id, index)?;
let parsed_url = Url::parse(&url)?;
let response = reqwest::get(&url).await?;
let image_bytes = response.bytes().await?;
//let response = reqwest::get(&url).await?;
//let image_bytes = response.bytes().await?;
let image_bytes = image_downloader.download_image(job_id, index).await?;
let ext = parsed_url.path().split(".").last().unwrap_or("png");
@@ -49,7 +49,7 @@ impl StorytellerCredentialHolder {
match self.credentials.read() {
Err(err) => Err(anyhow!("Failed to acquire read lock: {:?}", err)),
Ok(creds) => match &*creds {
None => Err(anyhow!("Credentials not set")),
None => Err(anyhow!("Storyteller credentials not set")),
Some(creds) => Ok(creds.clone()),
}
}