Create Optimization
This example demonstrates how to create and run an optimization on an existing G-Code in the Helio Additive platform. Optimizations adjust print speeds and other parameters to improve thermal quality and print outcomes.
GraphQL Operations
Section titled “GraphQL Operations”Create the following GraphQL files, then run your language’s codegen tool to generate the types.
mutation CreateOptimization($input: CreateOptimizationInput!) { createOptimization(input: $input) { id name }}query Optimization($id: ID!) { optimization(id: $id) { id name status progress qualityMeanDelta qualityStdDelta qualityMeanImprovement qualityStdImprovement optimizedGcodeUrl originalThermalIndexStatistics { thermalIndexMean thermalIndexStd } optimizedThermalIndexStatistics { optimizedThermalIndexMean optimizedThermalIndexStd } }}API Reference:
- CreateOptimizationInput - Input parameters for creating an optimization
- OptimizationSettingsInput - Advanced optimization settings
- SimulationStatus enum - Possible optimization status values
- Optimization type - Full optimization object structure
- Optimizer enum - Available optimizer algorithms
Code Example
Section titled “Code Example”-
Setup the client and configuration
index.ts import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";import { CreateOptimizationDocument } from "./mutations/__generated/CreateOptimization.generated";import { OptimizationDocument } from "./queries/__generated/Optimization.generated";// Load PAT from environmentconst PAT = process.env.PAT;if (!PAT) {throw new Error("PAT environment variable is required");}// Create Apollo Clientconst client = new ApolloClient({cache: new InMemoryCache(),link: new HttpLink({uri: "https://api.helioadditive.com/graphql",headers: {"Content-Type": "application/json",Authorization: `Bearer ${PAT}`,},}),});// Replace with an actual G-Code ID from your accountconst GCODE_ID = process.env.GCODE_ID ?? "your-gcode-id";main.py import asyncioimport osimport timeimport httpxfrom client.client import Client# Load PAT from environmentPAT = os.environ.get("PAT")if not PAT:raise ValueError("PAT environment variable is required")# Replace with an actual G-Code ID from your accountGCODE_ID = os.environ.get("GCODE_ID", "your-gcode-id")# Create GraphQL clientheaders = {"Authorization": f"Bearer {PAT}"}graphql_client = Client(url="https://api.helioadditive.com/graphql",headers=headers,http_client=httpx.AsyncClient(headers=headers, timeout=60))src/main.rs use graphql_client::{GraphQLQuery, Response};use reqwest::header::{AUTHORIZATION, CONTENT_TYPE};use std::time::{Duration, SystemTime, UNIX_EPOCH};#[derive(GraphQLQuery)]#[graphql(schema_path = "schema.graphqls",query_path = "mutations/CreateOptimization.graphql",response_derives = "Debug")]struct CreateOptimization;#[derive(GraphQLQuery)]#[graphql(schema_path = "schema.graphqls",query_path = "queries/Optimization.graphql",response_derives = "Debug")]struct Optimization;// Load from environment in main()let pat = std::env::var("PAT").expect("PAT environment variable must be set");let gcode_id = std::env::var("GCODE_ID").unwrap_or_else(|_| "your-gcode-id".to_string());src/main.cpp #include <iostream>#include <string>#include <thread>#include <chrono>#include <cstdlib>#include <cpr/cpr.h>#include <boost/json.hpp>#include "CreateOptimizationClient.h"#include "OptimizationClient.h"#include "graphqlservice/GraphQLResponse.h"#include "graphqlservice/JSONResponse.h"namespace CreateOptimization = graphql::client::mutation::CreateOptimization;namespace Optimization = graphql::client::query::Optimization;// Helper function to send GraphQL HTTP requestsgraphql::response::Value sendHttpRequest(const std::string& query,graphql::response::Value& variables,const std::string& pat) {std::string body = boost::json::serialize(boost::json::object{{"query", query},{"variables", boost::json::parse(graphql::response::toJSON(std::move(variables))).as_object()}});auto response = cpr::Post(cpr::Url{"https://api.helioadditive.com/graphql"},cpr::Header{{"Content-Type", "application/json"},{"Authorization", "Bearer " + pat}},cpr::Body{body});return graphql::response::parseJSON(boost::json::serialize(boost::json::parse(response.text).as_object()["data"].as_object()));}// Load PAT from environment in main()const char* pat_env = std::getenv("PAT");if (!pat_env) {std::cerr << "PAT environment variable is required" << std::endl;return 1;}std::string pat(pat_env);// Replace with an actual G-Code ID from your accountconst char* gcode_env = std::getenv("GCODE_ID");std::string gcodeId = gcode_env ? gcode_env : "your-gcode-id"; -
Create the optimization
Create a new optimization for the specified G-Code. You can optionally specify optimization settings like layer ranges.
async function createOptimizationEntry(gcodeId: string, name: string) {const { data, error } = await client.mutate({mutation: CreateOptimizationDocument,variables: {input: {gcodeId: gcodeId,name: name,// Optional: specify optimization settingsoptimizationSettings: {layersToOptimize: [{ fromLayer: 1, toLayer: 100 }],},},},errorPolicy: "all",});if (error) {throw new Error(`Failed to create optimization: ${error.message}`);}const optimizationId = data?.createOptimization?.id;if (!optimizationId) {throw new Error("Failed to create optimization");}return optimizationId;}async def create_optimization_entry(gcode_id: str, name: str) -> str:"""Create an optimization and return its ID."""result = await graphql_client.create_optimization(input={"gcodeId": gcode_id,"name": name,# Optional: specify optimization settings"optimizationSettings": {"layersToOptimize": [{"fromLayer": 1, "toLayer": 100}],},})return result.idasync fn create_optimization_entry(client: &reqwest::Client,pat: &str,gcode_id: &str,name: &str,) -> Result<String, Box<dyn std::error::Error>> {let variables = create_optimization::Variables {input: create_optimization::CreateOptimizationInput {gcode_id: gcode_id.to_string(),name: name.to_string(),optimization_settings: Some(create_optimization::OptimizationSettingsInput {layers_to_optimize: Some(vec![create_optimization::LayerRangeInput {from_layer: 1,to_layer: 100,}]),min_velocity: None,max_velocity: None,tolerance: None,max_iterations: None,optimizer: None,optimize_outerwall: None,residual_strategy_settings: None,reduction_strategy_settings: None,}),room_temperature: None,stabilized_air_temperature: None,constant_nozzle_temperature: None,constant_platform_temperature: None,constant_fan_speed: None,},};let response = client.post("https://api.helioadditive.com/graphql").header(CONTENT_TYPE, "application/json").header(AUTHORIZATION, format!("Bearer {}", pat)).json(&CreateOptimization::build_query(variables)).send().await?;let body: Response<create_optimization::ResponseData> = response.json().await?;Ok(body.data.unwrap().create_optimization.id)}std::string createOptimizationEntry(const std::string& gcodeId,const std::string& name,const std::string& pat) {const std::string query = CreateOptimization::GetRequestText();graphql::response::Value variables = CreateOptimization::serializeVariables(CreateOptimization::Variables{.input = CreateOptimization::CreateOptimizationInput{.gcodeId = gcodeId,.name = name,.optimizationSettings = CreateOptimization::OptimizationSettingsInput{.layersToOptimize = std::vector<CreateOptimization::LayerRangeInput>{CreateOptimization::LayerRangeInput{.fromLayer = 1, .toLayer = 100}}}}});auto response = CreateOptimization::parseResponse(sendHttpRequest(query, variables, pat));return response.createOptimization.id;} -
Poll and wait for optimization to complete
After creation, the optimization needs to run. Poll the status until it’s finished.
async function waitForOptimizationComplete(optimizationId: string): Promise<void> {return new Promise((resolve, reject) => {const checkStatus = async () => {const { data } = await client.query({query: OptimizationDocument,variables: { id: optimizationId },fetchPolicy: "no-cache",});const status = data?.optimization?.status;const progress = data?.optimization?.progress;console.log(`Optimization status: ${status}, progress: ${progress}%`);if (status === "FINISHED") {console.log(`Optimized G-Code URL: ${data?.optimization?.optimizedGcodeUrl}`);console.log(`Quality Mean Improvement: ${data?.optimization?.qualityMeanImprovement}`);console.log(`Quality Std Improvement: ${data?.optimization?.qualityStdImprovement}`);resolve();} else if (status === "FAILED") {reject(new Error("Optimization failed"));} else {// Poll every 2 secondssetTimeout(checkStatus, 2000);}};checkStatus();});}async def wait_for_optimization_complete(optimization_id: str) -> None:"""Poll until the optimization is complete."""while True:result = await graphql_client.optimization(id=optimization_id)status = result.statusprogress = result.progressprint(f"Optimization status: {status}, progress: {progress}%")if status == "FINISHED":print(f"Optimized G-Code URL: {result.optimized_gcode_url}")print(f"Quality Mean Improvement: {result.quality_mean_improvement}")print(f"Quality Std Improvement: {result.quality_std_improvement}")returnelif status == "FAILED":raise Exception("Optimization failed")await asyncio.sleep(2)async fn wait_for_optimization_complete(client: &reqwest::Client,pat: &str,optimization_id: &str,) -> Result<(), Box<dyn std::error::Error>> {loop {let variables = optimization::Variables {id: optimization_id.to_string(),};let response = client.post("https://api.helioadditive.com/graphql").header(CONTENT_TYPE, "application/json").header(AUTHORIZATION, format!("Bearer {}", pat)).json(&Optimization::build_query(variables)).send().await?;let body: Response<optimization::ResponseData> = response.json().await?;let opt = body.data.unwrap().optimization.unwrap();println!("Optimization status: {:?}, progress: {}%", opt.status, opt.progress);match opt.status.as_str() {"FINISHED" => {if let Some(url) = opt.optimized_gcode_url {println!("Optimized G-Code URL: {}", url);}if let Some(improvement) = opt.quality_mean_improvement {println!("Quality Mean Improvement: {}", improvement);}if let Some(improvement) = opt.quality_std_improvement {println!("Quality Std Improvement: {}", improvement);}return Ok(());}"FAILED" => return Err("Optimization failed".into()),_ => tokio::time::sleep(Duration::from_secs(2)).await,}}}void waitForOptimizationComplete(const std::string& optimizationId, const std::string& pat) {while (true) {const std::string query = Optimization::GetRequestText();graphql::response::Value variables = Optimization::serializeVariables(Optimization::Variables{.id = optimizationId});auto response = Optimization::parseResponse(sendHttpRequest(query, variables, pat));std::string status = response.optimization->status;int progress = response.optimization->progress;std::cout << "Optimization status: " << status << ", progress: " << progress << "%" << std::endl;if (status == "FINISHED") {if (response.optimization->optimizedGcodeUrl) {std::cout << "Optimized G-Code URL: " << *response.optimization->optimizedGcodeUrl << std::endl;}if (response.optimization->qualityMeanImprovement) {std::cout << "Quality Mean Improvement: " << *response.optimization->qualityMeanImprovement << std::endl;}if (response.optimization->qualityStdImprovement) {std::cout << "Quality Std Improvement: " << *response.optimization->qualityStdImprovement << std::endl;}return;} else if (status == "FAILED") {throw std::runtime_error("Optimization failed");}// Poll every 2 secondsstd::this_thread::sleep_for(std::chrono::seconds(2));}} -
Put it all together
Combine all the steps into a single function and run it.
async function createOptimization(gcodeId: string, name: string) {console.log(`Creating optimization for G-Code: ${gcodeId}`);// Create the optimizationconst optimizationId = await createOptimizationEntry(gcodeId, name);console.log(`Optimization created with ID: ${optimizationId}`);// Wait for optimization to completeconsole.log("Waiting for optimization to complete...");await waitForOptimizationComplete(optimizationId);console.log("Optimization finished!");return optimizationId;}// Example usageconst optimizationName = `optimization-${Date.now()}`;createOptimization(GCODE_ID, optimizationName).then((id) => console.log(`Successfully completed optimization: ${id}`)).catch(console.error);async def create_optimization(gcode_id: str, name: str) -> str:"""Create and wait for an optimization to complete."""print(f"Creating optimization for G-Code: {gcode_id}")# Create the optimizationoptimization_id = await create_optimization_entry(gcode_id, name)print(f"Optimization created with ID: {optimization_id}")# Wait for optimization to completeprint("Waiting for optimization to complete...")await wait_for_optimization_complete(optimization_id)print("Optimization finished!")return optimization_idif __name__ == "__main__":optimization_name = f"optimization-{int(time.time())}"optimization_id = asyncio.run(create_optimization(GCODE_ID, optimization_name))print(f"Successfully completed optimization: {optimization_id}")#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> {let pat = std::env::var("PAT").expect("PAT environment variable must be set");let gcode_id = std::env::var("GCODE_ID").unwrap_or_else(|_| "your-gcode-id".to_string());let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();let optimization_name = format!("optimization-{}", timestamp);let client = reqwest::Client::new();println!("Creating optimization for G-Code: {}", gcode_id);// Create the optimizationlet optimization_id = create_optimization_entry(&client, &pat, &gcode_id, &optimization_name).await?;println!("Optimization created with ID: {}", optimization_id);// Wait for optimization to completeprintln!("Waiting for optimization to complete...");wait_for_optimization_complete(&client, &pat, &optimization_id).await?;println!("Optimization finished!");println!("Successfully completed optimization: {}", optimization_id);Ok(())}std::string createOptimization(const std::string& gcodeId,const std::string& name,const std::string& pat) {std::cout << "Creating optimization for G-Code: " << gcodeId << std::endl;// Create the optimizationstd::string optimizationId = createOptimizationEntry(gcodeId, name, pat);std::cout << "Optimization created with ID: " << optimizationId << std::endl;// Wait for optimization to completestd::cout << "Waiting for optimization to complete..." << std::endl;waitForOptimizationComplete(optimizationId, pat);std::cout << "Optimization finished!" << std::endl;return optimizationId;}int main() {const char* pat_env = std::getenv("PAT");if (!pat_env) {std::cerr << "PAT environment variable is required" << std::endl;return 1;}std::string pat(pat_env);const char* gcode_env = std::getenv("GCODE_ID");std::string gcodeId = gcode_env ? gcode_env : "your-gcode-id";auto timestamp = std::chrono::system_clock::now().time_since_epoch().count();std::string optimizationName = "optimization-" + std::to_string(timestamp);try {std::string optimizationId = createOptimization(gcodeId, optimizationName, pat);std::cout << "Successfully completed optimization: " << optimizationId << std::endl;} catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;return 1;}return 0;}
Running the Example
Section titled “Running the Example”-
Create a
.env.localfile with your PAT and G-Code ID:Terminal window PAT="your-personal-access-token"GCODE_ID="your-gcode-id" -
Update the
GCODE_IDwith a valid G-Code ID from your account that is inREADYstatus. -
Run the example:
Terminal window bun run index.tsTerminal window uv run main.pyTerminal window cargo runTerminal window mkdir build && cd buildcmake .. -DVCPKG_DIR=$(pwd)/../vcpkg/installed/arm64-osxmake./CreateOptimizationExample