(
state: web::Data<Arc<RwLock<Master<M>>>>,
req: HttpRequest,
body: web::Json<OpenAIImageRequest>,
)
| 133 | } |
| 134 | |
| 135 | pub async fn generate_image_openai<M: Model>( |
| 136 | state: web::Data<Arc<RwLock<Master<M>>>>, |
| 137 | req: HttpRequest, |
| 138 | body: web::Json<OpenAIImageRequest>, |
| 139 | ) -> impl Responder { |
| 140 | let client = req |
| 141 | .peer_addr() |
| 142 | .map(|a| a.to_string()) |
| 143 | .unwrap_or_else(|| "unknown".to_string()); |
| 144 | |
| 145 | log::info!("starting OpenAI image generation for {} ...", &client); |
| 146 | |
| 147 | let mut master = state.write().await; |
| 148 | |
| 149 | if !master.model.as_ref().is_some_and(|m| m.output_modality() == OutputModality::Image) { |
| 150 | return HttpResponse::NotFound() |
| 151 | .json(serde_json::json!({"error": "No image model loaded"})); |
| 152 | } |
| 153 | |
| 154 | let args = ImageGenerationArgs::from_prompt(&body.prompt); |
| 155 | |
| 156 | let result_pngs: Arc<Mutex<Vec<Vec<u8>>>> = Arc::new(Mutex::new(Vec::new())); |
| 157 | let result_pngs_cloned = Arc::clone(&result_pngs); |
| 158 | |
| 159 | if let Err(e) = master |
| 160 | .generate_image(args, move |images| { |
| 161 | let pngs: Vec<Vec<u8>> = images.iter().map(encode_png).collect(); |
| 162 | let mut locked = result_pngs_cloned.lock().expect("Error acquiring lock"); |
| 163 | locked.extend(pngs); |
| 164 | }) |
| 165 | .await |
| 166 | { |
| 167 | return HttpResponse::InternalServerError() |
| 168 | .json(serde_json::json!({"error": format!("{e}")})); |
| 169 | } |
| 170 | |
| 171 | let locked = result_pngs.lock().expect("Error acquiring lock"); |
| 172 | |
| 173 | if body.response_format == "b64_json" { |
| 174 | // OpenAI-compatible JSON envelope |
| 175 | let created = SystemTime::now() |
| 176 | .duration_since(UNIX_EPOCH) |
| 177 | .unwrap() |
| 178 | .as_secs(); |
| 179 | let data: Vec<OpenAIImageData> = locked |
| 180 | .iter() |
| 181 | .map(|png| OpenAIImageData { |
| 182 | b64_json: general_purpose::STANDARD.encode(png), |
| 183 | }) |
| 184 | .collect(); |
| 185 | HttpResponse::Ok().json(OpenAIImageResponse { created, data }) |
| 186 | } else { |
| 187 | // Default: raw PNG bytes |
| 188 | if let Some(png) = locked.first() { |
| 189 | HttpResponse::Ok() |
| 190 | .content_type("image/png") |
| 191 | .body(png.clone()) |
| 192 | } else { |
nothing calls this directly
no test coverage detected