273 lines
8.9 KiB
JavaScript
273 lines
8.9 KiB
JavaScript
import { useState, useEffect, useRef } from "react";
|
|
import Head from "next/head";
|
|
import Image from "next/image";
|
|
import styles from "../styles/studio.module.css";
|
|
import FormData from 'form-data';
|
|
import Dropzone from 'react-dropzone';
|
|
import { userAgentFromString } from "next/server";
|
|
import TextInput from "@/components/textinput";
|
|
import { Canvas, useFrame, useThree } from '@react-three/fiber'
|
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
import {CanvasComponent} from "@/components/canvascomponent";
|
|
|
|
|
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
|
|
export default function Studio(){
|
|
|
|
const [gltfModel, setGltfModel] = useState(null);
|
|
const [isResultVisible, setIsResultVisible] = useState(null)
|
|
const [isLoadingVisible, setIsLoadingVisible] = useState(null)
|
|
const [prediction, setPrediction] = useState(null);
|
|
const [error, setError] = useState(null);
|
|
const [inputValue, setInputValue] = useState('');
|
|
|
|
// create a canvas reference in the main state
|
|
const [canvasRef, setCanvasRef] = useState(null);
|
|
|
|
function handleInputValueChange(newInputValue) {
|
|
setInputValue(newInputValue);
|
|
}
|
|
|
|
useEffect(() => {
|
|
console.log("loaded the page");
|
|
setIsResultVisible(false)
|
|
setIsLoadingVisible(false)
|
|
|
|
},[]);
|
|
|
|
|
|
const handleDrop = (event) => {
|
|
event.preventDefault();
|
|
|
|
const file = event.dataTransfer.files[0];
|
|
if (file && file.name.endsWith('.glb')) {
|
|
const reader = new FileReader();
|
|
|
|
reader.readAsArrayBuffer(file);
|
|
reader.onload = (event) => {
|
|
const arrayBuffer = event.target.result;
|
|
|
|
const loader = new GLTFLoader();
|
|
loader.parse(arrayBuffer, '', (gltf) => {
|
|
setGltfModel(gltf);
|
|
console.log("gltf model loaded")
|
|
console.log('Loaded Scene:', gltf.scene);
|
|
|
|
}, (error) => {
|
|
console.error('ArrayBuffer loading error:', error);
|
|
});
|
|
};
|
|
}
|
|
};
|
|
|
|
|
|
const getReplicateResults = async (image, mask) => {
|
|
|
|
setIsLoadingVisible(true)
|
|
|
|
let promptText = "beautiful living room"
|
|
|
|
if (inputValue) {
|
|
promptText = inputValue
|
|
}
|
|
|
|
const response = await fetch("/api/predictions", {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
prompt: promptText + ", photorealistic, high resolution product photography, don't modify product",
|
|
negative_prompt: "blurry, painting, cartoon, abstract, ugly, deformed",
|
|
image: image,
|
|
mask: mask,
|
|
num_outputs: 4,
|
|
guidance_scale: 7.5,
|
|
}),
|
|
});
|
|
let prediction = await response.json();
|
|
if (response.status !== 201) {
|
|
setError(prediction.detail);
|
|
return;
|
|
}
|
|
setPrediction(prediction);
|
|
|
|
while (
|
|
prediction.status !== "succeeded" &&
|
|
prediction.status !== "failed"
|
|
) {
|
|
await sleep(1000);
|
|
const response = await fetch("/api/predictions/" + prediction.id);
|
|
prediction = await response.json();
|
|
if (response.status !== 200) {
|
|
setError(prediction.detail);
|
|
return;
|
|
}
|
|
|
|
if (prediction.status == "succeeded" && prediction.output) {
|
|
|
|
setIsResultVisible(true)
|
|
setIsLoadingVisible(false)
|
|
}
|
|
|
|
console.log({prediction})
|
|
setPrediction(prediction);
|
|
}
|
|
};
|
|
|
|
async function generateImages() {
|
|
console.log("Called the generate images function")
|
|
|
|
// Do something with the image data URL
|
|
let snapshotImage = capture3DSnapshot()
|
|
|
|
const formData = new FormData();
|
|
formData.append('image', snapshotImage);
|
|
|
|
if (!snapshotImage) {
|
|
console.log("image file is null")
|
|
}
|
|
// Generate base64 url image for remove bg
|
|
|
|
try {
|
|
|
|
const response = await fetch('http://127.0.0.1:5000/get_item_mask', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
console.log(response)
|
|
const data = await response.json();
|
|
let maskBase64Url = `data:image/jpeg;base64,${data.ai_mask}`
|
|
|
|
setIsResultVisible(false)
|
|
let imageURLTemp = "https://images.unsplash.com/photo-1490730141103-6cac27aaab94?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2940&q=80"
|
|
|
|
// Generate base64 image for input image.
|
|
// Filereader converts a file blob into a base64 string
|
|
const reader = new FileReader();
|
|
reader.readAsDataURL(snapshotImage);
|
|
reader.onload = async () => {
|
|
const imageBase64Url = reader.result;
|
|
|
|
// now send a request to replicate
|
|
await getReplicateResults(imageBase64Url ,maskBase64Url)
|
|
|
|
};
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
|
|
function base64ToBlob(base64Image) {
|
|
const parts = base64Image.split(';base64,');
|
|
const mimeType = parts[0].split(':')[1];
|
|
const byteString = atob(parts[1]);
|
|
const arrayBuffer = new ArrayBuffer(byteString.length);
|
|
const uint8Array = new Uint8Array(arrayBuffer);
|
|
|
|
for (let i = 0; i < byteString.length; i++) {
|
|
uint8Array[i] = byteString.charCodeAt(i);
|
|
}
|
|
|
|
return new Blob([arrayBuffer], { type: mimeType });
|
|
}
|
|
|
|
function capture3DSnapshot() {
|
|
const dataUrl = canvasRef.toDataURL("image/png")
|
|
const blob = base64ToBlob(dataUrl);
|
|
setIsResultVisible(false)
|
|
return blob
|
|
}
|
|
|
|
//download snapshot
|
|
const download3DSnapshot = () => {
|
|
const link = document.createElement("a");
|
|
link.setAttribute("download", "canvas.png");
|
|
link.setAttribute(
|
|
"href",
|
|
canvasRef.toDataURL("image/png").replace("image/png", "image/octet-stream")
|
|
);
|
|
link.click();
|
|
};
|
|
|
|
|
|
return(
|
|
<div className={styles.page}>
|
|
<div className={styles.inputPanel}>
|
|
<div className={styles.mainImageContainer}>
|
|
<div
|
|
className={styles.imageContainer}
|
|
onDrop={handleDrop}
|
|
onDragOver={(event) => event.preventDefault()}
|
|
>
|
|
{gltfModel ? <CanvasComponent setCanvasRef={setCanvasRef} gltfModel={gltfModel} /> : "Drop your GLB model here"}
|
|
</div>
|
|
</div>
|
|
|
|
<div><TextInput onTextChange={handleInputValueChange} /></div>
|
|
|
|
<div className={styles.buttonContainer}>
|
|
<div
|
|
className={styles.generateButton}
|
|
onClick={()=>generateImages()}
|
|
>
|
|
Generate Images
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.resultsPanel}>
|
|
{isResultVisible? (
|
|
<>
|
|
<div>
|
|
{prediction.output && (
|
|
<div className={styles.imageResultsContainer}>
|
|
<div className={styles.imageWrapper}>
|
|
<Image
|
|
fill
|
|
src={prediction.output[0]}
|
|
alt="output"
|
|
/>
|
|
</div>
|
|
<div className={styles.imageWrapper}>
|
|
<Image
|
|
fill
|
|
src={prediction.output[1]}
|
|
alt="output"
|
|
/>
|
|
</div>
|
|
<div className={styles.imageWrapper}>
|
|
<Image
|
|
fill
|
|
src={prediction.output[2]}
|
|
alt="output"
|
|
/>
|
|
</div>
|
|
<div className={styles.imageWrapper}>
|
|
<Image
|
|
fill
|
|
src={prediction.output[3]}
|
|
alt="output"
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
</>
|
|
) : (
|
|
<></>
|
|
)}
|
|
{
|
|
isLoadingVisible?
|
|
(<p>Loading...</p>):(<></>)
|
|
}
|
|
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
}
|