Spaces:
Running
Running
import { useState } from "react"; | |
import { supabase } from "@/integrations/supabase/client"; | |
import { UrdfData } from "@/lib/types"; | |
import { toast } from "sonner"; | |
export const useUrdfParser = () => { | |
const [isLoading, setIsLoading] = useState(false); | |
const [error, setError] = useState<string | null>(null); | |
const [data, setData] = useState<UrdfData | null>(null); | |
const parseUrdf = async (urdfContent: string) => { | |
const requestId = `urdf-${Date.now()}`; // Generate unique ID for tracking this request | |
console.log(`[${requestId}] π Urdf Parser: Starting parse request`); | |
console.log( | |
`[${requestId}] π Content preview:`, | |
urdfContent?.substring(0, 100) + "..." | |
); | |
// Check if the Urdf content is too large | |
const MAX_SIZE = 4 * 1024 * 1024; // 4MB limit | |
if (urdfContent.length > MAX_SIZE) { | |
const errorMessage = `Urdf content too large (${( | |
urdfContent.length / | |
1024 / | |
1024 | |
).toFixed(2)}MB). Maximum size is ${MAX_SIZE / 1024 / 1024}MB.`; | |
console.error(`[${requestId}] β ${errorMessage}`); | |
setError(errorMessage); | |
toast.error("File too large", { | |
description: errorMessage, | |
duration: 5000, | |
}); | |
return null; | |
} | |
setIsLoading(true); | |
setError(null); | |
const startTime = performance.now(); | |
try { | |
// Make sure the urdfContent is a string | |
if (typeof urdfContent !== "string") { | |
throw new Error("Urdf content must be a string"); | |
} | |
console.log( | |
`[${requestId}] π‘ Calling Supabase edge function "urdf-parser"...` | |
); | |
const { data: rawResponse, error } = await supabase.functions.invoke( | |
"urdf-parser", | |
{ | |
body: { urdfContent }, | |
} | |
); | |
if (error) { | |
console.error(`[${requestId}] β Supabase function error:`, error); | |
// Handle different error cases | |
if (error.message.includes("non-2xx status code")) { | |
// Server error from edge function | |
const serverErrorMsg = | |
"The Urdf parser encountered a server error. It might be due to the complexity of your Urdf file or temporary server issues."; | |
console.error(`[${requestId}] π₯ Server error in edge function`); | |
// Check if we got fallback data despite the error | |
if (rawResponse && rawResponse.fallback) { | |
console.log(`[${requestId}] π Using fallback data from server`); | |
toast.warning("Reduced Urdf Data", { | |
description: | |
"Limited information extracted from your Urdf file due to parsing limitations.", | |
duration: 5000, | |
}); | |
// Use the fallback data | |
setData(rawResponse.fallback); | |
return rawResponse.fallback; | |
} | |
toast.error("Urdf Parser Error", { | |
description: serverErrorMsg, | |
duration: 5000, | |
}); | |
setError(serverErrorMsg); | |
} else if (error.message.includes("timeout")) { | |
// Timeout error | |
const timeoutMsg = | |
"The Urdf parser timed out. Your file might be too complex to process within the allowed time."; | |
console.error(`[${requestId}] β±οΈ Edge function timed out`); | |
toast.error("Processing Timeout", { | |
description: timeoutMsg, | |
duration: 5000, | |
}); | |
setError(timeoutMsg); | |
} else { | |
// Generic error | |
setError(error.message); | |
toast.error("Error Parsing Urdf", { | |
description: error.message, | |
duration: 5000, | |
}); | |
} | |
throw error; | |
} | |
const endTime = performance.now(); | |
console.log( | |
`[${requestId}] β Edge function responded in ${( | |
endTime - startTime | |
).toFixed(2)}ms` | |
); | |
console.log( | |
`[${requestId}] π Response data structure:`, | |
Object.keys(rawResponse || {}) | |
); | |
console.log(`[${requestId}] π¦ Full response:`, rawResponse); | |
// Transform raw data into UrdfData format | |
let transformedData: UrdfData | null = null; | |
if (rawResponse && rawResponse.success && rawResponse.data) { | |
const responseData = rawResponse.data; | |
// Count joint types from raw joints array | |
const jointTypes: { [key: string]: number } = { | |
revolute: 0, | |
prismatic: 0, | |
continuous: 0, | |
fixed: 0, | |
other: 0, | |
}; | |
if (responseData.joints && Array.isArray(responseData.joints)) { | |
responseData.joints.forEach((joint) => { | |
const type = joint.type?.toLowerCase() || "other"; | |
if (type in jointTypes) { | |
jointTypes[type]++; | |
} else { | |
jointTypes.other++; | |
} | |
}); | |
} | |
// Transform links to expected format | |
const transformedLinks = | |
responseData.links?.map((link) => ({ | |
name: link.name, | |
mass: link.mass, | |
})) || []; | |
// Calculate total mass - either use the one from the response or sum up links | |
const totalMass = | |
responseData.total_mass || | |
transformedLinks.reduce((sum, link) => sum + (link.mass || 0), 0); | |
// Create the transformed data object | |
transformedData = { | |
name: responseData.name, | |
description: | |
"A detailed 3D model of a robotic system with articulated joints and components.", | |
mass: totalMass, | |
dofs: responseData.num_joints || responseData.joints?.length || 0, | |
joints: { | |
revolute: jointTypes.revolute, | |
prismatic: jointTypes.prismatic, | |
continuous: jointTypes.continuous, | |
fixed: jointTypes.fixed, | |
other: jointTypes.other, | |
}, | |
links: transformedLinks, | |
// Default materials since we don't have this info from Urdf | |
materials: [{ name: "Metal", percentage: 100 }], | |
}; | |
console.log(`[${requestId}] π Transformed data:`, transformedData); | |
} | |
setData(transformedData); | |
return transformedData; | |
} catch (err) { | |
const errorMessage = | |
err instanceof Error ? err.message : "Unknown error occurred"; | |
const endTime = performance.now(); | |
console.error( | |
`[${requestId}] β Error parsing Urdf after ${( | |
endTime - startTime | |
).toFixed(2)}ms:`, | |
err | |
); | |
console.error(`[${requestId}] π§© Error details:`, { | |
message: errorMessage, | |
type: err instanceof Error ? err.constructor.name : typeof err, | |
stack: err instanceof Error ? err.stack : undefined, | |
}); | |
setError(errorMessage); | |
return null; | |
} finally { | |
setIsLoading(false); | |
console.log( | |
`[${requestId}] π Urdf parsing request completed, isLoading set to false` | |
); | |
} | |
}; | |
return { | |
parseUrdf, | |
data, | |
isLoading, | |
error, | |
}; | |
}; | |