use crate::{client, validators};
use serde_json::{json, Value};
use std::collections::HashMap;
pub fn check(name: &str) {
let base = client::base_url();
let mut params = HashMap::new();
params.insert("name".into(), name.into());
let data = client::request_json(
"GET",
&format!("{}/vidu/v1/material/elements/create/check", base),
None,
None,
Some(¶ms)
);
client::ok(data);
}
pub fn preprocess(name: &str, elem_type: &str, images: &[String]) {
if images.is_empty() || images.len() > 3 {
client::fail("client_error", "Must provide 1-3 images", None, None, None);
}
let components: Vec<Value> = images.iter().enumerate().map(|(i, img)| {
json!({
"content": img,
"src_img": img,
"content_type": "image",
"type": if i == 0 { "main" } else { "auxiliary" }
})
}).collect();
let body = json!({
"components": components,
"name": name,
"type": elem_type
});
let err = validators::validate_element_preprocess(&body);
if !err.is_empty() {
client::fail("client_error", &err, None, None, None);
}
let base = client::base_url();
let data = client::request_json("POST", &format!("{}/vidu/v1/material/elements/pre-process", base), None, Some(&body), None);
let id = data.get("id").map(|v| match v {
Value::String(s) => s.clone(),
Value::Number(n) => n.to_string(),
_ => String::new(),
}).unwrap_or_default();
let creator_id = data.get("creator_id").map(|v| match v {
Value::String(s) => s.clone(),
Value::Number(n) => n.to_string(),
_ => String::new(),
}).unwrap_or_default();
let style = data.get("recaption")
.and_then(|r| r.get("style"))
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let description = data.get("recaption")
.and_then(|r| r.get("description"))
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
client::ok(json!({
"id": id,
"creator_id": creator_id,
"style": style,
"description": description
}));
}
fn extract_string_id(data: &Value, key: &str) -> String {
data.get(key).map(|v| match v {
Value::String(s) => s.clone(),
Value::Number(n) => n.to_string(),
_ => String::new(),
}).unwrap_or_default()
}
pub fn create(
name: &str, modality: &str, elem_type: &str,
images: &[String], description: Option<&str>, style: Option<&str>,
) {
if images.is_empty() || images.len() > 3 {
client::fail("client_error", "Must provide 1-3 images", None, None, None);
}
if let Some(s) = style {
if s.chars().count() > 64 {
client::fail("client_error", "recaption.style must not exceed 64 characters", None, None, None);
}
}
if let Some(d) = description {
let char_count = d.chars().count();
if d.is_empty() || char_count > 1280 {
client::fail("client_error", "recaption.description must be 1-1280 characters", None, None, None);
}
}
let base = client::base_url();
let mut check_params = HashMap::new();
check_params.insert("name".into(), name.into());
let _check = client::request_json(
"GET",
&format!("{}/vidu/v1/material/elements/create/check", base),
Some("check_name"),
None,
Some(&check_params),
);
let processed_images: Vec<String> = images.iter().map(|img| {
crate::commands::tasks::process_image_input(img)
}).collect();
let components: Vec<Value> = processed_images.iter().enumerate().map(|(i, img)| {
json!({
"content": img,
"src_img": img,
"content_type": "image",
"type": if i == 0 { "main" } else { "auxiliary" }
})
}).collect();
let preprocess_body = json!({
"components": components,
"name": name,
"type": elem_type
});
let prep_data = client::request_json(
"POST",
&format!("{}/vidu/v1/material/elements/pre-process", base),
Some("preprocess"),
Some(&preprocess_body),
None,
);
let elem_id = extract_string_id(&prep_data, "id");
let creator_id = extract_string_id(&prep_data, "creator_id");
let prep_style = prep_data.get("recaption")
.and_then(|r| r.get("style"))
.and_then(|v| v.as_str())
.unwrap_or("");
let prep_desc = prep_data.get("recaption")
.and_then(|r| r.get("description"))
.and_then(|v| v.as_str())
.unwrap_or("");
let final_style = style.unwrap_or(prep_style);
let final_desc = description.unwrap_or(prep_desc);
let mut recaption = json!({"description": final_desc});
if !final_style.is_empty() {
recaption["style"] = json!(final_style);
}
let create_body = json!({
"id": elem_id,
"name": name,
"modality": modality,
"type": elem_type,
"components": components,
"creator_id": creator_id,
"recaption": recaption
});
let data = client::request_json(
"POST",
&format!("{}/vidu/v1/material/elements", base),
Some("create"),
Some(&create_body),
None,
);
let id = extract_string_id(&data, "id");
let ver = extract_string_id(&data, "version");
client::ok(json!({"id": id, "version": ver}));
}
pub fn list_elements(keyword: Option<&str>, page: i64, pagesz: i64) {
let mut params = HashMap::new();
params.insert("pager.page".into(), page.to_string());
params.insert("pager.pagesz".into(), pagesz.to_string());
params.insert("modalities".into(), "image".into());
if let Some(kw) = keyword {
params.insert("keyword".into(), kw.to_string());
}
let base = client::base_url();
let data = client::request_json("GET", &format!("{}/vidu/v1/material/elements/personal", base), None, None, Some(¶ms));
let elements = data.get("elements").and_then(|v| v.as_array()).cloned().unwrap_or_default();
let items: Vec<Value> = elements.iter().map(|e| {
json!({
"id": e.get("id").map(|v| match v { Value::String(s) => s.clone(), Value::Number(n) => n.to_string(), _ => String::new() }).unwrap_or_default(),
"version": e.get("version").map(|v| match v { Value::String(s) => s.clone(), Value::Number(n) => n.to_string(), _ => String::new() }).unwrap_or_default(),
"name": e.get("name").and_then(|v| v.as_str()).unwrap_or("")
})
}).collect();
let next_token = data.get("next_page_token").and_then(|v| v.as_str()).unwrap_or("");
client::ok(json!({"elements": items, "next_page_token": next_token}));
}
pub fn search(keyword: &str, pagesz: i64, sort_by: &str, page_token: &str) {
if keyword.is_empty() {
client::fail("client_error", "--keyword is required for search", None, None, None);
}
let mut params = HashMap::new();
params.insert("keyword".into(), keyword.into());
params.insert("pager.page_token".into(), page_token.into());
params.insert("pager.pagesz".into(), pagesz.to_string());
params.insert("modalities".into(), "image".into());
params.insert("sort_by".into(), sort_by.into());
params.insert("is_like".into(), "false".into());
params.insert("is_collect".into(), "false".into());
let base = client::base_url();
let data = client::request_json("GET", &format!("{}/vidu/v1/material/share_elements/feed", base), None, None, Some(¶ms));
let share_elements = data.get("share_elements").and_then(|v| v.as_array()).cloned().unwrap_or_default();
let items: Vec<Value> = share_elements.iter().map(|se| {
let empty_obj = json!({});
let empty_arr = json!([]);
let el = se.get("element").unwrap_or(&empty_obj);
let sh = se.get("share").unwrap_or(&empty_obj);
let recaption = el.get("recaption").unwrap_or(&empty_obj);
let desc: String = recaption.get("description").and_then(|v| v.as_str()).unwrap_or("").chars().take(100).collect();
json!({
"id": el.get("id").map(|v| match v { Value::String(s) => s.clone(), Value::Number(n) => n.to_string(), _ => String::new() }).unwrap_or_default(),
"version": el.get("version").map(|v| match v { Value::String(s) => s.clone(), Value::Number(n) => n.to_string(), _ => String::new() }).unwrap_or_default(),
"name": el.get("name").and_then(|v| v.as_str()).unwrap_or(""),
"description": desc,
"category": sh.get("category_display").unwrap_or(&empty_arr)
})
}).collect();
let next_token = data.get("next_page_token").and_then(|v| v.as_str()).unwrap_or("");
client::ok(json!({"elements": items, "next_page_token": next_token}));
}