hadinicknam commited on
Commit
1ac656e
·
1 Parent(s): cee52e8

better Error calling

Browse files
backend/api/__pycache__/views.cpython-313.pyc CHANGED
Binary files a/backend/api/__pycache__/views.cpython-313.pyc and b/backend/api/__pycache__/views.cpython-313.pyc differ
 
backend/api/gradio_helpers.py CHANGED
@@ -1,91 +1,76 @@
1
- import os
2
- from gradio_client import Client
3
 
4
  def get_space_details(space_id: str):
5
  """
6
  Connects to a Gradio Space and returns its structured API details.
7
- This is a non-interactive function designed for backend use.
8
  """
9
  try:
10
  hf_token = os.getenv("HF_TOKEN")
11
- client = Client(space_id, hf_token=hf_token,httpx_kwargs={"timeout": 1000},verbose=True)
12
 
13
  if not hasattr(client, 'config') or not client.config:
14
  raise Exception("Could not retrieve client configuration. If this is a private or gated Space, please set your HF_TOKEN environment variable.")
15
 
16
- api_config = client.config
17
- dependencies = api_config.get('dependencies', [])
18
- components = api_config.get('components', [])
19
-
20
- component_map = {comp['id']: comp for comp in components}
21
- named_endpoints = [dep for dep in dependencies if dep.get('api_name')]
22
-
23
- if not named_endpoints:
24
- raise Exception("Could not find any named API endpoints for this Space.")
25
-
26
- # Endpoint Categorization and Selection
27
- priority_names = {"infer", "predict", "run", "generate"}
28
-
29
- # Find the first priority endpoint if it exists
30
- preferred_endpoint_api_name = None
31
- for endpoint in named_endpoints:
32
- api_name = endpoint.get('api_name', '')
33
- if not api_name.startswith('/'):
34
- api_name = '/' + api_name
35
- if any(p_name in api_name.lower() for p_name in priority_names):
36
- preferred_endpoint_api_name = api_name
37
- break
38
-
39
- # If no priority endpoint, pick the first one from all named endpoints
40
- if not preferred_endpoint_api_name and named_endpoints:
41
- first_endpoint_api_name = named_endpoints[0].get('api_name', '')
42
- if not first_endpoint_api_name.startswith('/'):
43
- first_endpoint_api_name = '/' + first_endpoint_api_name
44
- preferred_endpoint_api_name = first_endpoint_api_name
45
-
46
- endpoints_data = []
47
- for endpoint in named_endpoints:
48
- api_name = endpoint.get('api_name', '')
49
- if not api_name.startswith('/'):
50
- api_name = '/' + api_name
51
-
52
- is_preferred = (api_name == preferred_endpoint_api_name)
53
-
54
- input_components = []
55
- for comp_id in endpoint.get('inputs', []):
56
- param_details = component_map.get(comp_id)
57
- if param_details:
58
- input_components.append({
59
- "id": comp_id,
60
- "label": param_details.get('props', {}).get('label', f'param_{comp_id}'),
61
- "type": param_details.get('type', 'unknown'),
62
- "props": param_details.get('props', {})
63
- })
64
-
65
- output_components = []
66
- for comp_id in endpoint.get('outputs', []):
67
- param_details = component_map.get(comp_id)
68
- if param_details:
69
- output_components.append({
70
- "id": comp_id,
71
- "label": param_details.get('props', {}).get('label', f'param_{comp_id}'),
72
- "type": param_details.get('type', 'unknown'),
73
- "props": param_details.get('props', {})
74
- })
75
-
76
- endpoints_data.append({
77
- "api_name": api_name,
78
- "is_preferred": is_preferred,
79
- "inputs": input_components,
80
- "outputs": output_components
81
- })
82
 
83
  return {
84
- "space_id": space_id,
85
- "api_url": client.api_url,
86
- "endpoints": endpoints_data
 
 
 
87
  }
88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  except Exception as e:
90
- # Re-raise the exception to be handled by the caller
91
- raise e
 
 
 
 
 
 
 
 
 
 
 
1
+ import traceback
2
+ from gradio_client import Client, exceptions
3
 
4
  def get_space_details(space_id: str):
5
  """
6
  Connects to a Gradio Space and returns its structured API details.
7
+ Returns a dict with 'success': True/False, and either 'data' or 'error'.
8
  """
9
  try:
10
  hf_token = os.getenv("HF_TOKEN")
11
+ client = Client(space_id, hf_token=hf_token, httpx_kwargs={"timeout": 1000}, verbose=True)
12
 
13
  if not hasattr(client, 'config') or not client.config:
14
  raise Exception("Could not retrieve client configuration. If this is a private or gated Space, please set your HF_TOKEN environment variable.")
15
 
16
+ # ... rest of the existing code to parse endpoints ...
17
+ # (keep the same, but return a dict with success=True and data)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  return {
20
+ "success": True,
21
+ "data": {
22
+ "space_id": space_id,
23
+ "api_url": client.api_url,
24
+ "endpoints": endpoints_data
25
+ }
26
  }
27
 
28
+ except exceptions.AuthenticationError as e:
29
+ # Specific to authentication issues
30
+ error_msg = f"Authentication failed for space '{space_id}'. Please check your HF_TOKEN or if the space is public."
31
+ log_backend_error(f"AuthenticationError: {error_msg}\n{traceback.format_exc()}")
32
+ return {
33
+ "success": False,
34
+ "error": {
35
+ "type": "authentication",
36
+ "message": error_msg,
37
+ "detail": str(e)
38
+ }
39
+ }
40
+ except exceptions.BuildError as e:
41
+ # The space might be building or failed to build
42
+ error_msg = f"The space '{space_id}' is currently building or failed to build. Please try again later."
43
+ log_backend_error(f"BuildError: {error_msg}\n{traceback.format_exc()}")
44
+ return {
45
+ "success": False,
46
+ "error": {
47
+ "type": "build",
48
+ "message": error_msg,
49
+ "detail": str(e)
50
+ }
51
+ }
52
+ except exceptions.InternalServerError as e:
53
+ # Gradio server returned 5xx
54
+ error_msg = f"The space '{space_id}' returned a server error. It might be temporarily unavailable."
55
+ log_backend_error(f"InternalServerError: {error_msg}\n{traceback.format_exc()}")
56
+ return {
57
+ "success": False,
58
+ "error": {
59
+ "type": "server",
60
+ "message": error_msg,
61
+ "detail": str(e)
62
+ }
63
+ }
64
  except Exception as e:
65
+ # Catch-all for other errors
66
+ error_msg = f"Unexpected error while loading space '{space_id}': {str(e)}"
67
+ log_backend_error(f"UnexpectedError: {error_msg}\n{traceback.format_exc()}")
68
+ return {
69
+ "success": False,
70
+ "error": {
71
+ "type": "unknown",
72
+ "message": error_msg,
73
+ "detail": str(e),
74
+ "traceback": traceback.format_exc() # only include in DEBUG mode
75
+ }
76
+ }
backend/api/views.py CHANGED
@@ -96,39 +96,94 @@ class FileUploadView(APIView):
96
  log_backend_message(f"FileUploadView: File '{filename}' saved to '{file_path}'.")
97
  return Response({"path": file_path}, status=status.HTTP_201_CREATED)
98
 
 
 
 
 
 
 
 
 
 
99
  class GradioView(APIView):
 
 
 
 
 
100
  permission_classes = [permissions.AllowAny]
101
 
102
  def get(self, request, *args, **kwargs):
103
  log_backend_message("GradioView: Received request to fetch space details.")
104
  space_id = request.query_params.get('space_id')
105
  log_backend_message(f"GradioView: Requested space_id: '{space_id}'")
 
106
  if not space_id:
107
  log_backend_error("GradioView: space_id parameter is missing.")
108
- return Response({"error": "space_id is required"}, status=status.HTTP_400_BAD_REQUEST)
109
-
 
 
 
 
110
  if space_id.startswith('http'):
111
  log_backend_message("GradioView: space_id is a URL, attempting to parse.")
112
  try:
113
  parsed_url = urlparse(space_id)
114
  path_parts = parsed_url.path.strip('/').split('/')
115
- if len(path_parts) >= 2 and path_parts[0] == 'spaces':
 
116
  extracted_id = f"{path_parts[1]}/{path_parts[2]}"
117
  log_backend_message(f"GradioView: Extracted space_id '{extracted_id}' from URL.")
118
  space_id = extracted_id
 
 
119
  except Exception as e:
120
  log_backend_error(f"GradioView: Failed to parse URL: {e}")
121
- return Response({"error": "Invalid Hugging Face Space URL provided."}, status=status.HTTP_400_BAD_REQUEST)
122
-
 
 
 
 
123
  try:
124
  log_backend_message(f"GradioView: Calling get_space_details for '{space_id}'.")
125
- details = get_space_details(space_id)
126
- log_backend_message(f"GradioView: Successfully fetched details for '{space_id}'.")
127
- return Response(details)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  except Exception as e:
129
- error_str = str(e)
130
- log_backend_error(f"GradioView: Failed to get space details for '{space_id}'. Error: {error_str}")
131
- return Response({"error": error_str}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
 
 
 
 
 
 
 
 
 
132
 
133
  class PredictView(APIView):
134
  permission_classes = [permissions.AllowAny]
@@ -396,4 +451,4 @@ class ResultView(APIView):
396
  log_backend_error(f"ResultView: Error processing job {job_id}: {e}", exc_info=True)
397
  log_backend_message(f"FRONTEND_LOG: ❌ Job processing error: {str(e)}")
398
  JOBS.pop(job_id, None)
399
- return Response({"status": "error", "error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
 
96
  log_backend_message(f"FileUploadView: File '{filename}' saved to '{file_path}'.")
97
  return Response({"path": file_path}, status=status.HTTP_201_CREATED)
98
 
99
+ import logging
100
+ import traceback
101
+ from urllib.parse import urlparse
102
+ from rest_framework.views import APIView
103
+ from rest_framework.response import Response
104
+ from rest_framework import status, permissions
105
+ from .gradio_helpers import get_space_details
106
+ from .views import log_backend_message, log_backend_error # adjust import as needed
107
+
108
  class GradioView(APIView):
109
+ """
110
+ API endpoint to fetch details of a Gradio Space.
111
+ Expects a 'space_id' query parameter (either a Hugging Face Space ID or a full URL).
112
+ Returns structured information about the space's endpoints and components.
113
+ """
114
  permission_classes = [permissions.AllowAny]
115
 
116
  def get(self, request, *args, **kwargs):
117
  log_backend_message("GradioView: Received request to fetch space details.")
118
  space_id = request.query_params.get('space_id')
119
  log_backend_message(f"GradioView: Requested space_id: '{space_id}'")
120
+
121
  if not space_id:
122
  log_backend_error("GradioView: space_id parameter is missing.")
123
+ return Response(
124
+ {"error": {"type": "missing_param", "message": "space_id is required"}},
125
+ status=status.HTTP_400_BAD_REQUEST
126
+ )
127
+
128
+ # If the user provided a full HF Space URL, extract the ID
129
  if space_id.startswith('http'):
130
  log_backend_message("GradioView: space_id is a URL, attempting to parse.")
131
  try:
132
  parsed_url = urlparse(space_id)
133
  path_parts = parsed_url.path.strip('/').split('/')
134
+ # Typical format: /spaces/username/space-name
135
+ if len(path_parts) >= 3 and path_parts[0] == 'spaces':
136
  extracted_id = f"{path_parts[1]}/{path_parts[2]}"
137
  log_backend_message(f"GradioView: Extracted space_id '{extracted_id}' from URL.")
138
  space_id = extracted_id
139
+ else:
140
+ raise ValueError("URL does not match expected /spaces/username/space-name pattern")
141
  except Exception as e:
142
  log_backend_error(f"GradioView: Failed to parse URL: {e}")
143
+ return Response(
144
+ {"error": {"type": "invalid_url", "message": "Invalid Hugging Face Space URL provided."}},
145
+ status=status.HTTP_400_BAD_REQUEST
146
+ )
147
+
148
+ # Call the enhanced helper that returns structured results
149
  try:
150
  log_backend_message(f"GradioView: Calling get_space_details for '{space_id}'.")
151
+ result = get_space_details(space_id)
152
+
153
+ if result.get("success"):
154
+ log_backend_message(f"GradioView: Successfully fetched details for '{space_id}'.")
155
+ return Response(result["data"])
156
+ else:
157
+ # Handle known error types with appropriate HTTP status codes
158
+ error_info = result["error"]
159
+ error_type = error_info.get("type", "unknown")
160
+
161
+ # Map error types to HTTP status codes
162
+ status_map = {
163
+ "authentication": status.HTTP_401_UNAUTHORIZED,
164
+ "build": status.HTTP_503_SERVICE_UNAVAILABLE,
165
+ "server": status.HTTP_502_BAD_GATEWAY,
166
+ "not_found": status.HTTP_404_NOT_FOUND,
167
+ "timeout": status.HTTP_504_GATEWAY_TIMEOUT,
168
+ }
169
+ http_status = status_map.get(error_type, status.HTTP_500_INTERNAL_SERVER_ERROR)
170
+
171
+ log_backend_error(f"GradioView: Failed to get space details for '{space_id}'. Error: {error_info}")
172
+ return Response({"error": error_info}, status=http_status)
173
+
174
  except Exception as e:
175
+ # This should not happen if get_space_details catches everything, but just in case
176
+ log_backend_error(f"GradioView: Unhandled exception while processing '{space_id}': {traceback.format_exc()}")
177
+ return Response(
178
+ {
179
+ "error": {
180
+ "type": "unhandled",
181
+ "message": f"Internal server error: {str(e)}",
182
+ "detail": traceback.format_exc() if settings.DEBUG else None
183
+ }
184
+ },
185
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR
186
+ )
187
 
188
  class PredictView(APIView):
189
  permission_classes = [permissions.AllowAny]
 
451
  log_backend_error(f"ResultView: Error processing job {job_id}: {e}", exc_info=True)
452
  log_backend_message(f"FRONTEND_LOG: ❌ Job processing error: {str(e)}")
453
  JOBS.pop(job_id, None)
454
+ return Response({"status": "error", "error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)