youssefreda9 commited on
Commit
0405b6b
·
1 Parent(s): e18c6c8

fix: Use requests.post() directly instead of InferenceClient (version compat issue)

Browse files
Files changed (1) hide show
  1. src/hf_inference.py +71 -96
src/hf_inference.py CHANGED
@@ -1,8 +1,8 @@
1
  """
2
  HuggingFace Inference API client for Bayan models.
3
 
4
- Uses huggingface_hub.InferenceClient which works from within HF Spaces
5
- (handles internal routing / DNS automatically).
6
 
7
  Models:
8
  - bayan10/summarization-model (MBart, summarization pipeline)
@@ -15,23 +15,51 @@ import os
15
  import json
16
  import logging
17
  import time
 
18
 
19
  logger = logging.getLogger(__name__)
20
 
21
  HF_API_TOKEN = os.environ.get("HF_API_TOKEN", "")
 
 
22
 
23
- # Lazy-initialized client (created on first use)
24
- _client = None
25
 
 
 
 
 
 
 
26
 
27
- def _get_client():
28
- """Get or create the InferenceClient singleton."""
29
- global _client
30
- if _client is None:
31
- from huggingface_hub import InferenceClient
32
- _client = InferenceClient(token=HF_API_TOKEN if HF_API_TOKEN else None)
33
- logger.info("HuggingFace InferenceClient initialized (token=%s)", "set" if HF_API_TOKEN else "not set")
34
- return _client
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
 
37
  # ============================================================
@@ -45,117 +73,62 @@ AUTOCOMPLETE_REPO = os.environ.get("AUTOCOMPLETE_REPO_ID", "bayan10/AutoComplete
45
 
46
 
47
  # ============================================================
48
- # Generic low-level call (works for models without pipeline_tag)
49
  # ============================================================
50
 
51
- def _call_model_raw(repo_id, payload):
52
- """
53
- Call any HF model using the low-level .post() method.
54
- This works even for models without a pipeline_tag configured.
55
- Returns parsed JSON response.
56
- """
57
- client = _get_client()
58
- logger.info("Calling HF model (raw): %s", repo_id)
59
-
60
- response = client.post(
61
- json=payload,
62
- model=repo_id,
63
- )
64
 
65
- # response is bytes
66
- result = json.loads(response)
67
- logger.info("HF raw result for %s: type=%s, preview=%s",
68
- repo_id, type(result).__name__, str(result)[:150])
69
- return result
70
 
 
71
 
72
- # ============================================================
73
- # Model-specific wrappers
74
- # ============================================================
75
 
76
  def hf_summarize(text, max_length=128, min_length=30):
77
  """Summarize Arabic text via HF Inference API."""
78
- logger.info("Calling HF summarization: %s (max_length=%d)", SUMMARIZATION_REPO, max_length)
79
-
80
- # Use raw post since .summarization() has different kwargs
81
- result = _call_model_raw(SUMMARIZATION_REPO, {
82
  "inputs": text,
83
  "parameters": {
84
  "max_length": max_length,
85
  "min_length": min_length,
86
  }
87
  })
88
-
89
- # HF summarization returns: [{"summary_text": "..."}]
90
- if isinstance(result, list) and len(result) > 0:
91
- item = result[0]
92
- if isinstance(item, dict):
93
- return item.get("summary_text", item.get("generated_text", str(item)))
94
- return str(item)
95
-
96
- if isinstance(result, dict):
97
- return result.get("summary_text", result.get("generated_text", str(result)))
98
-
99
- return str(result)
100
 
101
 
102
  def hf_correct_spelling(text):
103
  """Correct spelling in Arabic text via HF Inference API."""
104
- logger.info("Calling HF spelling correction: %s", SPELLING_REPO)
105
-
106
- result = _call_model_raw(SPELLING_REPO, {
107
- "inputs": text,
108
- })
109
-
110
- # Seq2seq/text2text models return: [{"generated_text": "..."}]
111
- if isinstance(result, list) and len(result) > 0:
112
- item = result[0]
113
- if isinstance(item, dict):
114
- return item.get("generated_text", item.get("translation_text", text))
115
- return str(item) if str(item).strip() else text
116
-
117
- if isinstance(result, dict):
118
- return result.get("generated_text", result.get("translation_text", text))
119
-
120
- return text
121
 
122
 
123
  def hf_add_punctuation(text):
124
  """Add punctuation to Arabic text via HF Inference API."""
125
- logger.info("Calling HF punctuation: %s", PUNCTUATION_REPO)
126
-
127
- result = _call_model_raw(PUNCTUATION_REPO, {
128
- "inputs": text,
129
- })
130
-
131
- if isinstance(result, list) and len(result) > 0:
132
- item = result[0]
133
- if isinstance(item, dict):
134
- return item.get("generated_text", item.get("translation_text", text))
135
- return str(item) if str(item).strip() else text
136
-
137
- if isinstance(result, dict):
138
- return result.get("generated_text", result.get("translation_text", text))
139
-
140
- return text
141
 
142
 
143
  def hf_autocomplete(text, n=5):
144
  """Get autocomplete suggestions for Arabic text via HF Inference API."""
145
- logger.info("Calling HF autocomplete: %s", AUTOCOMPLETE_REPO)
146
-
147
- result = _call_model_raw(AUTOCOMPLETE_REPO, {
148
  "inputs": text,
149
- "parameters": {
150
- "max_new_tokens": 20,
151
- }
152
  })
153
 
154
- # Text generation returns: [{"generated_text": "..."}] or a string
155
  if isinstance(result, str):
156
- completion = result
157
- if completion.startswith(text):
158
- completion = completion[len(text):].strip()
159
  return [completion] if completion else [text]
160
 
161
  if isinstance(result, list):
@@ -174,8 +147,9 @@ def hf_autocomplete(text, n=5):
174
  def check_hf_api_available():
175
  """Quick check if HF Inference API is reachable."""
176
  try:
177
- client = _get_client()
178
- return client is not None
 
179
  except Exception:
180
  return False
181
 
@@ -187,9 +161,10 @@ def debug_test_all_models():
187
  """
188
  results = {}
189
  test_text = "هذا نص تجريبي للاختبار"
 
190
 
191
  for name, fn, args in [
192
- ("summarization", hf_summarize, (test_text + " " + test_text * 3, 30, 10)),
193
  ("spelling", hf_correct_spelling, (test_text,)),
194
  ("punctuation", hf_add_punctuation, (test_text,)),
195
  ("autocomplete", hf_autocomplete, (test_text, 3)),
 
1
  """
2
  HuggingFace Inference API client for Bayan models.
3
 
4
+ Uses the `requests` library (via huggingface_hub's internal session)
5
+ to call the HF Inference API from within HF Spaces.
6
 
7
  Models:
8
  - bayan10/summarization-model (MBart, summarization pipeline)
 
15
  import json
16
  import logging
17
  import time
18
+ import requests
19
 
20
  logger = logging.getLogger(__name__)
21
 
22
  HF_API_TOKEN = os.environ.get("HF_API_TOKEN", "")
23
+ HF_API_BASE = "https://api-inference.huggingface.co/models/"
24
+ HF_TIMEOUT = 120 # seconds — accounts for cold starts
25
 
 
 
26
 
27
+ def _headers():
28
+ """Build request headers with auth token."""
29
+ h = {"Content-Type": "application/json"}
30
+ if HF_API_TOKEN:
31
+ h["Authorization"] = "Bearer " + HF_API_TOKEN
32
+ return h
33
 
34
+
35
+ def _call_model(repo_id, payload):
36
+ """
37
+ Call any HF model via the Inference API.
38
+ Uses requests library + wait_for_model option.
39
+ Returns parsed JSON response.
40
+ """
41
+ url = HF_API_BASE + repo_id
42
+
43
+ # Tell HF to wait for the model to load instead of returning 503
44
+ if "options" not in payload:
45
+ payload["options"] = {"wait_for_model": True}
46
+
47
+ logger.info("HF API call: %s", repo_id)
48
+ resp = requests.post(url, headers=_headers(), json=payload, timeout=HF_TIMEOUT)
49
+
50
+ logger.info("HF API response for %s: HTTP %d, size=%d bytes",
51
+ repo_id, resp.status_code, len(resp.content))
52
+
53
+ if resp.status_code != 200:
54
+ logger.error("HF API error for %s: HTTP %d — %s",
55
+ repo_id, resp.status_code, resp.text[:500])
56
+ raise RuntimeError("HF API error for {} (HTTP {}): {}".format(
57
+ repo_id, resp.status_code, resp.text[:300]))
58
+
59
+ result = resp.json()
60
+ logger.info("HF API result for %s: type=%s, preview=%s",
61
+ repo_id, type(result).__name__, str(result)[:150])
62
+ return result
63
 
64
 
65
  # ============================================================
 
73
 
74
 
75
  # ============================================================
76
+ # Model-specific wrappers
77
  # ============================================================
78
 
79
+ def _extract_text(result, fallback=""):
80
+ """Extract generated text from various HF response formats."""
81
+ if isinstance(result, list) and len(result) > 0:
82
+ item = result[0]
83
+ if isinstance(item, dict):
84
+ return (item.get("summary_text")
85
+ or item.get("generated_text")
86
+ or item.get("translation_text")
87
+ or fallback)
88
+ return str(item) if str(item).strip() else fallback
 
 
 
89
 
90
+ if isinstance(result, dict):
91
+ return (result.get("summary_text")
92
+ or result.get("generated_text")
93
+ or result.get("translation_text")
94
+ or fallback)
95
 
96
+ return str(result) if result else fallback
97
 
 
 
 
98
 
99
  def hf_summarize(text, max_length=128, min_length=30):
100
  """Summarize Arabic text via HF Inference API."""
101
+ result = _call_model(SUMMARIZATION_REPO, {
 
 
 
102
  "inputs": text,
103
  "parameters": {
104
  "max_length": max_length,
105
  "min_length": min_length,
106
  }
107
  })
108
+ return _extract_text(result, text[:100])
 
 
 
 
 
 
 
 
 
 
 
109
 
110
 
111
  def hf_correct_spelling(text):
112
  """Correct spelling in Arabic text via HF Inference API."""
113
+ result = _call_model(SPELLING_REPO, {"inputs": text})
114
+ return _extract_text(result, text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
 
117
  def hf_add_punctuation(text):
118
  """Add punctuation to Arabic text via HF Inference API."""
119
+ result = _call_model(PUNCTUATION_REPO, {"inputs": text})
120
+ return _extract_text(result, text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
 
123
  def hf_autocomplete(text, n=5):
124
  """Get autocomplete suggestions for Arabic text via HF Inference API."""
125
+ result = _call_model(AUTOCOMPLETE_REPO, {
 
 
126
  "inputs": text,
127
+ "parameters": {"max_new_tokens": 20}
 
 
128
  })
129
 
 
130
  if isinstance(result, str):
131
+ completion = result[len(text):].strip() if result.startswith(text) else result
 
 
132
  return [completion] if completion else [text]
133
 
134
  if isinstance(result, list):
 
147
  def check_hf_api_available():
148
  """Quick check if HF Inference API is reachable."""
149
  try:
150
+ resp = requests.get(HF_API_BASE + SUMMARIZATION_REPO,
151
+ headers=_headers(), timeout=10)
152
+ return resp.status_code == 200
153
  except Exception:
154
  return False
155
 
 
161
  """
162
  results = {}
163
  test_text = "هذا نص تجريبي للاختبار"
164
+ long_text = (test_text + " ") * 5
165
 
166
  for name, fn, args in [
167
+ ("summarization", hf_summarize, (long_text, 30, 10)),
168
  ("spelling", hf_correct_spelling, (test_text,)),
169
  ("punctuation", hf_add_punctuation, (test_text,)),
170
  ("autocomplete", hf_autocomplete, (test_text, 3)),