From 0623f30837f00da1996c48b9da46dca345212334 Mon Sep 17 00:00:00 2001 From: AI Bot Date: Wed, 30 Sep 2026 16:29:16 +0530 Subject: [PATCH] feat: Add Clean Image (AI) button to pre-process images before Meshy 3D generation --- src/components/ImageTo3DModal.tsx | 37 +++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/components/ImageTo3DModal.tsx b/src/components/ImageTo3DModal.tsx index 1853ce4..b1e296e 100644 --- a/src/components/ImageTo3DModal.tsx +++ b/src/components/ImageTo3DModal.tsx @@ -5,6 +5,7 @@ import { fal } from '@fal-ai/client'; import { cn } from '../lib/utils'; import { useAuthStore } from '../store/authStore'; import { api } from '../lib/api'; +import { editUVLayer } from '../lib/api/apiUtils'; import { Canvas } from '@react-three/fiber'; import { OrbitControls, Stage } from '@react-three/drei'; import { GLTFLoader } from 'three-stdlib'; @@ -46,7 +47,7 @@ const ModelPreview = ({ url }: { url: string }) => { }; export const ImageTo3DModal: React.FC = ({ isOpen, onClose, onPushToApp }) => { - const { profile, setProfile } = useAuthStore(); + const { profile, setProfile, token } = useAuthStore(); const [apiProvider, setApiProvider] = useState<'fal' | 'tripo' | 'meshy'>('fal'); const [apiKey, setApiKey] = useState(''); const [tripoApiKey, setTripoApiKey] = useState(''); @@ -72,6 +73,7 @@ export const ImageTo3DModal: React.FC = ({ isOpen, onClose, const [progressMessage, setProgressMessage] = useState(''); const [generatedModelUrl, setGeneratedModelUrl] = useState(null); const [error, setError] = useState(null); + const [isCleaningImage, setIsCleaningImage] = useState(false); const fileInputRef = useRef(null); const [isValidatingKey, setIsValidatingKey] = useState(false); const [keyValidationStatus, setKeyValidationStatus] = useState<'idle' | 'valid' | 'invalid' | 'error'>('idle'); @@ -137,6 +139,29 @@ export const ImageTo3DModal: React.FC = ({ isOpen, onClose, } }; + const handleCleanImage = async (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + if (!imageFile || !token) return; + + setIsCleaningImage(true); + try { + const base64 = await fileToDataUrl(imageFile); + const newUrl = await editUVLayer("Remove all text, labels, and logos from this object, leaving a clean plain surface of the exact same shape.", base64, token); + + const res = await fetch(newUrl); + const blob = await res.blob(); + const newFile = new File([blob], "cleaned-image.png", { type: "image/png" }); + + setImageFile(newFile); + setImagePreview(newUrl); + } catch (err: any) { + alert("Failed to clean image: " + err.message); + } finally { + setIsCleaningImage(false); + } + }; + // Utility to convert file to data URL for Fal API if needed const fileToDataUrl = (file: File): Promise => { return new Promise((resolve, reject) => { @@ -453,8 +478,16 @@ export const ImageTo3DModal: React.FC = ({ isOpen, onClose, {imagePreview ? ( <> Preview -
+
Change Image +