mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 09:28:11 +00:00
wip
This commit is contained in:
1 parent
11607b4fec
commit
3dfb320ef6
5 files changed
+102
-58
No files matched your search
@@ -1,4 +1,5 @@
|
||||
pub mod run_object;
|
||||
pub mod run_object_id;
|
||||
pub mod upload_object_id;
|
||||
pub mod upload_mime_type;
|
||||
pub mod upload_object_id;
|
||||
pub mod world_object_id;
|
||||
@@ -0,0 +1,80 @@
|
||||
use std::collections::HashMap;
|
||||
use chrono::Utc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
const RUN_MIME_TYPE: &str = "application/run+json";
|
||||
|
||||
const RUN_VERSION : &str = "0.0.1";
|
||||
|
||||
/// World Labs' API is very frontend driven
|
||||
/// They send whole objects back to the frontend that the frontend is in charge of mutatingbjects or PATCH them back to the server (yuck):
|
||||
/// - request #1 - create run
|
||||
/// - request #6 - patch run after image upload
|
||||
/// Gotta go fast?
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
|
||||
pub struct RunObject {
|
||||
/// The primary ID of the run.
|
||||
/// This won't exist until we post it to the server.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub id: Option<String>,
|
||||
|
||||
pub metadata: RunObjectMetadata,
|
||||
pub mime_type: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct RunObjectMetadata {
|
||||
pub version: String,
|
||||
|
||||
#[serde(rename = "createdAt")]
|
||||
pub created_at: u64,
|
||||
|
||||
#[serde(rename = "updatedAt")]
|
||||
pub updated_at: u64,
|
||||
|
||||
#[serde(rename = "usesAdvancedEditing")]
|
||||
pub uses_advanced_editing: bool,
|
||||
|
||||
#[serde(rename = "draftMode")]
|
||||
pub draft_mode: bool,
|
||||
|
||||
/// Polymorphic set of ID-to-object mappings.
|
||||
pub nodes: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
impl Default for RunObject {
|
||||
fn default() -> Self {
|
||||
let now = Utc::now();
|
||||
let now = now.timestamp().unsigned_abs();
|
||||
Self {
|
||||
id: None,
|
||||
metadata: RunObjectMetadata{
|
||||
version: RUN_VERSION.to_string(),
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
uses_advanced_editing: false,
|
||||
draft_mode: false,
|
||||
nodes: HashMap::new(),
|
||||
},
|
||||
mime_type: RUN_MIME_TYPE.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::api::api_types::run_object::RunObject;
|
||||
|
||||
#[test]
|
||||
fn default_runobject() {
|
||||
let object = RunObject::default();
|
||||
assert!(object.id.is_none());
|
||||
assert_eq!(&object.metadata.version, "0.0.1");
|
||||
assert!(object.metadata.created_at > 1765433415549);
|
||||
assert!(object.metadata.updated_at > 1765433415549);
|
||||
assert_eq!(&object.mime_type, "application/run+json");
|
||||
}
|
||||
}
|
||||
|
||||
+15
-57
@@ -1,3 +1,4 @@
|
||||
use crate::api::api_types::run_object::RunObject;
|
||||
use crate::api::api_types::run_object_id::RunObjectId;
|
||||
use crate::api::common::common_header_values::{ORIGIN_VALUE, REFERER_VALUE};
|
||||
use crate::credentials::world_labs_bearer_token::WorldLabsBearerToken;
|
||||
@@ -5,6 +6,7 @@ use crate::credentials::world_labs_cookies::WorldLabsCookies;
|
||||
use crate::error::world_labs_client_error::WorldLabsClientError;
|
||||
use crate::error::world_labs_error::WorldLabsError;
|
||||
use crate::error::world_labs_generic_api_error::WorldLabsGenericApiError;
|
||||
use crate::error::world_labs_specific_api_error::WorldLabsSpecificApiError;
|
||||
use chrono::Utc;
|
||||
use http_headers::names::{PRIORITY, SEC_FETCH_DEST, SEC_FETCH_MODE, SEC_FETCH_SITE, SEC_GPC};
|
||||
use http_headers::values::accept::ACCEPT_ALL;
|
||||
@@ -32,6 +34,7 @@ pub struct CreateRunObjectArgs<'a> {
|
||||
|
||||
pub struct CreateRunObjectResponse {
|
||||
pub id: RunObjectId,
|
||||
pub run_object: RunObject,
|
||||
}
|
||||
|
||||
/// Marble Image-to-World
|
||||
@@ -67,9 +70,9 @@ pub async fn create_run_object(args: CreateRunObjectArgs<'_>) -> Result<CreateRu
|
||||
request_builder = request_builder.timeout(timeout);
|
||||
}
|
||||
|
||||
let request_payload = RawRequest::default();
|
||||
let new_run_object = RunObject::default();
|
||||
|
||||
let http_request = request_builder.json(&request_payload)
|
||||
let http_request = request_builder.json(&new_run_object)
|
||||
.build()
|
||||
.map_err(|err| {
|
||||
error!("Error building request: {:?}", err);
|
||||
@@ -101,63 +104,18 @@ pub async fn create_run_object(args: CreateRunObjectArgs<'_>) -> Result<CreateRu
|
||||
|
||||
debug!("Response body (200): {}", response_body);
|
||||
|
||||
let response : RawResponse = serde_json::from_str(&response_body)
|
||||
let response : RunObject = serde_json::from_str(&response_body)
|
||||
.map_err(|err| WorldLabsGenericApiError::SerdeResponseParseErrorWithBody(err, response_body.to_string()))?;
|
||||
|
||||
let run_id = match &response.id {
|
||||
Some(id) => RunObjectId(id.to_string()),
|
||||
None => {
|
||||
return Err(WorldLabsSpecificApiError::NoRunIdInResponse { response_body }.into())
|
||||
}
|
||||
};
|
||||
|
||||
Ok(CreateRunObjectResponse {
|
||||
id: RunObjectId(response.id),
|
||||
id: run_id,
|
||||
run_object: response,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct RawRequest {
|
||||
pub metadata: RawRequestMetadata,
|
||||
pub mime_type: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct RawRequestMetadata {
|
||||
pub version: String,
|
||||
|
||||
#[serde(rename = "createdAt")]
|
||||
pub created_at: u64,
|
||||
|
||||
#[serde(rename = "updatedAt")]
|
||||
pub updated_at: u64,
|
||||
|
||||
#[serde(rename = "usesAdvancedEditing")]
|
||||
pub uses_advanced_editing: bool,
|
||||
|
||||
#[serde(rename = "draftMode")]
|
||||
pub draft_mode: bool,
|
||||
|
||||
pub nodes: RawRequestNodes,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct RawRequestNodes {
|
||||
}
|
||||
|
||||
impl Default for RawRequest {
|
||||
fn default() -> Self {
|
||||
let now = Utc::now();
|
||||
let now = now.timestamp().unsigned_abs();
|
||||
Self {
|
||||
metadata: RawRequestMetadata {
|
||||
version: "0.0.1".to_string(),
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
uses_advanced_editing: false,
|
||||
draft_mode: false,
|
||||
nodes: RawRequestNodes {},
|
||||
},
|
||||
mime_type: "application/run+json".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct RawResponse {
|
||||
pub id: String,
|
||||
//pub owner_id: String,
|
||||
}
|
||||
@@ -3,6 +3,9 @@ use std::fmt::{Display, Formatter};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum WorldLabsSpecificApiError {
|
||||
/// If the API drops run ids (unlikely)
|
||||
NoRunIdInResponse { response_body: String },
|
||||
|
||||
/// The Google GCP upload failed because the signature does not match
|
||||
GoogleUploadSignatureDoesNotMatch,
|
||||
|
||||
@@ -62,6 +65,7 @@ impl Error for WorldLabsSpecificApiError {}
|
||||
impl Display for WorldLabsSpecificApiError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::NoRunIdInResponse { response_body } => write!(f, "no run.id found in response: {}", response_body),
|
||||
Self::GoogleUploadSignatureDoesNotMatch => write!(f, "Google upload signature does not match"),
|
||||
Self::AutomationBlocked => write!(f, "Automation blocked"),
|
||||
Self::TooManyVideos => write!(f, "Too many videos are being generated"),
|
||||
|
||||
+1
@@ -41,6 +41,7 @@ pub async fn upload_image_and_create_world_with_retry(args: UploadImageAndCreate
|
||||
}).await?;
|
||||
|
||||
let run_object_id = response.id;
|
||||
let run_object = response.run_object;
|
||||
|
||||
info!("Object id: {}", run_object_id.0);
|
||||
|
||||
|
||||
Reference in new issue
Block a user