From ae537af469e02f6a8bd5081be56e483f9372396a Mon Sep 17 00:00:00 2001 From: DjKesu Date: Sun, 19 May 2024 11:48:42 -0700 Subject: [PATCH] added image check --- api.py | 9 ++ generate.py | 31 +++++-- ui/app/components/cad-viewer.tsx | 138 +++++++++++++------------------ ui/app/page.tsx | 130 +++++++++++++++-------------- 4 files changed, 159 insertions(+), 149 deletions(-) diff --git a/api.py b/api.py index 1a8ca6a..0b14301 100644 --- a/api.py +++ b/api.py @@ -24,6 +24,15 @@ def cad(): generation_id, iteration = generate_scad(query) return {"id": generation_id, "iteration": iteration, "shapes": []} +@cross_origin() +@app.route("/models/generated/", methods=["GET"]) +def get_iterations(generation_id): + directory = os.path.join("generated", str(generation_id)) + if not os.path.exists(directory): + abort(404, description="Resource not found") + iterations = [name for name in os.listdir(directory) if os.path.isdir(os.path.join(directory, name))] + return jsonify(iterations) + @cross_origin() @app.route("/models/generated///output.stl") def serve_stl(generation_id, iteration): diff --git a/generate.py b/generate.py index 3f11145..3289890 100644 --- a/generate.py +++ b/generate.py @@ -275,13 +275,32 @@ def get_last_generated_scad(generation_id: str): # creates .scad, .png, and .stl files # places them in /generated/{generation_id}/{iteration}/output.{filetype} def render_scad(code: str, generation_id: str, iteration: int) -> bool: - os.system(f"mkdir -p generated/{generation_id}/{iteration}") - os.system(f"echo '{code}' > generated/{generation_id}/{iteration}/output.scad") - png_command = f"openscad -o generated/{generation_id}/{iteration}/output.png generated/{generation_id}/{iteration}/output.scad" - stl_command = f"openscad -o generated/{generation_id}/{iteration}/output.stl generated/{generation_id}/{iteration}/output.scad" - png_success = os.system(png_command) == 0 + # Ensure the output directory exists + output_dir = f"generated/{generation_id}/{iteration}" + os.makedirs(output_dir, exist_ok=True) + + # Write the SCAD code to a file + scad_file = f"{output_dir}/output.scad" + with open(scad_file, 'w') as file: + file.write(code) + + # Generate STL file + stl_command = f"openscad -o {output_dir}/output.stl {scad_file}" stl_success = os.system(stl_command) == 0 - return png_success and stl_success + + # Call the bash script to generate images + bash_script = "./scad2image.sh" + bash_command = f"{bash_script} {scad_file}" + png_success = os.system(bash_command) == 0 + + # Check if the final combined image is created + final_image_path = f"{output_dir}/renders/final_image.png" + if png_success and os.path.exists(final_image_path): + # Move the final image to the output directory + os.rename(final_image_path, f"{output_dir}/output.png") + return stl_success + else: + return False # Generates OpenSCAD code given an initial prompt diff --git a/ui/app/components/cad-viewer.tsx b/ui/app/components/cad-viewer.tsx index 3548f3f..62ef078 100644 --- a/ui/app/components/cad-viewer.tsx +++ b/ui/app/components/cad-viewer.tsx @@ -1,93 +1,71 @@ -"use client" +"use client"; -import { useEffect, useRef } from 'react' -import "../../dist/three-cad-viewer/three-cad-viewer.css" -import { Viewer } from "../../dist/three-cad-viewer/three-cad-viewer.esm.js" +import { useEffect, useRef } from 'react'; +import "../../dist/three-cad-viewer/three-cad-viewer.css"; +import { Viewer, Display } from "../../dist/three-cad-viewer/three-cad-viewer.esm.js"; -function nc(change) {} +function nc(change) { + console.log("NOTIFY:", JSON.stringify(change, null, 2)); +} export interface CadViewerProps { - cadShapes?: any, - stlFileUrl?: string + cadShapes?: any; + stlFileUrl?: string; } -export default function CadViewer({ cadShapes = [], stlFileUrl }: CadViewerProps) { - const ref = useRef(null) - const { innerWidth: width, innerHeight: height } = window - - const viewerOptions = { - theme: "light", - ortho: true, - control: "trackball", // "orbit", - normalLen: 0, - cadWidth: width, - height: height * 0.85, - ticks: 10, - ambientIntensity: 0.9, - directIntensity: 0.12, - transparent: false, - blackEdges: false, - axes: true, - grid: [false, false, false], - timeit: false, - rotateSpeed: 1, - tools: false, - glass: false - } - - const renderOptions = { - ambientIntensity: 1.0, - directIntensity: 1.1, - metalness: 0.30, - roughness: 0.65, - edgeColor: 0x707070, - defaultOpacity: 0.5, - normalLen: 0, - up: "Z" - } - - useEffect(() => { - const container = ref.current +export default function CadViewer({ cadShapes = {}, stlFileUrl }: CadViewerProps) { + const ref = useRef(null); + const { innerWidth: width, innerHeight: height } = window; - if (stlFileUrl) { - const viewer = new Viewer(container, viewerOptions, nc) - fetch(stlFileUrl) - .then(response => response.arrayBuffer()) - .then(data => { - const blob = new Blob([data], { type: 'application/octet-stream' }) - const url = URL.createObjectURL(blob) - viewer.clear() - viewer.loadSTL(url) - viewer.render() - }) - .catch(error => console.error(error)) - } - }, [stlFileUrl]) + const viewerOptions = { + theme: "light", + ortho: true, + control: "trackball", + normalLen: 0, + cadWidth: width, + height: height * 0.85, + treeWidth: 240, + ticks: 10, + ambientIntensity: 0.9, + directIntensity: 0.12, + transparent: false, + blackEdges: false, + axes: true, + grid: [false, false, false], + timeit: false, + rotateSpeed: 1, + }; - useEffect(() => { - const container = ref.current + useEffect(() => { + const container = ref.current; - if (cadShapes && cadShapes.length > 0) { - const viewer = new Viewer(container, viewerOptions, nc) + if (container && stlFileUrl) { + const display = new Display(container, viewerOptions); + const viewer = new Viewer(display, true, viewerOptions, nc); + fetch(stlFileUrl) + .then(response => response.arrayBuffer()) + .then(data => { + const blob = new Blob([data], { type: 'application/octet-stream' }); + const url = URL.createObjectURL(blob); + viewer.clear(); + viewer.addModelFromURL(url); // Ensure this is the correct method name + viewer.render(); + }) + .catch(error => console.error(error)); + } + }, [stlFileUrl]); - render("input", ...cadShapes) - function render(name: string, shapes, states) { - viewer?.clear() - const [unselected, selected] = viewer.renderTessellatedShapes(shapes, states, renderOptions) - console.log(unselected) - console.log(selected) + useEffect(() => { + const container = ref.current; - viewer.render( - unselected, - selected, - states, - renderOptions, - ) - } - } - }, [cadShapes]) + if (container && cadShapes && Object.keys(cadShapes).length > 0) { + const display = new Display(container, viewerOptions); + const viewer = new Viewer(display, true, viewerOptions, nc); + viewer.render(cadShapes, {}); + } + }, [cadShapes]); - return ( -
- ) + return ( +
+ ); } diff --git a/ui/app/page.tsx b/ui/app/page.tsx index a96b9d3..30051b7 100644 --- a/ui/app/page.tsx +++ b/ui/app/page.tsx @@ -4,10 +4,9 @@ import { Alert, Layout, Select, Space, theme } from 'antd'; import Search from 'antd/es/input/Search'; import { useState } from 'react'; import { getCadDownload as downloadCadFile, getCadShapes as getCadObject, getGeneratedFiles } from './api/cad'; -import CadViewer from './components/cad-viewer'; const { Content } = Layout; -const BASE_URL = "http://127.0.0.1:5001"; // Ensure this URL matches your backend server +const test = true; // Set to true for hardcoded values, false for original fetching export default function Home() { const { @@ -17,36 +16,57 @@ export default function Home() { const [cadShapes, setCadShapes] = useState([]); const [isError, setIsError] = useState(false); const [cadID, setCadID] = useState(); - const [iteration, setIteration] = useState(); - const [generatedFiles, setGeneratedFiles] = useState([]); - const [stlFileUrl, setStlFileUrl] = useState(); + const [iterations, setIterations] = useState([]); + const [generatedFiles, setGeneratedFiles] = useState>({}); const onSearch = async (value: string) => { try { setIsError(false); - const cadObject = await getCadObject(value); - setCadShapes(cadObject.shapes); - setCadID(cadObject.id); - setIteration(cadObject.iteration); - const files = await getGeneratedFiles(cadObject.id, cadObject.iteration); - setGeneratedFiles(files); - setIsError(false); - const stlFile = files.find(file => file.endsWith('.stl')); - if (stlFile) { - setStlFileUrl(`${BASE_URL}/models/generated/${cadObject.id}/${cadObject.iteration}/${stlFile}`); + if (!test) { + const cadObject = await getCadObject(value); + setCadShapes(cadObject.shapes); + setCadID(cadObject.id); + + // Fetch iterations for the generation + const iterationDirs = await fetchIterations(cadObject.id); + setIterations(iterationDirs); + + // Fetch generated files for each iteration + const filesByIteration: Record = {}; + for (const iteration of iterationDirs) { + const files = await getGeneratedFiles(cadObject.id, iteration); + filesByIteration[iteration] = files; + } + setGeneratedFiles(filesByIteration); + } else { + // Hardcoded values for testing + setCadID("20240519094656"); + setIterations(["0", "1"]); + setGeneratedFiles({ + "0": ["output.png", "output.stl", "output.scad"], + "1": ["output.png", "output.stl", "output.scad"], + }); } - } catch { - console.log("error"); + + setIsError(false); + } catch (error) { + console.log(error); setIsError(true); } }; const onDownload = async (file_type: string) => { - if (cadID && iteration) { - await downloadCadFile(cadID, iteration, file_type); + if (cadID && iterations.length > 0) { + await downloadCadFile(cadID, iterations[0], file_type); // Assuming download from the first iteration } }; + const fetchIterations = async (generationId: string): Promise => { + const response = await fetch(`${BASE_URL}/models/generated/${generationId}`); + const data = await response.json(); + return data; + }; + return ( @@ -54,9 +74,9 @@ export default function Home() { placeholder="Download" style={{ width: 120 }} onChange={onDownload} - options={generatedFiles.map(file => ({ - value: file.split('.').pop(), - label: file, + options={iterations.map(iteration => ({ + value: iteration, + label: `Iteration ${iteration}`, }))} /> @@ -72,50 +92,34 @@ export default function Home() { alignItems: 'center', }} > - - - - {generatedFiles.length > 0 && ( -
-

Generated Files:

- - - - - - - - - {generatedFiles.map(file => ( - - - - - ))} - -
File NameActions
{file} - - Download - -
+ {Object.keys(generatedFiles).map(iteration => ( +
+

Iteration {iteration}

+ {generatedFiles[iteration].map(file => ( + file.endsWith('output.png') && ( + {`Generated + ) + ))}
- )} - + ))} - {isError && ( - - - - )} + {isError && ( + + + + )} - + +