use base64::{
engine::{self, general_purpose},
Engine as _,
};
use image::{io::Reader as ImageReader, DynamicImage, RgbaImage};
use reqwest;
use serde_json::{json, Value};
use std::{borrow::Cow, io::Cursor};
async fn t2i(text: &str, batch_size: usize, api_key: &str) -> Result<Value, reqwest::Error> {
let client = reqwest::Client::new();
let res = client
.post("https://api.kakaobrain.com/v1/inference/karlo/t2i")
.header("Authorization", format!("KakaoAK {}", api_key))
.header("Content-Type", "application/json")
.json(&json!({
"prompt": {
"text": text,
"batch_size": batch_size
}
}))
.send()
.await?;
println!("Generating image based on text...");
let response: Value = res.json().await?;
Ok(response)
}
pub fn string_to_image(base64_string: &str) -> RgbaImage {
let img_data = general_purpose::STANDARD.decode(base64_string).unwrap();
let img = ImageReader::new(Cursor::new(img_data))
.with_guessed_format()
.expect("Failed to guess image format")
.decode()
.expect("Failed to decode image")
.to_rgba8();
img
}
pub async fn generate_image(
prompt: &str,
output_prefix: &str,
api_key: &str,
batch_size: Option<usize>,
) -> Result<(), Box<dyn std::error::Error>> {
let batch_size = batch_size.unwrap_or(1);
let response = t2i(prompt, batch_size, api_key).await?;
for (index, image_data) in response["images"].as_array().unwrap().iter().enumerate() {
let image_base64 = image_data["image"].as_str().unwrap();
let result = string_to_image(image_base64);
let output_path = Cow::from(format!("{}_{}.png", output_prefix, index + 1));
result.save(&*output_path)?;
println!("Generated image saved to {}", output_path);
}
Ok(())
}
async fn variations(
image_base64: &str,
batch_size: usize,
api_key: &str,
) -> Result<Value, reqwest::Error> {
let client = reqwest::Client::new();
let res = client
.post("https://api.kakaobrain.com/v1/inference/karlo/variations")
.header("Authorization", format!("KakaoAK {}", api_key))
.header("Content-Type", "application/json")
.json(&json!({
"prompt": {
"image": image_base64,
"batch_size": batch_size
}
}))
.send()
.await?;
println!("Generating variations...");
let response: Value = res.json().await?;
Ok(response)
}
fn image_to_base64_string(img: &DynamicImage) -> String {
let mut buffer = Vec::new();
let mut cursor = Cursor::new(&mut buffer);
img.write_to(&mut cursor, image::ImageOutputFormat::Png)
.expect("Failed to write image to buffer");
general_purpose::STANDARD.encode(buffer)
}
pub async fn generate_variations(
input_path: &str,
output_prefix: &str,
api_key: &str,
batch_size: Option<usize>,
) -> Result<(), Box<dyn std::error::Error>> {
let batch_size = batch_size.unwrap_or(1);
let input_image = image::open(input_path)?;
let img_base64 = image_to_base64_string(&input_image);
let response = variations(&img_base64, batch_size, api_key).await?;
for (index, image_data) in response["images"].as_array().unwrap().iter().enumerate() {
let image_base64 = image_data["image"].as_str().unwrap();
let result = string_to_image(image_base64);
let output_path = Cow::from(format!("{}_{}.png", output_prefix, index + 1));
result.save(&*output_path)?;
println!("Variation image saved to {}", output_path);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tokio;
const API_KEY: &str = "your_api_key_here";
#[test]
fn test_string_to_image() {
let contents = fs::read_to_string("decode_example.txt").expect("Failed to read file");
let _ = string_to_image(contents.as_str());
}
#[test]
fn test_image_to_base64_string() {
let input_image_path = "path/to/image.png";
let input_image = image::open(input_image_path).expect("Failed to open image file");
let _ = image_to_base64_string(&input_image);
}
#[tokio::test]
async fn test_generate_image() {
let prompt = "A beautiful sunset over the ocean";
let output_prefix = "sunset in the universe";
let result = generate_image(prompt, output_prefix, API_KEY, None).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_generate_variations() {
let input_path = "path/to/input/image.png";
let output_prefix = "output";
let result = generate_variations(input_path, output_prefix, API_KEY, None).await;
assert!(result.is_ok());
}
}