SolusOps commited on
Commit
d81c729
·
verified ·
1 Parent(s): 280bb54

fix: use InferenceClient for HF API calls instead of raw urllib

Browse files
Files changed (1) hide show
  1. services/hf_provider.py +53 -3
services/hf_provider.py CHANGED
@@ -1,13 +1,44 @@
1
  from __future__ import annotations
2
  import json
 
 
 
 
 
 
 
 
3
  import urllib.request
4
 
5
  HF_API_BASE = "https://api-inference.huggingface.co/models"
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  def generate(model_id: str, prompt: str, system: str = "",
8
  api_key: str = "", max_tokens: int = 1024, temperature: float = 0.3) -> str:
9
- """Text generation — used for MiniCPM concept extraction and Tiny Aya translation."""
10
- url = f"{HF_API_BASE}/{model_id}"
 
 
 
 
 
 
 
 
 
 
 
 
11
  messages = []
12
  if system:
13
  messages.append({"role": "system", "content": system})
@@ -18,7 +49,7 @@ def generate(model_id: str, prompt: str, system: str = "",
18
  headers = {"Content-Type": "application/json"}
19
  if api_key:
20
  headers["Authorization"] = f"Bearer {api_key}"
21
- req = urllib.request.Request(url, data=data, headers=headers, method="POST")
22
  with urllib.request.urlopen(req, timeout=60) as resp:
23
  result = json.loads(resp.read().decode("utf-8"))
24
  if isinstance(result, list): return result[0].get("generated_text", str(result[0]))
@@ -28,6 +59,19 @@ def generate(model_id: str, prompt: str, system: str = "",
28
  def vision_generate(model_id: str, image_b64: str, prompt: str,
29
  api_key: str = "", max_tokens: int = 1024) -> str:
30
  """Vision+language — MiniCPM-V for OCR and visual understanding."""
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  url = f"{HF_API_BASE}/{model_id}"
32
  payload = {"inputs": {"image": image_b64, "question": prompt},
33
  "parameters": {"max_new_tokens": max_tokens}}
@@ -44,6 +88,12 @@ def vision_generate(model_id: str, image_b64: str, prompt: str,
44
 
45
  def transcribe(model_id: str, audio_bytes: bytes, api_key: str = "") -> str:
46
  """ASR — Whisper via HuggingFace for voice input."""
 
 
 
 
 
 
47
  url = f"{HF_API_BASE}/{model_id}"
48
  headers = {"Content-Type": "audio/wav"}
49
  if api_key:
 
1
  from __future__ import annotations
2
  import json
3
+ import base64
4
+
5
+ try:
6
+ from huggingface_hub import InferenceClient as _HFClient
7
+ _HF_AVAILABLE = True
8
+ except ImportError:
9
+ _HF_AVAILABLE = False
10
+
11
  import urllib.request
12
 
13
  HF_API_BASE = "https://api-inference.huggingface.co/models"
14
+ HF_ROUTER_BASE = "https://router.huggingface.co/hf-inference/models"
15
+
16
+ def _try_router_url(model_id: str, payload: dict, api_key: str, timeout: int = 60) -> str:
17
+ """Try the new HF Router endpoint as fallback."""
18
+ url = f"{HF_ROUTER_BASE}/{model_id}/v1/chat/completions"
19
+ data = json.dumps(payload).encode("utf-8")
20
+ headers = {"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}
21
+ req = urllib.request.Request(url, data=data, headers=headers, method="POST")
22
+ with urllib.request.urlopen(req, timeout=timeout) as resp:
23
+ result = json.loads(resp.read().decode("utf-8"))
24
+ return result["choices"][0]["message"]["content"]
25
 
26
  def generate(model_id: str, prompt: str, system: str = "",
27
  api_key: str = "", max_tokens: int = 1024, temperature: float = 0.3) -> str:
28
+ """Text generation — MiniCPM concept extraction and Tiny Aya translation."""
29
+ if _HF_AVAILABLE and api_key:
30
+ client = _HFClient(api_key=api_key)
31
+ messages = []
32
+ if system:
33
+ messages.append({"role": "system", "content": system})
34
+ messages.append({"role": "user", "content": prompt})
35
+ response = client.chat_completion(
36
+ messages=messages, model=model_id,
37
+ max_tokens=max_tokens, temperature=temperature
38
+ )
39
+ return response.choices[0].message.content
40
+
41
+ # Fallback: raw HTTP
42
  messages = []
43
  if system:
44
  messages.append({"role": "system", "content": system})
 
49
  headers = {"Content-Type": "application/json"}
50
  if api_key:
51
  headers["Authorization"] = f"Bearer {api_key}"
52
+ req = urllib.request.Request(f"{HF_API_BASE}/{model_id}", data=data, headers=headers, method="POST")
53
  with urllib.request.urlopen(req, timeout=60) as resp:
54
  result = json.loads(resp.read().decode("utf-8"))
55
  if isinstance(result, list): return result[0].get("generated_text", str(result[0]))
 
59
  def vision_generate(model_id: str, image_b64: str, prompt: str,
60
  api_key: str = "", max_tokens: int = 1024) -> str:
61
  """Vision+language — MiniCPM-V for OCR and visual understanding."""
62
+ if _HF_AVAILABLE and api_key:
63
+ client = _HFClient(api_key=api_key)
64
+ image_data_url = f"data:image/png;base64,{image_b64}"
65
+ messages = [{"role": "user", "content": [
66
+ {"type": "image_url", "image_url": {"url": image_data_url}},
67
+ {"type": "text", "text": prompt},
68
+ ]}]
69
+ response = client.chat_completion(
70
+ messages=messages, model=model_id, max_tokens=max_tokens
71
+ )
72
+ return response.choices[0].message.content
73
+
74
+ # Fallback: raw HTTP
75
  url = f"{HF_API_BASE}/{model_id}"
76
  payload = {"inputs": {"image": image_b64, "question": prompt},
77
  "parameters": {"max_new_tokens": max_tokens}}
 
88
 
89
  def transcribe(model_id: str, audio_bytes: bytes, api_key: str = "") -> str:
90
  """ASR — Whisper via HuggingFace for voice input."""
91
+ if _HF_AVAILABLE and api_key:
92
+ client = _HFClient(api_key=api_key)
93
+ result = client.automatic_speech_recognition(audio=audio_bytes, model=model_id)
94
+ return result.text if hasattr(result, "text") else str(result)
95
+
96
+ # Fallback: raw HTTP
97
  url = f"{HF_API_BASE}/{model_id}"
98
  headers = {"Content-Type": "audio/wav"}
99
  if api_key: