youssefreda9 commited on
Commit
f69f6eb
·
1 Parent(s): 4ff9aed

fix: DNS endpoint discovery - test multiple HF hostnames to find reachable one

Browse files
Files changed (1) hide show
  1. src/hf_inference.py +79 -36
src/hf_inference.py CHANGED
@@ -1,21 +1,22 @@
1
  """
2
  HuggingFace Inference API client for Bayan models.
3
 
4
- Uses huggingface_hub.InferenceClient._inner_post with RequestParameters
5
- (v1.19.0) for internal routing inside HF Spaces.
6
  """
7
 
8
  import os
9
  import json
10
  import logging
11
  import time
 
12
 
13
  logger = logging.getLogger(__name__)
14
 
15
  HF_API_TOKEN = os.environ.get("HF_API_TOKEN", "")
16
- HF_API_BASE = "https://api-inference.huggingface.co/models/"
17
 
18
  _client = None
 
19
 
20
 
21
  def _get_client():
@@ -33,45 +34,66 @@ PUNCTUATION_REPO = os.environ.get("PUNCTUATION_REPO_ID", "bayan10/PuncAra-v1")
33
  AUTOCOMPLETE_REPO = os.environ.get("AUTOCOMPLETE_REPO_ID", "bayan10/AutoComplete")
34
 
35
 
36
- def _call_model(repo_id, payload, task=""):
37
- """
38
- Call HF model via InferenceClient._inner_post with RequestParameters.
39
-
40
- RequestParameters(url, task, model, json, data, headers)
41
- """
42
- from huggingface_hub.inference._common import RequestParameters
43
 
44
- client = _get_client()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
  if "options" not in payload:
47
  payload["options"] = {"wait_for_model": True}
48
 
49
- url = HF_API_BASE + repo_id
50
- logger.info("Calling HF model: %s (url=%s, task=%s)", repo_id, url, task)
 
51
 
52
- rp = RequestParameters(
53
- url=url,
54
- task=task,
55
- model=repo_id,
56
- json=payload,
57
- data=None,
58
- headers={},
59
- )
60
 
61
- response = client._inner_post(rp)
 
62
 
63
- # Parse response
64
- if isinstance(response, bytes):
65
- result = json.loads(response.decode("utf-8"))
66
- elif isinstance(response, str):
67
- result = json.loads(response)
68
- else:
69
- result = response
70
 
 
71
  logger.info("HF result for %s: type=%s preview=%s",
72
  repo_id, type(result).__name__, str(result)[:200])
73
 
74
- # Check for API errors in response
75
  if isinstance(result, dict) and "error" in result:
76
  raise RuntimeError("HF API error: " + str(result["error"]))
77
 
@@ -101,7 +123,7 @@ def _extract_text(result, fallback=""):
101
  # ============================================================
102
 
103
  def hf_summarize(text, max_length=128, min_length=30):
104
- result = _call_model(SUMMARIZATION_REPO, {
105
  "inputs": text,
106
  "parameters": {"max_length": max_length, "min_length": min_length},
107
  }, task="summarization")
@@ -109,17 +131,17 @@ def hf_summarize(text, max_length=128, min_length=30):
109
 
110
 
111
  def hf_correct_spelling(text):
112
- result = _call_model(SPELLING_REPO, {"inputs": text}, task="text2text-generation")
113
  return _extract_text(result, text)
114
 
115
 
116
  def hf_add_punctuation(text):
117
- result = _call_model(PUNCTUATION_REPO, {"inputs": text}, task="text2text-generation")
118
  return _extract_text(result, text)
119
 
120
 
121
  def hf_autocomplete(text, n=5):
122
- result = _call_model(AUTOCOMPLETE_REPO, {
123
  "inputs": text,
124
  "parameters": {"max_new_tokens": 20},
125
  }, task="text-generation")
@@ -141,17 +163,38 @@ def hf_autocomplete(text, n=5):
141
 
142
  def check_hf_api_available():
143
  try:
144
- return _get_client() is not None
145
  except Exception:
146
  return False
147
 
148
 
149
  def debug_test_all_models():
150
- """Test all HF models."""
151
  results = {}
152
  test_text = "هذا نص تجريبي للاختبار"
153
  long_text = (test_text + " ") * 5
154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  try:
156
  import huggingface_hub
157
  results["_info"] = {"hf_hub_version": huggingface_hub.__version__}
 
1
  """
2
  HuggingFace Inference API client for Bayan models.
3
 
4
+ Dynamically discovers a reachable HF API endpoint from inside HF Spaces,
5
+ since api-inference.huggingface.co is not DNS-resolvable from free-tier containers.
6
  """
7
 
8
  import os
9
  import json
10
  import logging
11
  import time
12
+ import socket
13
 
14
  logger = logging.getLogger(__name__)
15
 
16
  HF_API_TOKEN = os.environ.get("HF_API_TOKEN", "")
 
17
 
18
  _client = None
19
+ _working_url = None
20
 
21
 
22
  def _get_client():
 
34
  AUTOCOMPLETE_REPO = os.environ.get("AUTOCOMPLETE_REPO_ID", "bayan10/AutoComplete")
35
 
36
 
37
+ def _find_working_endpoint():
38
+ """Try multiple HF API endpoints to find one that resolves."""
39
+ global _working_url
 
 
 
 
40
 
41
+ if _working_url:
42
+ return _working_url
43
+
44
+ # Candidate API endpoints
45
+ candidates = [
46
+ "https://router.huggingface.co/hf-inference/models/",
47
+ "https://api-inference.huggingface.co/models/",
48
+ "https://api.huggingface.co/models/",
49
+ "https://huggingface.co/api/models/",
50
+ ]
51
+
52
+ for url in candidates:
53
+ # Extract hostname from URL
54
+ hostname = url.split("//")[1].split("/")[0]
55
+ try:
56
+ socket.getaddrinfo(hostname, 443)
57
+ logger.info("DNS resolved for: %s", hostname)
58
+ _working_url = url
59
+ return url
60
+ except socket.gaierror:
61
+ logger.warning("DNS failed for: %s", hostname)
62
+ continue
63
+
64
+ logger.error("No HF API endpoint is reachable!")
65
+ return None
66
+
67
+
68
+ def _call_model_httpx(repo_id, payload, task=""):
69
+ """Call HF model using httpx (same transport as InferenceClient)."""
70
+ import httpx
71
+
72
+ base_url = _find_working_endpoint()
73
+ if not base_url:
74
+ raise RuntimeError("No reachable HF API endpoint found")
75
+
76
+ url = base_url + repo_id
77
 
78
  if "options" not in payload:
79
  payload["options"] = {"wait_for_model": True}
80
 
81
+ headers = {"Content-Type": "application/json"}
82
+ if HF_API_TOKEN:
83
+ headers["Authorization"] = "Bearer " + HF_API_TOKEN
84
 
85
+ logger.info("Calling HF model: %s at %s", repo_id, url)
 
 
 
 
 
 
 
86
 
87
+ with httpx.Client(timeout=120) as client:
88
+ resp = client.post(url, json=payload, headers=headers)
89
 
90
+ if resp.status_code != 200:
91
+ raise RuntimeError(f"HF API error (HTTP {resp.status_code}): {resp.text[:300]}")
 
 
 
 
 
92
 
93
+ result = resp.json()
94
  logger.info("HF result for %s: type=%s preview=%s",
95
  repo_id, type(result).__name__, str(result)[:200])
96
 
 
97
  if isinstance(result, dict) and "error" in result:
98
  raise RuntimeError("HF API error: " + str(result["error"]))
99
 
 
123
  # ============================================================
124
 
125
  def hf_summarize(text, max_length=128, min_length=30):
126
+ result = _call_model_httpx(SUMMARIZATION_REPO, {
127
  "inputs": text,
128
  "parameters": {"max_length": max_length, "min_length": min_length},
129
  }, task="summarization")
 
131
 
132
 
133
  def hf_correct_spelling(text):
134
+ result = _call_model_httpx(SPELLING_REPO, {"inputs": text})
135
  return _extract_text(result, text)
136
 
137
 
138
  def hf_add_punctuation(text):
139
+ result = _call_model_httpx(PUNCTUATION_REPO, {"inputs": text})
140
  return _extract_text(result, text)
141
 
142
 
143
  def hf_autocomplete(text, n=5):
144
+ result = _call_model_httpx(AUTOCOMPLETE_REPO, {
145
  "inputs": text,
146
  "parameters": {"max_new_tokens": 20},
147
  }, task="text-generation")
 
163
 
164
  def check_hf_api_available():
165
  try:
166
+ return _find_working_endpoint() is not None
167
  except Exception:
168
  return False
169
 
170
 
171
  def debug_test_all_models():
172
+ """Test DNS resolution + all HF models."""
173
  results = {}
174
  test_text = "هذا نص تجريبي للاختبار"
175
  long_text = (test_text + " ") * 5
176
 
177
+ # DNS diagnostics
178
+ dns_results = {}
179
+ hostnames = [
180
+ "router.huggingface.co",
181
+ "api-inference.huggingface.co",
182
+ "api.huggingface.co",
183
+ "huggingface.co",
184
+ "hf.co",
185
+ "google.com",
186
+ "pypi.org",
187
+ ]
188
+ for hostname in hostnames:
189
+ try:
190
+ addrs = socket.getaddrinfo(hostname, 443)
191
+ dns_results[hostname] = "OK (" + addrs[0][4][0] + ")"
192
+ except socket.gaierror as e:
193
+ dns_results[hostname] = "FAIL: " + str(e)
194
+
195
+ results["_dns"] = dns_results
196
+ results["_working_endpoint"] = _find_working_endpoint() or "NONE"
197
+
198
  try:
199
  import huggingface_hub
200
  results["_info"] = {"hf_hub_version": huggingface_hub.__version__}