From 6e2b0e5a55bc921e6920bbf877b2753ac1117756 Mon Sep 17 00:00:00 2001 From: Jeremy Arnold Date: Wed, 14 Feb 2024 15:21:32 -0800 Subject: [PATCH] image_generator_open_ai example project --- Cargo.toml | 4 + examples/image_generator_openai.rs | 150 +++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 examples/image_generator_openai.rs diff --git a/Cargo.toml b/Cargo.toml index 08c471ec0..7a73e0002 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -175,3 +175,7 @@ required-features = ["http"] [[example]] name = "weather_app" required-features = ["http"] + +[[example]] +name = "image_generator_openai" +required-features = ["http"] \ No newline at end of file diff --git a/examples/image_generator_openai.rs b/examples/image_generator_openai.rs new file mode 100644 index 000000000..8b551889c --- /dev/null +++ b/examples/image_generator_openai.rs @@ -0,0 +1,150 @@ +use dioxus::prelude::*; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Error}; + +fn main() { + launch(app) +} + +fn app() -> Element { + let mut api = use_signal(|| "".to_string()); + let mut prompt = use_signal(|| "".to_string()); + let mut n_image = use_signal(|| 1.to_string()); + let mut image = use_signal(|| ImageResponse { + created: 0, + data: Vec::new(), + }); + let mut loading = use_signal(|| "".to_string()); + + let mut generate_images = use_resource(move || async move { + let api_key = api.peek().clone(); + let prompt = prompt.peek().clone(); + let number_of_images = n_image.peek().clone(); + + if (api_key.is_empty() || prompt.is_empty() || number_of_images.is_empty()) { + return; + } + + loading.set("is-loading".to_string()); + let images = request(api_key, prompt, number_of_images).await; + match images { + Ok(imgz) => { + image.set(imgz); + } + Err(e) => { + println!("Error: {:?}", e); + } + } + loading.set("".to_string()); + }); + + rsx! { + head { + link { + rel: "stylesheet", + href: "https://unpkg.com/bulma@0.9.0/css/bulma.min.css", + } + } + div { class: "container", + div { class: "columns", + div { class: "column", + input { class: "input is-primary mt-4", + value:"{api}", + r#type: "text", + placeholder: "API", + oninput: move |evt| { + api.set(evt.value().clone()); + }, + } + + input { class: "input is-primary mt-4", + placeholder: "MAX 1000 Dgts", + r#type: "text", + value:"{prompt}", + oninput: move |evt| { + prompt.set(evt.value().clone()); + }, + } + + input { class: "input is-primary mt-4", + r#type: "number", + min:"1", + max:"10", + value:"{n_image}", + oninput: move |evt| { + n_image.set(evt.value().clone()); + }, + } + } + } + + button { class: "button is-primary {loading}", + onclick: move |_| { + generate_images.restart(); + }, + "Generate image" + } + br { + } + } + {image.read().data.iter().map(|image| { + rsx!( + section { class: "is-flex", + div { class: "container is-fluid", + div { class: "container has-text-centered", + div { class: "is-justify-content-center", + div { class: "level", + div { class: "level-item", + figure { class: "image", + img { + alt: "", + src: "{image.url}", + } + } + } + } + } + } + } + } + ) + }) + } } +} +async fn request(api: String, prompt: String, n_image: String) -> Result { + let client = reqwest::Client::new(); + let body = json!({ + "prompt": prompt, + "n":n_image.parse::().unwrap_or(1), + "size":"1024x1024", + }); + + let mut authorization = "Bearer ".to_string(); + authorization.push_str(&api); + + let res = client + .post("https://api.openai.com/v1/images/generations") + .body(body.to_string()) + .header("Content-Type", "application/json") + .header("Authorization", authorization) + .send() + .await + .unwrap() + .text() + .await + .unwrap(); + + let deserialized: ImageResponse = serde_json::from_str(&res)?; + Ok(deserialized) +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Props, Clone)] +struct UrlImage { + url: String, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Props, Clone)] +struct ImageResponse { + created: i32, + data: Vec, +}