urdf-visualizer / viewer /src /hooks /useUrdfParser.ts
jurmy24's picture
refactor: rename URDF to Urdf
6bc7874
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,
};
};