mod data_set;
pub mod gen_type;
mod info;
mod model;
pub mod params;
mod query;
mod status;
mod work;
use std::sync::Arc;
use crate::{error, result::Result};
use info::Info;
use miniserde::json;
use model::Model;
use params::Params;
use reqwest::{
header::{HeaderMap, HeaderValue},
multipart::{self, Form},
Client,
};
use status::Status;
use tracing::{debug, info, instrument, trace};
use work::Work;
pub struct Flopper {
client: Arc<Client>,
model: usize,
duration: usize,
}
impl Flopper {
const DEFAULT_MODEL: usize = 4;
const URL_MODEL: &'static str = "https://api-key.fusionbrain.ai/key/api/v1/models";
const URL_RUN: &'static str = "https://api-key.fusionbrain.ai/key/api/v1/text2image/run";
const URL_WORK_STATUS: &'static str =
"https://api-key.fusionbrain.ai/key/api/v1/text2image/status";
const DURATION: usize = 60;
#[instrument(skip(key, secret))]
pub async fn build(
key: String,
secret: String,
model: Option<usize>,
duration: Option<usize>,
) -> Result<Self> {
let key = format!("Key {}", key);
let secret = format!("Secret {}", secret);
let mut headers = HeaderMap::new();
headers.insert("X-Key", HeaderValue::from_str(&key)?);
headers.insert("X-Secret", HeaderValue::from_str(&secret)?);
trace!("Create client with headers: {:#?}", &headers);
let client = reqwest::ClientBuilder::new()
.default_headers(headers)
.build()?;
Ok(Self {
client: Arc::new(client),
model: model.unwrap_or(Self::DEFAULT_MODEL),
duration: duration.unwrap_or(Self::DURATION),
})
}
#[instrument(skip(self))]
pub async fn get_all_model(&self) -> Result<Vec<Model>> {
debug!("Send request");
let r = self.client.get(Self::URL_MODEL).send().await?;
debug!("Fetch text");
let text = r.text().await?;
trace!("Parse text to Vec<Model>: {:#?}", text);
let models: Vec<Model> = miniserde::json::from_str(&text)?;
Ok(models)
}
#[instrument(skip(self))]
pub async fn push(&self, params: Params) -> Result<Info> {
debug!("Crate form");
let form = Form::new()
.part("model_id", multipart::Part::text(self.model.to_string()))
.part(
"params",
multipart::Part::text(json::to_string(¶ms)).mime_str("application/json")?,
);
debug!("Create and Send Response");
let r = self
.client
.post(Self::URL_RUN)
.multipart(form)
.send()
.await?;
debug!("Fetch text");
let text = r.text().await?;
trace!("Parse text to Info\n{:#?}", text);
let pull_out: Info = miniserde::json::from_str(&text)?;
Ok(pull_out)
}
#[instrument(skip(self, pull))]
pub async fn try_fetch(&self, pull: Info) -> Result<Vec<String>> {
info!("Generate request");
let r = self
.client
.get(&format!("{}/{}", Self::URL_WORK_STATUS, pull.uuid));
loop {
info!("Wait for {} seconds", self.duration);
tokio::time::sleep(std::time::Duration::from_secs(self.duration as u64)).await;
debug!("Clone and Send request");
let r = r
.try_clone()
.ok_or(error::Errors::CloneError)?
.send()
.await?;
debug!("Fetch text");
let text = r.text().await?;
trace!("Parse text to Work {:#?}", text);
let work: Work = miniserde::json::from_str(&text)?;
debug!("Check status");
match work.status {
Status::Initial => {
info!("Initial status: {}", work.uuid);
continue;
}
Status::Processing => {
info!("Processing status: {}", work.uuid);
continue;
}
Status::Fail => {
return Err(error::Errors::WorkFail(format!(
"error: {:#?}, censored: {}, uuid: {}",
work.error, work.censored, work.uuid
)))
}
Status::Done => {
info!("Done status: {}", work.uuid);
return Ok(if let Some(images) = work.images {
images
} else {
return Err(error::Errors::WorkFailNoImage(format!(
"uuid: {}",
work.uuid
)));
});
}
}
}
}
}