File size: 7,041 Bytes
72f0edb
 
 
 
 
 
 
 
 
 
 
 
6bc7874
72f0edb
 
 
 
 
6bc7874
72f0edb
 
6bc7874
72f0edb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6bc7874
72f0edb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6bc7874
72f0edb
 
 
 
 
6bc7874
72f0edb
6bc7874
72f0edb
 
 
 
 
 
 
 
6bc7874
72f0edb
 
 
 
 
 
 
 
6bc7874
72f0edb
 
 
 
 
 
 
 
 
 
 
 
6bc7874
72f0edb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6bc7874
72f0edb
 
 
 
 
 
 
 
 
 
 
 
 
 
6bc7874
72f0edb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6bc7874
72f0edb
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
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,
  };
};