diff --git a/kittycad.rs.patch.json b/kittycad.rs.patch.json index 619af479..7b55b1e6 100644 --- a/kittycad.rs.patch.json +++ b/kittycad.rs.patch.json @@ -33,18 +33,10 @@ }, { "op": "add", - "path": "/paths/~1ai~1image-to-3d~1{input_format}~1{output_format}/post/x-rust", + "path": "/paths/~1ai~1text-to-cad~1{output_format}/post/x-rust", "value": { - "example": "/// Generate a 3D model from an image.\n/// \n/// This is an alpha endpoint. It will change in the future. The current output is honestly pretty bad. So if you find this endpoint, you get what you pay for, which currently is nothing. But in the future will be made a lot better.\n/// \n/// **Parameters:**\n/// \n/// - `input_format: crate::types::ImageType`: The format of the image being converted. (required)\n/// - `output_format: crate::types::FileExportFormat`: The format the output file should be converted to. (required)\nasync fn example_ai_create_image_to_3d() -> anyhow::Result<()> {\n let client = kittycad::Client::new_from_env();\n let result: kittycad::types::Mesh = client\n .ai()\n .create_image_to_3d(\n kittycad::types::ImageType::Jpg,\n kittycad::types::FileExportFormat::Stl,\n &bytes::Bytes::from(\"some-string\"),\n )\n .await?;\n println!(\"{:?}\", result);\n Ok(())\n}\n", - "libDocsLink": "https://docs.rs/kittycad/latest/kittycad/ai/struct.Ai.html#method.create_image_to_3d" - } - }, - { - "op": "add", - "path": "/paths/~1ai~1text-to-3d~1{output_format}/post/x-rust", - "value": { - "example": "/// Generate a 3D model from text.\n/// \n/// This is an alpha endpoint. It will change in the future. The current output is honestly pretty bad. So if you find this endpoint, you get what you pay for, which currently is nothing. But in the future will be made a lot better.\n/// \n/// **Parameters:**\n/// \n/// - `output_format: crate::types::FileExportFormat`: The format the output file should be converted to. (required)\n/// - `prompt: &'astr`: The prompt for the model. (required)\nasync fn example_ai_create_text_to_3d() -> anyhow::Result<()> {\n let client = kittycad::Client::new_from_env();\n let result: kittycad::types::Mesh = client\n .ai()\n .create_text_to_3d(kittycad::types::FileExportFormat::Stl, \"some-string\")\n .await?;\n println!(\"{:?}\", result);\n Ok(())\n}\n", - "libDocsLink": "https://docs.rs/kittycad/latest/kittycad/ai/struct.Ai.html#method.create_text_to_3d" + "example": "/// Generate a CAD model from text.\n/// \n/// This operation is performed asynchronously, the `id` of the operation will be returned. You can use the `id` returned from the request to get status information about the async operation from the `/async/operations/{id}` endpoint.\n/// This is an alpha endpoint. It will change in the future. The current output is honestly pretty bad. So if you find this endpoint, you get what you pay for, which currently is nothing. But in the future will be made a lot better.\n/// \n/// **Parameters:**\n/// \n/// - `output_format: crate::types::FileExportFormat`: The format the output file should be converted to. (required)\nasync fn example_ai_create_text_to_cad() -> anyhow::Result<()> {\n let client = kittycad::Client::new_from_env();\n let result: kittycad::types::TextToCad = client\n .ai()\n .create_text_to_cad(\n kittycad::types::FileExportFormat::Stl,\n &kittycad::types::TextToCadCreateBody {\n prompt: \"some-string\".to_string(),\n },\n )\n .await?;\n println!(\"{:?}\", result);\n Ok(())\n}\n", + "libDocsLink": "https://docs.rs/kittycad/latest/kittycad/ai/struct.Ai.html#method.create_text_to_cad" } }, { @@ -543,6 +535,22 @@ "libDocsLink": "https://docs.rs/kittycad/latest/kittycad/users/struct.Users.html#method.get_session_for" } }, + { + "op": "add", + "path": "/paths/~1user~1text-to-cad/get/x-rust", + "value": { + "example": "/// List text-to-CAD models you've generated.\n/// \n/// This endpoint requires authentication by any KittyCAD user. It returns the text-to-CAD models for the authenticated user.\n/// The text-to-CAD models are returned in order of creation, with the most recently created text-to-CAD models first.\n/// \n/// **Parameters:**\n/// \n/// - `limit: Option`: Maximum number of items returned by a single call\n/// - `page_token: Option`: Token returned by previous call to retrieve the subsequent page\n/// - `sort_by: Option`\nasync fn example_ai_list_text_to_cad_models_for_user() -> anyhow::Result<()> {\n let client = kittycad::Client::new_from_env();\n let result: kittycad::types::TextToCadResultsPage = client\n .ai()\n .list_text_to_cad_models_for_user(\n Some(4 as u32),\n Some(\"some-string\".to_string()),\n Some(kittycad::types::CreatedAtSortMode::CreatedAtDescending),\n )\n .await?;\n println!(\"{:?}\", result);\n Ok(())\n}\n\n\n/// - OR -\n\n/// Get a stream of results.\n///\n/// This allows you to paginate through all the items.\nuse futures_util::TryStreamExt;\nasync fn example_ai_list_text_to_cad_models_for_user_stream() -> anyhow::Result<()> {\n let client = kittycad::Client::new_from_env();\n let mut ai = client.ai();\n let mut stream = ai.list_text_to_cad_models_for_user_stream(\n Some(4 as u32),\n Some(kittycad::types::CreatedAtSortMode::CreatedAtDescending),\n );\n loop {\n match stream.try_next().await {\n Ok(Some(item)) => {\n println!(\"{:?}\", item);\n }\n Ok(None) => {\n break;\n }\n Err(err) => {\n return Err(err.into());\n }\n }\n }\n\n Ok(())\n}\n", + "libDocsLink": "https://docs.rs/kittycad/latest/kittycad/ai/struct.Ai.html#method.list_text_to_cad_models_for_user" + } + }, + { + "op": "add", + "path": "/paths/~1user~1text-to-cad~1{id}/post/x-rust", + "value": { + "example": "/// Give feedback to a specific text-to-CAD response.\n/// \n/// This endpoint requires authentication by any KittyCAD user. The user must be the owner of the text-to-CAD model, in order to give feedback.\n/// \n/// **Parameters:**\n/// \n/// - `feedback: crate::types::AiFeedback`: The feedback. (required)\n/// - `id: uuid::Uuid`: The id of the model to give feedback to. (required)\nuse std::str::FromStr;\nasync fn example_ai_create_text_to_cad_model_feedback() -> anyhow::Result<()> {\n let client = kittycad::Client::new_from_env();\n client\n .ai()\n .create_text_to_cad_model_feedback(\n kittycad::types::AiFeedback::ThumbsDown,\n uuid::Uuid::from_str(\"d9797f8d-9ad6-4e08-90d7-2ec17e13471c\")?,\n )\n .await?;\n Ok(())\n}\n", + "libDocsLink": "https://docs.rs/kittycad/latest/kittycad/ai/struct.Ai.html#method.create_text_to_cad_model_feedback" + } + }, { "op": "add", "path": "/paths/~1users/get/x-rust", diff --git a/kittycad/src/ai.rs b/kittycad/src/ai.rs index c6f0f352..16e2cd54 100644 --- a/kittycad/src/ai.rs +++ b/kittycad/src/ai.rs @@ -12,26 +12,24 @@ impl Ai { Self { client } } - #[doc = "Generate a 3D model from an image.\n\nThis is an alpha endpoint. It will change in the future. The current output is honestly pretty bad. So if you find this endpoint, you get what you pay for, which currently is nothing. But in the future will be made a lot better.\n\n**Parameters:**\n\n- `input_format: crate::types::ImageType`: The format of the image being converted. (required)\n- `output_format: crate::types::FileExportFormat`: The format the output file should be converted to. (required)\n\n```rust,no_run\nasync fn example_ai_create_image_to_3d() -> anyhow::Result<()> {\n let client = kittycad::Client::new_from_env();\n let result: kittycad::types::Mesh = client\n .ai()\n .create_image_to_3d(\n kittycad::types::ImageType::Jpg,\n kittycad::types::FileExportFormat::Stl,\n &bytes::Bytes::from(\"some-string\"),\n )\n .await?;\n println!(\"{:?}\", result);\n Ok(())\n}\n```"] + #[doc = "Generate a CAD model from text.\n\nThis operation is performed asynchronously, the `id` of the operation will be returned. You can use the `id` returned from the request to get status information about the async operation from the `/async/operations/{id}` endpoint.\nThis is an alpha endpoint. It will change in the future. The current output is honestly pretty bad. So if you find this endpoint, you get what you pay for, which currently is nothing. But in the future will be made a lot better.\n\n**Parameters:**\n\n- `output_format: crate::types::FileExportFormat`: The format the output file should be converted to. (required)\n\n```rust,no_run\nasync fn example_ai_create_text_to_cad() -> anyhow::Result<()> {\n let client = kittycad::Client::new_from_env();\n let result: kittycad::types::TextToCad = client\n .ai()\n .create_text_to_cad(\n kittycad::types::FileExportFormat::Stl,\n &kittycad::types::TextToCadCreateBody {\n prompt: \"some-string\".to_string(),\n },\n )\n .await?;\n println!(\"{:?}\", result);\n Ok(())\n}\n```"] #[tracing::instrument] - pub async fn create_image_to_3d<'a>( + pub async fn create_text_to_cad<'a>( &'a self, - input_format: crate::types::ImageType, output_format: crate::types::FileExportFormat, - body: &bytes::Bytes, - ) -> Result { + body: &crate::types::TextToCadCreateBody, + ) -> Result { let mut req = self.client.client.request( http::Method::POST, format!( "{}/{}", self.client.base_url, - "ai/image-to-3d/{input_format}/{output_format}" - .replace("{input_format}", &format!("{}", input_format)) + "ai/text-to-cad/{output_format}" .replace("{output_format}", &format!("{}", output_format)) ), ); req = req.bearer_auth(&self.client.token); - req = req.body(body.clone()); + req = req.json(body); let resp = req.send().await?; let status = resp.status(); if status.is_success() { @@ -47,24 +45,32 @@ impl Ai { } } - #[doc = "Generate a 3D model from text.\n\nThis is an alpha endpoint. It will change in the future. The current output is honestly pretty bad. So if you find this endpoint, you get what you pay for, which currently is nothing. But in the future will be made a lot better.\n\n**Parameters:**\n\n- `output_format: crate::types::FileExportFormat`: The format the output file should be converted to. (required)\n- `prompt: &'astr`: The prompt for the model. (required)\n\n```rust,no_run\nasync fn example_ai_create_text_to_3d() -> anyhow::Result<()> {\n let client = kittycad::Client::new_from_env();\n let result: kittycad::types::Mesh = client\n .ai()\n .create_text_to_3d(kittycad::types::FileExportFormat::Stl, \"some-string\")\n .await?;\n println!(\"{:?}\", result);\n Ok(())\n}\n```"] + #[doc = "List text-to-CAD models you've generated.\n\nThis endpoint requires authentication by any KittyCAD user. It returns the text-to-CAD models for the authenticated user.\nThe text-to-CAD models are returned in order of creation, with the most recently created text-to-CAD models first.\n\n**Parameters:**\n\n- `limit: Option`: Maximum number of items returned by a single call\n- `page_token: Option`: Token returned by previous call to retrieve the subsequent page\n- `sort_by: Option`\n\n```rust,no_run\nuse futures_util::TryStreamExt;\nasync fn example_ai_list_text_to_cad_models_for_user_stream() -> anyhow::Result<()> {\n let client = kittycad::Client::new_from_env();\n let mut ai = client.ai();\n let mut stream = ai.list_text_to_cad_models_for_user_stream(\n Some(4 as u32),\n Some(kittycad::types::CreatedAtSortMode::CreatedAtDescending),\n );\n loop {\n match stream.try_next().await {\n Ok(Some(item)) => {\n println!(\"{:?}\", item);\n }\n Ok(None) => {\n break;\n }\n Err(err) => {\n return Err(err.into());\n }\n }\n }\n\n Ok(())\n}\n```"] #[tracing::instrument] - pub async fn create_text_to_3d<'a>( + pub async fn list_text_to_cad_models_for_user<'a>( &'a self, - output_format: crate::types::FileExportFormat, - prompt: &'a str, - ) -> Result { + limit: Option, + page_token: Option, + sort_by: Option, + ) -> Result { let mut req = self.client.client.request( - http::Method::POST, - format!( - "{}/{}", - self.client.base_url, - "ai/text-to-3d/{output_format}" - .replace("{output_format}", &format!("{}", output_format)) - ), + http::Method::GET, + format!("{}/{}", self.client.base_url, "user/text-to-cad"), ); req = req.bearer_auth(&self.client.token); - let query_params = vec![("prompt", prompt.to_string())]; + let mut query_params = vec![]; + if let Some(p) = limit { + query_params.push(("limit", format!("{}", p))); + } + + if let Some(p) = page_token { + query_params.push(("page_token", p)); + } + + if let Some(p) = sort_by { + query_params.push(("sort_by", format!("{}", p))); + } + req = req.query(&query_params); let resp = req.send().await?; let status = resp.status(); @@ -80,4 +86,103 @@ impl Ai { Err(crate::types::error::Error::UnexpectedResponse(resp)) } } + + #[doc = "List text-to-CAD models you've generated.\n\nThis endpoint requires authentication by any KittyCAD user. It returns the text-to-CAD models for the authenticated user.\nThe text-to-CAD models are returned in order of creation, with the most recently created text-to-CAD models first.\n\n**Parameters:**\n\n- `limit: Option`: Maximum number of items returned by a single call\n- `page_token: Option`: Token returned by previous call to retrieve the subsequent page\n- `sort_by: Option`\n\n```rust,no_run\nuse futures_util::TryStreamExt;\nasync fn example_ai_list_text_to_cad_models_for_user_stream() -> anyhow::Result<()> {\n let client = kittycad::Client::new_from_env();\n let mut ai = client.ai();\n let mut stream = ai.list_text_to_cad_models_for_user_stream(\n Some(4 as u32),\n Some(kittycad::types::CreatedAtSortMode::CreatedAtDescending),\n );\n loop {\n match stream.try_next().await {\n Ok(Some(item)) => {\n println!(\"{:?}\", item);\n }\n Ok(None) => {\n break;\n }\n Err(err) => {\n return Err(err.into());\n }\n }\n }\n\n Ok(())\n}\n```"] + #[tracing::instrument] + #[cfg(not(feature = "js"))] + pub fn list_text_to_cad_models_for_user_stream<'a>( + &'a self, + limit: Option, + sort_by: Option, + ) -> impl futures::Stream> + + Unpin + + '_ { + use futures::{StreamExt, TryFutureExt, TryStreamExt}; + + use crate::types::paginate::Pagination; + self.list_text_to_cad_models_for_user(limit, None, sort_by) + .map_ok(move |result| { + let items = futures::stream::iter(result.items().into_iter().map(Ok)); + let next_pages = + futures::stream::try_unfold(result, move |new_result| async move { + if new_result.has_more_pages() { + async { + let mut req = self.client.client.request( + http::Method::GET, + format!("{}/{}", self.client.base_url, "user/text-to-cad"), + ); + req = req.bearer_auth(&self.client.token); + let mut request = req.build()?; + request = new_result.next_page(request)?; + let resp = self.client.client.execute(request).await?; + let status = resp.status(); + if status.is_success() { + let text = resp.text().await.unwrap_or_default(); + serde_json::from_str(&text).map_err(|err| { + crate::types::error::Error::from_serde_error( + format_serde_error::SerdeError::new( + text.to_string(), + err, + ), + status, + ) + }) + } else { + Err(crate::types::error::Error::UnexpectedResponse(resp)) + } + } + .map_ok(|result: crate::types::TextToCadResultsPage| { + Some(( + futures::stream::iter(result.items().into_iter().map(Ok)), + result, + )) + }) + .await + } else { + Ok(None) + } + }) + .try_flatten(); + items.chain(next_pages) + }) + .try_flatten_stream() + .boxed() + } + + #[doc = "Give feedback to a specific text-to-CAD response.\n\nThis endpoint requires \ + authentication by any KittyCAD user. The user must be the owner of the text-to-CAD \ + model, in order to give feedback.\n\n**Parameters:**\n\n- `feedback: \ + crate::types::AiFeedback`: The feedback. (required)\n- `id: uuid::Uuid`: The id of \ + the model to give feedback to. (required)\n\n```rust,no_run\nuse \ + std::str::FromStr;\nasync fn example_ai_create_text_to_cad_model_feedback() -> \ + anyhow::Result<()> {\n let client = kittycad::Client::new_from_env();\n \ + client\n .ai()\n .create_text_to_cad_model_feedback(\n \ + kittycad::types::AiFeedback::ThumbsDown,\n \ + uuid::Uuid::from_str(\"d9797f8d-9ad6-4e08-90d7-2ec17e13471c\")?,\n )\n \ + .await?;\n Ok(())\n}\n```"] + #[tracing::instrument] + pub async fn create_text_to_cad_model_feedback<'a>( + &'a self, + feedback: crate::types::AiFeedback, + id: uuid::Uuid, + ) -> Result<(), crate::types::error::Error> { + let mut req = self.client.client.request( + http::Method::POST, + format!( + "{}/{}", + self.client.base_url, + "user/text-to-cad/{id}".replace("{id}", &format!("{}", id)) + ), + ); + req = req.bearer_auth(&self.client.token); + let query_params = vec![("feedback", format!("{}", feedback))]; + req = req.query(&query_params); + let resp = req.send().await?; + let status = resp.status(); + if status.is_success() { + Ok(()) + } else { + Err(crate::types::error::Error::UnexpectedResponse(resp)) + } + } } diff --git a/kittycad/src/types.rs b/kittycad/src/types.rs index 809a2a77..9583f239 100644 --- a/kittycad/src/types.rs +++ b/kittycad/src/types.rs @@ -446,6 +446,31 @@ pub enum AccountProvider { Github, } +#[doc = "Human feedback on an AI response."] +#[derive( + serde :: Serialize, + serde :: Deserialize, + PartialEq, + Hash, + Debug, + Clone, + schemars :: JsonSchema, + parse_display :: FromStr, + parse_display :: Display, +)] +#[cfg_attr(feature = "clap", derive(clap::ValueEnum))] +#[cfg_attr(feature = "tabled", derive(tabled::Tabled))] +pub enum AiFeedback { + #[doc = "Thumbs up."] + #[serde(rename = "thumbs_up")] + #[display("thumbs_up")] + ThumbsUp, + #[doc = "Thumbs down."] + #[serde(rename = "thumbs_down")] + #[display("thumbs_down")] + ThumbsDown, +} + #[doc = "AI plugin api information."] #[derive( serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, @@ -1895,6 +1920,37 @@ pub enum AsyncApiCallOutput { #[doc = "The user ID of the user who created the API call."] user_id: Option, }, + #[doc = "Text to CAD."] + #[serde(rename = "text_to_cad")] + TextToCad { + #[doc = "The time and date the API call was completed."] + completed_at: Option>, + #[doc = "The time and date the API call was created."] + created_at: chrono::DateTime, + #[doc = "The error the function returned, if any."] + error: Option, + #[doc = "Feedback from the user, if any."] + feedback: Option, + #[doc = "The unique identifier of the API call.\n\nThis is the same as the API call ID."] + id: uuid::Uuid, + #[doc = "The version of the model."] + model_version: String, + #[doc = "The output format of the model."] + output_format: FileExportFormat, + #[doc = "The output of the model in the given file format the user requested, base64 \ + encoded. The key of the map is the path of the output file."] + outputs: Option>, + #[doc = "The prompt."] + prompt: String, + #[doc = "The time and date the API call was started."] + started_at: Option>, + #[doc = "The status of the API call."] + status: ApiCallStatus, + #[doc = "The time and date the API call was last updated."] + updated_at: chrono::DateTime, + #[doc = "The user ID of the user who created the API call."] + user_id: Option, + }, } #[doc = "A single page of results"] @@ -2005,6 +2061,10 @@ pub enum AsyncApiCallType { #[serde(rename = "file_surface_area")] #[display("file_surface_area")] FileSurfaceArea, + #[doc = "Text to CAD."] + #[serde(rename = "text_to_cad")] + #[display("text_to_cad")] + TextToCad, } #[doc = "Co-ordinate axis specifier.\n\nSee [cglearn.eu] for background reading.\n\n[cglearn.eu]: https://cglearn.eu/pub/computer-graphics/introduction-to-geometry#material-coordinate-systems-1"] @@ -5449,29 +5509,6 @@ pub enum ImageFormat { Jpeg, } -#[doc = "An enumeration."] -#[derive( - serde :: Serialize, - serde :: Deserialize, - PartialEq, - Hash, - Debug, - Clone, - schemars :: JsonSchema, - parse_display :: FromStr, - parse_display :: Display, -)] -#[cfg_attr(feature = "clap", derive(clap::ValueEnum))] -#[cfg_attr(feature = "tabled", derive(tabled::Tabled))] -pub enum ImageType { - #[serde(rename = "png")] - #[display("png")] - Png, - #[serde(rename = "jpg")] - #[display("jpg")] - Jpg, -} - #[doc = "File to import into the current model"] #[derive( serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, @@ -6364,35 +6401,6 @@ impl tabled::Tabled for Mass { } } -#[derive( - serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, -)] -pub struct Mesh { - pub mesh: String, -} - -impl std::fmt::Display for Mesh { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!( - f, - "{}", - serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)? - ) - } -} - -#[cfg(feature = "tabled")] -impl tabled::Tabled for Mesh { - const LENGTH: usize = 1; - fn fields(&self) -> Vec> { - vec![self.mesh.clone().into()] - } - - fn headers() -> Vec> { - vec!["mesh".into()] - } -} - #[doc = "Jetstream statistics."] #[derive( serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, @@ -6461,8 +6469,6 @@ pub struct Metadata { pub fs: FileSystemMetadata, #[doc = "The git hash of the server."] pub git_hash: String, - #[doc = "Metadata about our point-e instance."] - pub point_e: PointEMetadata, #[doc = "Metadata about our pub-sub connection."] pub pubsub: Connection, } @@ -6479,14 +6485,13 @@ impl std::fmt::Display for Metadata { #[cfg(feature = "tabled")] impl tabled::Tabled for Metadata { - const LENGTH: usize = 6; + const LENGTH: usize = 5; fn fields(&self) -> Vec> { vec![ format!("{:?}", self.cache).into(), format!("{:?}", self.environment).into(), format!("{:?}", self.fs).into(), self.git_hash.clone().into(), - format!("{:?}", self.point_e).into(), format!("{:?}", self.pubsub).into(), ] } @@ -6497,7 +6502,6 @@ impl tabled::Tabled for Metadata { "environment".into(), "fs".into(), "git_hash".into(), - "point_e".into(), "pubsub".into(), ] } @@ -7001,6 +7005,12 @@ pub enum ModelingCmd { #[doc = "IDs of the vertices for which to obtain curve ids from"] vertex_ids: Vec, }, + #[doc = "Get vertices within a path"] + #[serde(rename = "path_get_vertex_uuids")] + PathGetVertexUuids { + #[doc = "Which path to query"] + path_id: uuid::Uuid, + }, #[doc = "Start dragging mouse."] #[serde(rename = "handle_mouse_drag_start")] HandleMouseDragStart { @@ -7512,6 +7522,12 @@ pub enum OkModelingCmdResponse { #[doc = "The response from the `PathGetCurveUuidsForVertices` command."] data: PathGetCurveUuidsForVertices, }, + #[doc = "The response from the `Path Get Vertex UUIDs` command."] + #[serde(rename = "path_get_vertex_uuids")] + PathGetVertexUuids { + #[doc = "The response from the `PathGetVertexUuids` command."] + data: PathGetVertexUuids, + }, #[doc = "The response from the `PlaneIntersectAndProject` command."] #[serde(rename = "plane_intersect_and_project")] PlaneIntersectAndProject { @@ -7874,6 +7890,37 @@ impl tabled::Tabled for PathGetInfo { } } +#[doc = "The response from the `PathGetVertexUuids` command."] +#[derive( + serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, +)] +pub struct PathGetVertexUuids { + #[doc = "The UUIDs of the vertex entities."] + pub vertex_ids: Vec, +} + +impl std::fmt::Display for PathGetVertexUuids { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!( + f, + "{}", + serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)? + ) + } +} + +#[cfg(feature = "tabled")] +impl tabled::Tabled for PathGetVertexUuids { + const LENGTH: usize = 1; + fn fields(&self) -> Vec> { + vec![format!("{:?}", self.vertex_ids).into()] + } + + fn headers() -> Vec> { + vec!["vertex_ids".into()] + } +} + #[doc = "A segment of a path. Paths are composed of many segments."] #[derive( serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, @@ -7892,16 +7939,24 @@ pub enum PathSegment { #[doc = "A circular arc segment."] #[serde(rename = "arc")] Arc { - #[doc = "Start of the arc along circle's perimeter."] + #[doc = "End of the arc along circle's perimeter, in degrees. Deprecated: use `end` \ + instead."] angle_end: f64, - #[doc = "Start of the arc along circle's perimeter."] + #[doc = "Start of the arc along circle's perimeter, in degrees. Deprecated: use `start` \ + instead."] angle_start: f64, #[doc = "Center of the circle"] center: Point2D, + #[doc = "End of the arc along circle's perimeter. If not given, this will use \ + `degrees_end` instead."] + end: Option, #[doc = "Radius of the circle"] radius: f64, #[doc = "Whether or not this arc is a relative offset"] relative: bool, + #[doc = "Start of the arc along circle's perimeter. If not given, this will use \ + `degrees_start` instead."] + start: Option, }, #[doc = "A cubic bezier curve segment. Start at the end of the current line, go through \ control point 1 and 2, then end at a given point."] @@ -8312,38 +8367,6 @@ impl tabled::Tabled for Point3D { } } -#[doc = "Metadata about our point-e instance.\n\nThis is mostly used for internal purposes and \ - debugging."] -#[derive( - serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, -)] -pub struct PointEMetadata { - #[doc = "If the point-e service returned an ok response from ping."] - pub ok: bool, -} - -impl std::fmt::Display for PointEMetadata { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!( - f, - "{}", - serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)? - ) - } -} - -#[cfg(feature = "tabled")] -impl tabled::Tabled for PointEMetadata { - const LENGTH: usize = 1; - fn fields(&self) -> Vec> { - vec![format!("{:?}", self.ok).into()] - } - - fn headers() -> Vec> { - vec!["ok".into()] - } -} - #[doc = "The response from the `/ping` endpoint."] #[derive( serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, @@ -9103,6 +9126,220 @@ impl tabled::Tabled for TakeSnapshot { } } +#[doc = "A response from a text to CAD prompt."] +#[derive( + serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, +)] +pub struct TextToCad { + #[doc = "The time and date the API call was completed."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub completed_at: Option>, + #[doc = "The time and date the API call was created."] + pub created_at: chrono::DateTime, + #[doc = "The error the function returned, if any."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub error: Option, + #[doc = "Feedback from the user, if any."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub feedback: Option, + #[doc = "The unique identifier of the API call.\n\nThis is the same as the API call ID."] + pub id: uuid::Uuid, + #[doc = "The version of the model."] + pub model_version: String, + #[doc = "The output format of the model."] + pub output_format: FileExportFormat, + #[doc = "The output of the model in the given file format the user requested, base64 encoded. \ + The key of the map is the path of the output file."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub outputs: Option>, + #[doc = "The prompt."] + pub prompt: String, + #[doc = "The time and date the API call was started."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub started_at: Option>, + #[doc = "The status of the API call."] + pub status: ApiCallStatus, + #[doc = "The time and date the API call was last updated."] + pub updated_at: chrono::DateTime, + #[doc = "The user ID of the user who created the API call."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub user_id: Option, +} + +impl std::fmt::Display for TextToCad { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!( + f, + "{}", + serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)? + ) + } +} + +#[cfg(feature = "tabled")] +impl tabled::Tabled for TextToCad { + const LENGTH: usize = 13; + fn fields(&self) -> Vec> { + vec![ + if let Some(completed_at) = &self.completed_at { + format!("{:?}", completed_at).into() + } else { + String::new().into() + }, + format!("{:?}", self.created_at).into(), + if let Some(error) = &self.error { + format!("{:?}", error).into() + } else { + String::new().into() + }, + if let Some(feedback) = &self.feedback { + format!("{:?}", feedback).into() + } else { + String::new().into() + }, + format!("{:?}", self.id).into(), + self.model_version.clone().into(), + format!("{:?}", self.output_format).into(), + if let Some(outputs) = &self.outputs { + format!("{:?}", outputs).into() + } else { + String::new().into() + }, + self.prompt.clone().into(), + if let Some(started_at) = &self.started_at { + format!("{:?}", started_at).into() + } else { + String::new().into() + }, + format!("{:?}", self.status).into(), + format!("{:?}", self.updated_at).into(), + if let Some(user_id) = &self.user_id { + format!("{:?}", user_id).into() + } else { + String::new().into() + }, + ] + } + + fn headers() -> Vec> { + vec![ + "completed_at".into(), + "created_at".into(), + "error".into(), + "feedback".into(), + "id".into(), + "model_version".into(), + "output_format".into(), + "outputs".into(), + "prompt".into(), + "started_at".into(), + "status".into(), + "updated_at".into(), + "user_id".into(), + ] + } +} + +#[doc = "Body for generating models from text."] +#[derive( + serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, +)] +pub struct TextToCadCreateBody { + #[doc = "The prompt for the model."] + pub prompt: String, +} + +impl std::fmt::Display for TextToCadCreateBody { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!( + f, + "{}", + serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)? + ) + } +} + +#[cfg(feature = "tabled")] +impl tabled::Tabled for TextToCadCreateBody { + const LENGTH: usize = 1; + fn fields(&self) -> Vec> { + vec![self.prompt.clone().into()] + } + + fn headers() -> Vec> { + vec!["prompt".into()] + } +} + +#[doc = "A single page of results"] +#[derive( + serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, +)] +pub struct TextToCadResultsPage { + #[doc = "list of items on this page of results"] + pub items: Vec, + #[doc = "token used to fetch the next page of results (if any)"] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub next_page: Option, +} + +impl std::fmt::Display for TextToCadResultsPage { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!( + f, + "{}", + serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)? + ) + } +} + +#[cfg(feature = "requests")] +impl crate::types::paginate::Pagination for TextToCadResultsPage { + type Item = TextToCad; + fn has_more_pages(&self) -> bool { + self.next_page.is_some() + } + + fn next_page( + &self, + req: reqwest::Request, + ) -> anyhow::Result { + let mut req = req.try_clone().ok_or_else(|| { + crate::types::error::Error::InvalidRequest(format!( + "failed to clone request: {:?}", + req + )) + })?; + req.url_mut() + .query_pairs_mut() + .append_pair("next_page", self.next_page.as_deref().unwrap_or("")); + Ok(req) + } + + fn items(&self) -> Vec { + self.items.clone() + } +} + +#[cfg(feature = "tabled")] +impl tabled::Tabled for TextToCadResultsPage { + const LENGTH: usize = 2; + fn fields(&self) -> Vec> { + vec![ + format!("{:?}", self.items).into(), + if let Some(next_page) = &self.next_page { + format!("{:?}", next_page).into() + } else { + String::new().into() + }, + ] + } + + fn headers() -> Vec> { + vec!["items".into(), "next_page".into()] + } +} + #[doc = "The valid types of angle formats."] #[derive( serde :: Serialize, diff --git a/kittycad/tests/tabled_one_of.txt b/kittycad/tests/tabled_one_of.txt index ed1746a5..0bc5167d 100644 --- a/kittycad/tests/tabled_one_of.txt +++ b/kittycad/tests/tabled_one_of.txt @@ -1,5 +1,5 @@ -+----------------+------------------+----------+------------+-------------+-----------------+ -| FileConversion | FileCenterOfMass | FileMass | FileVolume | FileDensity | FileSurfaceArea | -+----------------+------------------+----------+------------+-------------+-----------------+ -| + | | | | | | -+----------------+------------------+----------+------------+-------------+-----------------+ \ No newline at end of file ++----------------+------------------+----------+------------+-------------+-----------------+-----------+ +| FileConversion | FileCenterOfMass | FileMass | FileVolume | FileDensity | FileSurfaceArea | TextToCad | ++----------------+------------------+----------+------------+-------------+-----------------+-----------+ +| + | | | | | | | ++----------------+------------------+----------+------------+-------------+-----------------+-----------+ \ No newline at end of file diff --git a/openapitor/tests/types/kittycad.rs.gen b/openapitor/tests/types/kittycad.rs.gen index 180f2d14..3430b524 100644 --- a/openapitor/tests/types/kittycad.rs.gen +++ b/openapitor/tests/types/kittycad.rs.gen @@ -440,6 +440,31 @@ pub enum AccountProvider { Github, } +#[doc = "Human feedback on an AI response."] +#[derive( + serde :: Serialize, + serde :: Deserialize, + PartialEq, + Hash, + Debug, + Clone, + schemars :: JsonSchema, + parse_display :: FromStr, + parse_display :: Display, +)] +#[cfg_attr(feature = "clap", derive(clap::ValueEnum))] +#[cfg_attr(feature = "tabled", derive(tabled::Tabled))] +pub enum AiFeedback { + #[doc = "Thumbs up."] + #[serde(rename = "thumbs_up")] + #[display("thumbs_up")] + ThumbsUp, + #[doc = "Thumbs down."] + #[serde(rename = "thumbs_down")] + #[display("thumbs_down")] + ThumbsDown, +} + #[doc = "AI plugin api information."] #[derive( serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, @@ -1887,6 +1912,36 @@ pub enum AsyncApiCallOutput { #[doc = "The user ID of the user who created the API call."] user_id: Option, }, + #[doc = "Text to CAD."] + #[serde(rename = "text_to_cad")] + TextToCad { + #[doc = "The time and date the API call was completed."] + completed_at: Option>, + #[doc = "The time and date the API call was created."] + created_at: chrono::DateTime, + #[doc = "The error the function returned, if any."] + error: Option, + #[doc = "Feedback from the user, if any."] + feedback: Option, + #[doc = "The unique identifier of the API call.\n\nThis is the same as the API call ID."] + id: uuid::Uuid, + #[doc = "The version of the model."] + model_version: String, + #[doc = "The output format of the model."] + output_format: FileExportFormat, + #[doc = "The output of the model in the given file format the user requested, base64 encoded. The key of the map is the path of the output file."] + outputs: Option>, + #[doc = "The prompt."] + prompt: String, + #[doc = "The time and date the API call was started."] + started_at: Option>, + #[doc = "The status of the API call."] + status: ApiCallStatus, + #[doc = "The time and date the API call was last updated."] + updated_at: chrono::DateTime, + #[doc = "The user ID of the user who created the API call."] + user_id: Option, + }, } #[doc = "A single page of results"] @@ -1997,6 +2052,10 @@ pub enum AsyncApiCallType { #[serde(rename = "file_surface_area")] #[display("file_surface_area")] FileSurfaceArea, + #[doc = "Text to CAD."] + #[serde(rename = "text_to_cad")] + #[display("text_to_cad")] + TextToCad, } #[doc = "Co-ordinate axis specifier.\n\nSee [cglearn.eu] for background reading.\n\n[cglearn.eu]: https://cglearn.eu/pub/computer-graphics/introduction-to-geometry#material-coordinate-systems-1"] @@ -5373,29 +5432,6 @@ pub enum ImageFormat { Jpeg, } -#[doc = "An enumeration."] -#[derive( - serde :: Serialize, - serde :: Deserialize, - PartialEq, - Hash, - Debug, - Clone, - schemars :: JsonSchema, - parse_display :: FromStr, - parse_display :: Display, -)] -#[cfg_attr(feature = "clap", derive(clap::ValueEnum))] -#[cfg_attr(feature = "tabled", derive(tabled::Tabled))] -pub enum ImageType { - #[serde(rename = "png")] - #[display("png")] - Png, - #[serde(rename = "jpg")] - #[display("jpg")] - Jpg, -} - #[doc = "File to import into the current model"] #[derive( serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, @@ -6258,35 +6294,6 @@ impl tabled::Tabled for Mass { } } -#[derive( - serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, -)] -pub struct Mesh { - pub mesh: String, -} - -impl std::fmt::Display for Mesh { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!( - f, - "{}", - serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)? - ) - } -} - -#[cfg(feature = "tabled")] -impl tabled::Tabled for Mesh { - const LENGTH: usize = 1; - fn fields(&self) -> Vec> { - vec![self.mesh.clone().into()] - } - - fn headers() -> Vec> { - vec!["mesh".into()] - } -} - #[doc = "Jetstream statistics."] #[derive( serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, @@ -6354,8 +6361,6 @@ pub struct Metadata { pub fs: FileSystemMetadata, #[doc = "The git hash of the server."] pub git_hash: String, - #[doc = "Metadata about our point-e instance."] - pub point_e: PointEMetadata, #[doc = "Metadata about our pub-sub connection."] pub pubsub: Connection, } @@ -6372,14 +6377,13 @@ impl std::fmt::Display for Metadata { #[cfg(feature = "tabled")] impl tabled::Tabled for Metadata { - const LENGTH: usize = 6; + const LENGTH: usize = 5; fn fields(&self) -> Vec> { vec![ format!("{:?}", self.cache).into(), format!("{:?}", self.environment).into(), format!("{:?}", self.fs).into(), self.git_hash.clone().into(), - format!("{:?}", self.point_e).into(), format!("{:?}", self.pubsub).into(), ] } @@ -6390,7 +6394,6 @@ impl tabled::Tabled for Metadata { "environment".into(), "fs".into(), "git_hash".into(), - "point_e".into(), "pubsub".into(), ] } @@ -6866,6 +6869,12 @@ pub enum ModelingCmd { #[doc = "IDs of the vertices for which to obtain curve ids from"] vertex_ids: Vec, }, + #[doc = "Get vertices within a path"] + #[serde(rename = "path_get_vertex_uuids")] + PathGetVertexUuids { + #[doc = "Which path to query"] + path_id: uuid::Uuid, + }, #[doc = "Start dragging mouse."] #[serde(rename = "handle_mouse_drag_start")] HandleMouseDragStart { @@ -7361,6 +7370,12 @@ pub enum OkModelingCmdResponse { #[doc = "The response from the `PathGetCurveUuidsForVertices` command."] data: PathGetCurveUuidsForVertices, }, + #[doc = "The response from the `Path Get Vertex UUIDs` command."] + #[serde(rename = "path_get_vertex_uuids")] + PathGetVertexUuids { + #[doc = "The response from the `PathGetVertexUuids` command."] + data: PathGetVertexUuids, + }, #[doc = "The response from the `PlaneIntersectAndProject` command."] #[serde(rename = "plane_intersect_and_project")] PlaneIntersectAndProject { @@ -7714,6 +7729,37 @@ impl tabled::Tabled for PathGetInfo { } } +#[doc = "The response from the `PathGetVertexUuids` command."] +#[derive( + serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, +)] +pub struct PathGetVertexUuids { + #[doc = "The UUIDs of the vertex entities."] + pub vertex_ids: Vec, +} + +impl std::fmt::Display for PathGetVertexUuids { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!( + f, + "{}", + serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)? + ) + } +} + +#[cfg(feature = "tabled")] +impl tabled::Tabled for PathGetVertexUuids { + const LENGTH: usize = 1; + fn fields(&self) -> Vec> { + vec![format!("{:?}", self.vertex_ids).into()] + } + + fn headers() -> Vec> { + vec!["vertex_ids".into()] + } +} + #[doc = "A segment of a path. Paths are composed of many segments."] #[derive( serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, @@ -7732,16 +7778,20 @@ pub enum PathSegment { #[doc = "A circular arc segment."] #[serde(rename = "arc")] Arc { - #[doc = "Start of the arc along circle's perimeter."] + #[doc = "End of the arc along circle's perimeter, in degrees. Deprecated: use `end` instead."] angle_end: f64, - #[doc = "Start of the arc along circle's perimeter."] + #[doc = "Start of the arc along circle's perimeter, in degrees. Deprecated: use `start` instead."] angle_start: f64, #[doc = "Center of the circle"] center: Point2D, + #[doc = "End of the arc along circle's perimeter. If not given, this will use `degrees_end` instead."] + end: Option, #[doc = "Radius of the circle"] radius: f64, #[doc = "Whether or not this arc is a relative offset"] relative: bool, + #[doc = "Start of the arc along circle's perimeter. If not given, this will use `degrees_start` instead."] + start: Option, }, #[doc = "A cubic bezier curve segment. Start at the end of the current line, go through control point 1 and 2, then end at a given point."] #[serde(rename = "bezier")] @@ -8143,37 +8193,6 @@ impl tabled::Tabled for Point3D { } } -#[doc = "Metadata about our point-e instance.\n\nThis is mostly used for internal purposes and debugging."] -#[derive( - serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, -)] -pub struct PointEMetadata { - #[doc = "If the point-e service returned an ok response from ping."] - pub ok: bool, -} - -impl std::fmt::Display for PointEMetadata { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!( - f, - "{}", - serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)? - ) - } -} - -#[cfg(feature = "tabled")] -impl tabled::Tabled for PointEMetadata { - const LENGTH: usize = 1; - fn fields(&self) -> Vec> { - vec![format!("{:?}", self.ok).into()] - } - - fn headers() -> Vec> { - vec!["ok".into()] - } -} - #[doc = "The response from the `/ping` endpoint."] #[derive( serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, @@ -8922,6 +8941,219 @@ impl tabled::Tabled for TakeSnapshot { } } +#[doc = "A response from a text to CAD prompt."] +#[derive( + serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, +)] +pub struct TextToCad { + #[doc = "The time and date the API call was completed."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub completed_at: Option>, + #[doc = "The time and date the API call was created."] + pub created_at: chrono::DateTime, + #[doc = "The error the function returned, if any."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub error: Option, + #[doc = "Feedback from the user, if any."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub feedback: Option, + #[doc = "The unique identifier of the API call.\n\nThis is the same as the API call ID."] + pub id: uuid::Uuid, + #[doc = "The version of the model."] + pub model_version: String, + #[doc = "The output format of the model."] + pub output_format: FileExportFormat, + #[doc = "The output of the model in the given file format the user requested, base64 encoded. The key of the map is the path of the output file."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub outputs: Option>, + #[doc = "The prompt."] + pub prompt: String, + #[doc = "The time and date the API call was started."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub started_at: Option>, + #[doc = "The status of the API call."] + pub status: ApiCallStatus, + #[doc = "The time and date the API call was last updated."] + pub updated_at: chrono::DateTime, + #[doc = "The user ID of the user who created the API call."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub user_id: Option, +} + +impl std::fmt::Display for TextToCad { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!( + f, + "{}", + serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)? + ) + } +} + +#[cfg(feature = "tabled")] +impl tabled::Tabled for TextToCad { + const LENGTH: usize = 13; + fn fields(&self) -> Vec> { + vec![ + if let Some(completed_at) = &self.completed_at { + format!("{:?}", completed_at).into() + } else { + String::new().into() + }, + format!("{:?}", self.created_at).into(), + if let Some(error) = &self.error { + format!("{:?}", error).into() + } else { + String::new().into() + }, + if let Some(feedback) = &self.feedback { + format!("{:?}", feedback).into() + } else { + String::new().into() + }, + format!("{:?}", self.id).into(), + self.model_version.clone().into(), + format!("{:?}", self.output_format).into(), + if let Some(outputs) = &self.outputs { + format!("{:?}", outputs).into() + } else { + String::new().into() + }, + self.prompt.clone().into(), + if let Some(started_at) = &self.started_at { + format!("{:?}", started_at).into() + } else { + String::new().into() + }, + format!("{:?}", self.status).into(), + format!("{:?}", self.updated_at).into(), + if let Some(user_id) = &self.user_id { + format!("{:?}", user_id).into() + } else { + String::new().into() + }, + ] + } + + fn headers() -> Vec> { + vec![ + "completed_at".into(), + "created_at".into(), + "error".into(), + "feedback".into(), + "id".into(), + "model_version".into(), + "output_format".into(), + "outputs".into(), + "prompt".into(), + "started_at".into(), + "status".into(), + "updated_at".into(), + "user_id".into(), + ] + } +} + +#[doc = "Body for generating models from text."] +#[derive( + serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, +)] +pub struct TextToCadCreateBody { + #[doc = "The prompt for the model."] + pub prompt: String, +} + +impl std::fmt::Display for TextToCadCreateBody { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!( + f, + "{}", + serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)? + ) + } +} + +#[cfg(feature = "tabled")] +impl tabled::Tabled for TextToCadCreateBody { + const LENGTH: usize = 1; + fn fields(&self) -> Vec> { + vec![self.prompt.clone().into()] + } + + fn headers() -> Vec> { + vec!["prompt".into()] + } +} + +#[doc = "A single page of results"] +#[derive( + serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema, +)] +pub struct TextToCadResultsPage { + #[doc = "list of items on this page of results"] + pub items: Vec, + #[doc = "token used to fetch the next page of results (if any)"] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub next_page: Option, +} + +impl std::fmt::Display for TextToCadResultsPage { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!( + f, + "{}", + serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)? + ) + } +} + +#[cfg(feature = "requests")] +impl crate::types::paginate::Pagination for TextToCadResultsPage { + type Item = TextToCad; + fn has_more_pages(&self) -> bool { + self.next_page.is_some() + } + + fn next_page( + &self, + req: reqwest::Request, + ) -> anyhow::Result { + let mut req = req.try_clone().ok_or_else(|| { + crate::types::error::Error::InvalidRequest(format!( + "failed to clone request: {:?}", + req + )) + })?; + req.url_mut() + .query_pairs_mut() + .append_pair("next_page", self.next_page.as_deref().unwrap_or("")); + Ok(req) + } + + fn items(&self) -> Vec { + self.items.clone() + } +} + +#[cfg(feature = "tabled")] +impl tabled::Tabled for TextToCadResultsPage { + const LENGTH: usize = 2; + fn fields(&self) -> Vec> { + vec![ + format!("{:?}", self.items).into(), + if let Some(next_page) = &self.next_page { + format!("{:?}", next_page).into() + } else { + String::new().into() + }, + ] + } + + fn headers() -> Vec> { + vec!["items".into(), "next_page".into()] + } +} + #[doc = "The valid types of angle formats."] #[derive( serde :: Serialize, diff --git a/spec.json b/spec.json index 59fb1523..d156ea29 100644 --- a/spec.json +++ b/spec.json @@ -194,26 +194,17 @@ } } }, - "/ai/image-to-3d/{input_format}/{output_format}": { + "/ai/text-to-cad/{output_format}": { "post": { "tags": [ "ai", "beta", "hidden" ], - "summary": "Generate a 3D model from an image.", - "description": "This is an alpha endpoint. It will change in the future. The current output is honestly pretty bad. So if you find this endpoint, you get what you pay for, which currently is nothing. But in the future will be made a lot better.", - "operationId": "create_image_to_3d", + "summary": "Generate a CAD model from text.", + "description": "This operation is performed asynchronously, the `id` of the operation will be returned. You can use the `id` returned from the request to get status information about the async operation from the `/async/operations/{id}` endpoint.\nThis is an alpha endpoint. It will change in the future. The current output is honestly pretty bad. So if you find this endpoint, you get what you pay for, which currently is nothing. But in the future will be made a lot better.", + "operationId": "create_text_to_cad", "parameters": [ - { - "in": "path", - "name": "input_format", - "description": "The format of the image being converted.", - "required": true, - "schema": { - "$ref": "#/components/schemas/ImageType" - } - }, { "in": "path", "name": "output_format", @@ -226,175 +217,17 @@ ], "requestBody": { "content": { - "application/octet-stream": { + "application/json": { "schema": { - "type": "string", - "format": "binary" + "$ref": "#/components/schemas/TextToCadCreateBody" } } }, "required": true }, "responses": { - "200": { - "description": "successful operation", - "headers": { - "Access-Control-Allow-Credentials": { - "description": "Access-Control-Allow-Credentials header.", - "style": "simple", - "required": true, - "schema": { - "type": "string" - } - }, - "Access-Control-Allow-Headers": { - "description": "Access-Control-Allow-Headers header. This is a comma-separated list of headers.", - "style": "simple", - "required": true, - "schema": { - "type": "string" - } - }, - "Access-Control-Allow-Methods": { - "description": "Access-Control-Allow-Methods header.", - "style": "simple", - "required": true, - "schema": { - "type": "string" - } - }, - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin header.", - "style": "simple", - "required": true, - "schema": { - "type": "string" - } - } - }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Mesh" - } - } - } - }, - "4XX": { - "$ref": "#/components/responses/Error" - }, - "5XX": { - "$ref": "#/components/responses/Error" - } - } - }, - "options": { - "tags": [ - "hidden" - ], - "summary": "OPTIONS endpoint.", - "description": "This is necessary for some preflight requests, specifically POST, PUT, and DELETE.", - "operationId": "options_create_image_to_3d", - "parameters": [ - { - "in": "path", - "name": "input_format", - "description": "The format of the image being converted.", - "required": true, - "schema": { - "$ref": "#/components/schemas/ImageType" - } - }, - { - "in": "path", - "name": "output_format", - "description": "The format the output file should be converted to.", - "required": true, - "schema": { - "$ref": "#/components/schemas/FileExportFormat" - } - } - ], - "responses": { - "204": { - "description": "successful operation, no content", - "headers": { - "Access-Control-Allow-Credentials": { - "description": "Access-Control-Allow-Credentials header.", - "style": "simple", - "required": true, - "schema": { - "type": "string" - } - }, - "Access-Control-Allow-Headers": { - "description": "Access-Control-Allow-Headers header. This is a comma-separated list of headers.", - "style": "simple", - "required": true, - "schema": { - "type": "string" - } - }, - "Access-Control-Allow-Methods": { - "description": "Access-Control-Allow-Methods header.", - "style": "simple", - "required": true, - "schema": { - "type": "string" - } - }, - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin header.", - "style": "simple", - "required": true, - "schema": { - "type": "string" - } - } - } - }, - "4XX": { - "$ref": "#/components/responses/Error" - }, - "5XX": { - "$ref": "#/components/responses/Error" - } - } - } - }, - "/ai/text-to-3d/{output_format}": { - "post": { - "tags": [ - "ai", - "beta", - "hidden" - ], - "summary": "Generate a 3D model from text.", - "description": "This is an alpha endpoint. It will change in the future. The current output is honestly pretty bad. So if you find this endpoint, you get what you pay for, which currently is nothing. But in the future will be made a lot better.", - "operationId": "create_text_to_3d", - "parameters": [ - { - "in": "path", - "name": "output_format", - "description": "The format the output file should be converted to.", - "required": true, - "schema": { - "$ref": "#/components/schemas/FileExportFormat" - } - }, - { - "in": "query", - "name": "prompt", - "description": "The prompt for the model.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "successful operation", + "201": { + "description": "successful creation", "headers": { "Access-Control-Allow-Credentials": { "description": "Access-Control-Allow-Credentials header.", @@ -432,7 +265,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Mesh" + "$ref": "#/components/schemas/TextToCad" } } } @@ -451,7 +284,7 @@ ], "summary": "OPTIONS endpoint.", "description": "This is necessary for some preflight requests, specifically POST, PUT, and DELETE.", - "operationId": "options_create_text_to_3d", + "operationId": "options_create_text_to_cad", "parameters": [ { "in": "path", @@ -6401,6 +6234,245 @@ } } }, + "/user/text-to-cad": { + "get": { + "tags": [ + "ai", + "beta", + "hidden" + ], + "summary": "List text-to-CAD models you've generated.", + "description": "This endpoint requires authentication by any KittyCAD user. It returns the text-to-CAD models for the authenticated user.\nThe text-to-CAD models are returned in order of creation, with the most recently created text-to-CAD models first.", + "operationId": "list_text_to_cad_models_for_user", + "parameters": [ + { + "in": "query", + "name": "limit", + "description": "Maximum number of items returned by a single call", + "schema": { + "nullable": true, + "type": "integer", + "format": "uint32", + "minimum": 1 + } + }, + { + "in": "query", + "name": "page_token", + "description": "Token returned by previous call to retrieve the subsequent page", + "schema": { + "nullable": true, + "type": "string" + } + }, + { + "in": "query", + "name": "sort_by", + "schema": { + "$ref": "#/components/schemas/CreatedAtSortMode" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "headers": { + "Access-Control-Allow-Credentials": { + "description": "Access-Control-Allow-Credentials header.", + "style": "simple", + "required": true, + "schema": { + "type": "string" + } + }, + "Access-Control-Allow-Headers": { + "description": "Access-Control-Allow-Headers header. This is a comma-separated list of headers.", + "style": "simple", + "required": true, + "schema": { + "type": "string" + } + }, + "Access-Control-Allow-Methods": { + "description": "Access-Control-Allow-Methods header.", + "style": "simple", + "required": true, + "schema": { + "type": "string" + } + }, + "Access-Control-Allow-Origin": { + "description": "Access-Control-Allow-Origin header.", + "style": "simple", + "required": true, + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TextToCadResultsPage" + } + } + } + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + }, + "x-dropshot-pagination": { + "required": [] + } + } + }, + "/user/text-to-cad/{id}": { + "post": { + "tags": [ + "ai", + "beta", + "hidden" + ], + "summary": "Give feedback to a specific text-to-CAD response.", + "description": "This endpoint requires authentication by any KittyCAD user. The user must be the owner of the text-to-CAD model, in order to give feedback.", + "operationId": "create_text_to_cad_model_feedback", + "parameters": [ + { + "in": "path", + "name": "id", + "description": "The id of the model to give feedback to.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "in": "query", + "name": "feedback", + "description": "The feedback.", + "required": true, + "schema": { + "$ref": "#/components/schemas/AiFeedback" + } + } + ], + "responses": { + "204": { + "description": "resource updated", + "headers": { + "Access-Control-Allow-Credentials": { + "description": "Access-Control-Allow-Credentials header.", + "style": "simple", + "required": true, + "schema": { + "type": "string" + } + }, + "Access-Control-Allow-Headers": { + "description": "Access-Control-Allow-Headers header. This is a comma-separated list of headers.", + "style": "simple", + "required": true, + "schema": { + "type": "string" + } + }, + "Access-Control-Allow-Methods": { + "description": "Access-Control-Allow-Methods header.", + "style": "simple", + "required": true, + "schema": { + "type": "string" + } + }, + "Access-Control-Allow-Origin": { + "description": "Access-Control-Allow-Origin header.", + "style": "simple", + "required": true, + "schema": { + "type": "string" + } + } + } + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + } + }, + "options": { + "tags": [ + "hidden" + ], + "summary": "OPTIONS endpoint.", + "description": "This is necessary for some preflight requests, specifically POST, PUT, and DELETE.", + "operationId": "options_create_text_to_cad_model_feedback", + "parameters": [ + { + "in": "path", + "name": "id", + "description": "The id of the model to give feedback to.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "successful operation, no content", + "headers": { + "Access-Control-Allow-Credentials": { + "description": "Access-Control-Allow-Credentials header.", + "style": "simple", + "required": true, + "schema": { + "type": "string" + } + }, + "Access-Control-Allow-Headers": { + "description": "Access-Control-Allow-Headers header. This is a comma-separated list of headers.", + "style": "simple", + "required": true, + "schema": { + "type": "string" + } + }, + "Access-Control-Allow-Methods": { + "description": "Access-Control-Allow-Methods header.", + "style": "simple", + "required": true, + "schema": { + "type": "string" + } + }, + "Access-Control-Allow-Origin": { + "description": "Access-Control-Allow-Origin header.", + "style": "simple", + "required": true, + "schema": { + "type": "string" + } + } + } + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + } + } + }, "/users": { "get": { "tags": [ @@ -6982,6 +7054,25 @@ } ] }, + "AiFeedback": { + "description": "Human feedback on an AI response.", + "oneOf": [ + { + "description": "Thumbs up.", + "type": "string", + "enum": [ + "thumbs_up" + ] + }, + { + "description": "Thumbs down.", + "type": "string", + "enum": [ + "thumbs_down" + ] + } + ] + }, "AiPluginApi": { "description": "AI plugin api information.", "type": "object", @@ -8290,7 +8381,102 @@ "type": { "type": "string", "enum": [ - "file_density" + "file_density" + ] + }, + "updated_at": { + "title": "DateTime", + "description": "The time and date the API call was last updated.", + "type": "string", + "format": "date-time" + }, + "user_id": { + "description": "The user ID of the user who created the API call.", + "type": "string" + } + }, + "required": [ + "created_at", + "id", + "material_mass_unit", + "output_unit", + "src_format", + "status", + "type", + "updated_at" + ] + }, + { + "description": "A file surface area.", + "type": "object", + "properties": { + "completed_at": { + "nullable": true, + "title": "DateTime", + "description": "The time and date the API call was completed.", + "type": "string", + "format": "date-time" + }, + "created_at": { + "title": "DateTime", + "description": "The time and date the API call was created.", + "type": "string", + "format": "date-time" + }, + "error": { + "nullable": true, + "description": "The error the function returned, if any.", + "type": "string" + }, + "id": { + "description": "The unique identifier of the API call.\n\nThis is the same as the API call ID.", + "allOf": [ + { + "$ref": "#/components/schemas/Uuid" + } + ] + }, + "output_unit": { + "description": "The output unit for the surface area.", + "allOf": [ + { + "$ref": "#/components/schemas/UnitArea" + } + ] + }, + "src_format": { + "description": "The source format of the file.", + "allOf": [ + { + "$ref": "#/components/schemas/FileImportFormat" + } + ] + }, + "started_at": { + "nullable": true, + "title": "DateTime", + "description": "The time and date the API call was started.", + "type": "string", + "format": "date-time" + }, + "status": { + "description": "The status of the API call.", + "allOf": [ + { + "$ref": "#/components/schemas/ApiCallStatus" + } + ] + }, + "surface_area": { + "nullable": true, + "description": "The resulting surface area.", + "type": "number", + "format": "double" + }, + "type": { + "type": "string", + "enum": [ + "file_surface_area" ] }, "updated_at": { @@ -8307,7 +8493,6 @@ "required": [ "created_at", "id", - "material_mass_unit", "output_unit", "src_format", "status", @@ -8316,7 +8501,7 @@ ] }, { - "description": "A file surface area.", + "description": "Text to CAD.", "type": "object", "properties": { "completed_at": { @@ -8337,30 +8522,48 @@ "description": "The error the function returned, if any.", "type": "string" }, - "id": { - "description": "The unique identifier of the API call.\n\nThis is the same as the API call ID.", + "feedback": { + "nullable": true, + "description": "Feedback from the user, if any.", "allOf": [ { - "$ref": "#/components/schemas/Uuid" + "$ref": "#/components/schemas/AiFeedback" } ] }, - "output_unit": { - "description": "The output unit for the surface area.", + "id": { + "description": "The unique identifier of the API call.\n\nThis is the same as the API call ID.", "allOf": [ { - "$ref": "#/components/schemas/UnitArea" + "$ref": "#/components/schemas/Uuid" } ] }, - "src_format": { - "description": "The source format of the file.", + "model_version": { + "description": "The version of the model.", + "type": "string" + }, + "output_format": { + "description": "The output format of the model.", "allOf": [ { - "$ref": "#/components/schemas/FileImportFormat" + "$ref": "#/components/schemas/FileExportFormat" } ] }, + "outputs": { + "description": "The output of the model in the given file format the user requested, base64 encoded. The key of the map is the path of the output file.", + "type": "object", + "additionalProperties": { + "title": "String", + "type": "string", + "format": "byte" + } + }, + "prompt": { + "description": "The prompt.", + "type": "string" + }, "started_at": { "nullable": true, "title": "DateTime", @@ -8376,16 +8579,10 @@ } ] }, - "surface_area": { - "nullable": true, - "description": "The resulting surface area.", - "type": "number", - "format": "double" - }, "type": { "type": "string", "enum": [ - "file_surface_area" + "text_to_cad" ] }, "updated_at": { @@ -8402,8 +8599,9 @@ "required": [ "created_at", "id", - "output_unit", - "src_format", + "model_version", + "output_format", + "prompt", "status", "type", "updated_at" @@ -8476,6 +8674,13 @@ "enum": [ "file_surface_area" ] + }, + { + "description": "Text to CAD.", + "type": "string", + "enum": [ + "text_to_cad" + ] } ] }, @@ -10847,14 +11052,6 @@ } ] }, - "ImageType": { - "description": "An enumeration.", - "type": "string", - "enum": [ - "png", - "jpg" - ] - }, "ImportFile": { "description": "File to import into the current model", "type": "object", @@ -11516,17 +11713,6 @@ "output_unit" ] }, - "Mesh": { - "type": "object", - "properties": { - "mesh": { - "type": "string" - } - }, - "required": [ - "mesh" - ] - }, "MetaClusterInfo": { "description": "Jetstream statistics.", "type": "object", @@ -11581,14 +11767,6 @@ "description": "The git hash of the server.", "type": "string" }, - "point_e": { - "description": "Metadata about our point-e instance.", - "allOf": [ - { - "$ref": "#/components/schemas/PointEMetadata" - } - ] - }, "pubsub": { "description": "Metadata about our pub-sub connection.", "allOf": [ @@ -11603,7 +11781,6 @@ "environment", "fs", "git_hash", - "point_e", "pubsub" ] }, @@ -13197,6 +13374,27 @@ "vertex_ids" ] }, + { + "description": "Get vertices within a path", + "type": "object", + "properties": { + "path_id": { + "description": "Which path to query", + "type": "string", + "format": "uuid" + }, + "type": { + "type": "string", + "enum": [ + "path_get_vertex_uuids" + ] + } + }, + "required": [ + "path_id", + "type" + ] + }, { "description": "Start dragging mouse.", "type": "object", @@ -14195,6 +14393,25 @@ "type" ] }, + { + "description": "The response from the `Path Get Vertex UUIDs` command.", + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/PathGetVertexUuids" + }, + "type": { + "type": "string", + "enum": [ + "path_get_vertex_uuids" + ] + } + }, + "required": [ + "data", + "type" + ] + }, { "description": "The response from the `PlaneIntersectAndProject` command.", "type": "object", @@ -14822,6 +15039,23 @@ "segments" ] }, + "PathGetVertexUuids": { + "description": "The response from the `PathGetVertexUuids` command.", + "type": "object", + "properties": { + "vertex_ids": { + "description": "The UUIDs of the vertex entities.", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + "required": [ + "vertex_ids" + ] + }, "PathSegment": { "description": "A segment of a path. Paths are composed of many segments.", "oneOf": [ @@ -14859,12 +15093,14 @@ "type": "object", "properties": { "angle_end": { - "description": "Start of the arc along circle's perimeter.", + "deprecated": true, + "description": "End of the arc along circle's perimeter, in degrees. Deprecated: use `end` instead.", "type": "number", "format": "double" }, "angle_start": { - "description": "Start of the arc along circle's perimeter.", + "deprecated": true, + "description": "Start of the arc along circle's perimeter, in degrees. Deprecated: use `start` instead.", "type": "number", "format": "double" }, @@ -14876,6 +15112,15 @@ } ] }, + "end": { + "nullable": true, + "description": "End of the arc along circle's perimeter. If not given, this will use `degrees_end` instead.", + "allOf": [ + { + "$ref": "#/components/schemas/Angle" + } + ] + }, "radius": { "description": "Radius of the circle", "type": "number", @@ -14885,6 +15130,15 @@ "description": "Whether or not this arc is a relative offset", "type": "boolean" }, + "start": { + "nullable": true, + "description": "Start of the arc along circle's perimeter. If not given, this will use `degrees_start` instead.", + "allOf": [ + { + "$ref": "#/components/schemas/Angle" + } + ] + }, "type": { "type": "string", "enum": [ @@ -15222,19 +15476,6 @@ "z" ] }, - "PointEMetadata": { - "description": "Metadata about our point-e instance.\n\nThis is mostly used for internal purposes and debugging.", - "type": "object", - "properties": { - "ok": { - "description": "If the point-e service returned an ok response from ping.", - "type": "boolean" - } - }, - "required": [ - "ok" - ] - }, "Pong": { "description": "The response from the `/ping` endpoint.", "type": "object", @@ -15660,6 +15901,140 @@ "contents" ] }, + "TextToCad": { + "description": "A response from a text to CAD prompt.", + "type": "object", + "properties": { + "completed_at": { + "nullable": true, + "title": "DateTime", + "description": "The time and date the API call was completed.", + "type": "string", + "format": "date-time" + }, + "created_at": { + "title": "DateTime", + "description": "The time and date the API call was created.", + "type": "string", + "format": "date-time" + }, + "error": { + "nullable": true, + "description": "The error the function returned, if any.", + "type": "string" + }, + "feedback": { + "nullable": true, + "description": "Feedback from the user, if any.", + "allOf": [ + { + "$ref": "#/components/schemas/AiFeedback" + } + ] + }, + "id": { + "description": "The unique identifier of the API call.\n\nThis is the same as the API call ID.", + "allOf": [ + { + "$ref": "#/components/schemas/Uuid" + } + ] + }, + "model_version": { + "description": "The version of the model.", + "type": "string" + }, + "output_format": { + "description": "The output format of the model.", + "allOf": [ + { + "$ref": "#/components/schemas/FileExportFormat" + } + ] + }, + "outputs": { + "description": "The output of the model in the given file format the user requested, base64 encoded. The key of the map is the path of the output file.", + "type": "object", + "additionalProperties": { + "title": "String", + "type": "string", + "format": "byte" + } + }, + "prompt": { + "description": "The prompt.", + "type": "string" + }, + "started_at": { + "nullable": true, + "title": "DateTime", + "description": "The time and date the API call was started.", + "type": "string", + "format": "date-time" + }, + "status": { + "description": "The status of the API call.", + "allOf": [ + { + "$ref": "#/components/schemas/ApiCallStatus" + } + ] + }, + "updated_at": { + "title": "DateTime", + "description": "The time and date the API call was last updated.", + "type": "string", + "format": "date-time" + }, + "user_id": { + "description": "The user ID of the user who created the API call.", + "type": "string" + } + }, + "required": [ + "created_at", + "id", + "model_version", + "output_format", + "prompt", + "status", + "updated_at" + ] + }, + "TextToCadCreateBody": { + "description": "Body for generating models from text.", + "type": "object", + "properties": { + "prompt": { + "description": "The prompt for the model.", + "type": "string" + } + }, + "required": [ + "prompt" + ] + }, + "TextToCadResultsPage": { + "description": "A single page of results", + "type": "object", + "properties": { + "items": { + "description": "list of items on this page of results", + "type": "array", + "items": { + "$ref": "#/components/schemas/TextToCad" + } + }, + "next_page": { + "nullable": true, + "description": "token used to fetch the next page of results (if any)", + "type": "string" + } + }, + "required": [ + "items" + ] + }, "UnitAngle": { "description": "The valid types of angle formats.", "oneOf": [