gfathertech commited on
Commit
c916e31
·
verified ·
1 Parent(s): f35c298

Update client.py

Browse files
Files changed (1) hide show
  1. client.py +46 -9
client.py CHANGED
@@ -1,11 +1,14 @@
1
  """Dynamic OpenAPI Client Driver for SOG-X Backend."""
 
2
  import os
 
3
  import logging
4
  from typing import Dict, Any, Tuple, Optional
5
  import httpx
6
 
7
  logger = logging.getLogger("sogx.client")
8
 
 
9
  class BackendClient:
10
  def __init__(self, backend_url: Optional[str] = None, token: Optional[str] = None):
11
  self.base_url = (backend_url or os.getenv("BACKEND_URL", "http://localhost:7860")).rstrip("/")
@@ -15,9 +18,10 @@ class BackendClient:
15
  headers = {}
16
  if self.token:
17
  headers["Authorization"] = f"Bearer {self.token}"
18
- active_key = user_api_key or os.getenv("USER_KEY", "samuel_super_secret_key_1234567890_key")
19
- headers["X-API-Key"] = active_key
20
- headers["X-User-API-Key"] = active_key
 
21
  return headers
22
 
23
  def fetch_openapi_schema(self, user_api_key: Optional[str] = None) -> Tuple[bool, Dict[str, Any]]:
@@ -41,7 +45,14 @@ class BackendClient:
41
  files: Dict[str, Any],
42
  user_api_key: Optional[str] = None,
43
  ) -> Tuple[bool, Any]:
44
- """Execute request against any backend route dynamically."""
 
 
 
 
 
 
 
45
  url = f"{self.base_url}{path}"
46
  headers = self.get_headers(user_api_key)
47
 
@@ -58,10 +69,7 @@ class BackendClient:
58
  return False, f"Unsupported HTTP method: {method}"
59
 
60
  if res.status_code == 200:
61
- try:
62
- return True, res.json()
63
- except Exception:
64
- return True, res.text
65
  elif res.status_code == 401:
66
  return False, "❌ 401 Unauthorized: Invalid API Key."
67
  elif res.status_code == 429:
@@ -69,4 +77,33 @@ class BackendClient:
69
  return False, f"Error {res.status_code}: {res.text}"
70
 
71
  except Exception as exc:
72
- return False, f"Request Failed: {str(exc)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  """Dynamic OpenAPI Client Driver for SOG-X Backend."""
2
+ import mimetypes
3
  import os
4
+ import tempfile
5
  import logging
6
  from typing import Dict, Any, Tuple, Optional
7
  import httpx
8
 
9
  logger = logging.getLogger("sogx.client")
10
 
11
+
12
  class BackendClient:
13
  def __init__(self, backend_url: Optional[str] = None, token: Optional[str] = None):
14
  self.base_url = (backend_url or os.getenv("BACKEND_URL", "http://localhost:7860")).rstrip("/")
 
18
  headers = {}
19
  if self.token:
20
  headers["Authorization"] = f"Bearer {self.token}"
21
+ active_key = user_api_key or os.getenv("USER_KEY", "")
22
+ if active_key:
23
+ headers["X-API-Key"] = active_key
24
+ headers["X-User-API-Key"] = active_key
25
  return headers
26
 
27
  def fetch_openapi_schema(self, user_api_key: Optional[str] = None) -> Tuple[bool, Dict[str, Any]]:
 
45
  files: Dict[str, Any],
46
  user_api_key: Optional[str] = None,
47
  ) -> Tuple[bool, Any]:
48
+ """Execute request against any backend route dynamically.
49
+
50
+ On success, returns (True, response) where response is one of:
51
+ - a parsed JSON dict/list (for application/json responses)
52
+ - {"__binary__": True, "content_type": str, "file_path": str} for
53
+ images, audio, video, PDFs, or any other downloadable file response
54
+ - a plain string for anything else (e.g. text/plain)
55
+ """
56
  url = f"{self.base_url}{path}"
57
  headers = self.get_headers(user_api_key)
58
 
 
69
  return False, f"Unsupported HTTP method: {method}"
70
 
71
  if res.status_code == 200:
72
+ return True, self._parse_response(res)
 
 
 
73
  elif res.status_code == 401:
74
  return False, "❌ 401 Unauthorized: Invalid API Key."
75
  elif res.status_code == 429:
 
77
  return False, f"Error {res.status_code}: {res.text}"
78
 
79
  except Exception as exc:
80
+ return False, f"Request Failed: {str(exc)}"
81
+
82
+ @staticmethod
83
+ def _parse_response(res: "httpx.Response") -> Any:
84
+ """Route the response body based on its real Content-Type, the way Swagger UI does."""
85
+ content_type = res.headers.get("content-type", "").split(";")[0].strip().lower()
86
+ disposition = res.headers.get("content-disposition", "")
87
+
88
+ if content_type.startswith("application/json"):
89
+ try:
90
+ return res.json()
91
+ except Exception:
92
+ pass # fall through and treat as text/binary below
93
+
94
+ is_binary = (
95
+ content_type.startswith(("image/", "audio/", "video/", "application/pdf"))
96
+ or content_type == "application/octet-stream"
97
+ or "attachment" in disposition
98
+ )
99
+ if is_binary:
100
+ ext = mimetypes.guess_extension(content_type) or ""
101
+ fd, tmp_path = tempfile.mkstemp(suffix=ext)
102
+ with os.fdopen(fd, "wb") as fh:
103
+ fh.write(res.content)
104
+ return {"__binary__": True, "content_type": content_type, "file_path": tmp_path}
105
+
106
+ try:
107
+ return res.json()
108
+ except Exception:
109
+ return res.text