sara.mesquita commited on
Commit
083159f
Β·
1 Parent(s): f1cb7dd

fix: usar HF InferenceClient com meta-llama/Llama-3.2-11B-Vision-Instruct

Browse files
Files changed (1) hide show
  1. core/ai.py +59 -41
core/ai.py CHANGED
@@ -1,12 +1,12 @@
1
  """
2
- ai.py β€” Integracao com modelo de visao via HuggingFace ou NVIDIA NIM.
3
 
4
  Variaveis de ambiente:
5
- HF_TOKEN β€” token HuggingFace (HF Serverless Inference)
6
  NVIDIA_API_KEY β€” chave NVIDIA NIM (free tier em build.nvidia.com)
7
 
8
- Modelo HF: nvidia/llama-3.2-11b-vision-instruct (11B, acessivel no HF)
9
- Modelo NIM: nvidia/nemotron-3-nano-omni-30b-a3b (30B Omni, se tiver NVIDIA key)
10
  """
11
  import base64
12
  import io
@@ -19,7 +19,7 @@ import numpy as np
19
 
20
  log = logging.getLogger(__name__)
21
 
22
- _HF_MODEL = "nvidia/llama-3.2-11b-vision-instruct"
23
  _NIM_MODEL = "nvidia/nemotron-3-nano-omni-30b-a3b"
24
 
25
  PROMPT = (
@@ -39,36 +39,38 @@ PROMPT = (
39
 
40
  class AnimalAI:
41
  def __init__(self):
 
42
  self.model = None
43
- self.client = None
44
 
45
  hf_token = os.environ.get("HF_TOKEN", "")
46
  nvidia_key = os.environ.get("NVIDIA_API_KEY", "")
47
 
48
- try:
49
- from openai import OpenAI
50
-
51
- if nvidia_key:
52
  self.model = os.environ.get("NVIDIA_MODEL", _NIM_MODEL)
53
  self.client = OpenAI(
54
  base_url="https://integrate.api.nvidia.com/v1",
55
  api_key=nvidia_key,
56
  )
57
- log.info("AI: Nemotron Omni 30B via NVIDIA NIM")
 
 
58
 
59
- elif hf_token:
 
 
 
60
  self.model = os.environ.get("NVIDIA_MODEL", _HF_MODEL)
61
- self.client = OpenAI(
62
- base_url="https://api-inference.huggingface.co/v1/",
63
- api_key=hf_token,
64
- )
65
- log.info("AI: %s via HuggingFace Serverless", self.model)
66
-
67
- else:
68
- log.warning("Sem chave de API β€” IA desabilitada. Configure HF_TOKEN nos Secrets do Space.")
69
 
70
- except ImportError:
71
- log.warning("openai nao instalado.")
72
 
73
  self.embedder = None
74
  try:
@@ -79,38 +81,54 @@ class AnimalAI:
79
  log.warning("sentence-transformers nao carregou: %s", e)
80
 
81
  def analyze_image(self, image) -> dict:
82
- """Analisa imagem com IA. _ai_success=False indica fallback."""
83
  if self.client is None:
84
  return self._fallback()
85
 
86
  try:
87
  img_b64 = self._to_b64(image)
88
- resp = self.client.chat.completions.create(
89
- model=self.model,
90
- messages=[{
91
- "role": "user",
92
- "content": [
93
- {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64," + img_b64}},
94
- {"type": "text", "text": PROMPT},
95
- ],
96
- }],
97
- max_tokens=400,
98
- temperature=0.1,
99
- )
100
- raw = resp.choices[0].message.content or ""
101
- log.info("AI resposta: %s", raw[:150])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  result = self._parse(raw)
103
  result["_ai_success"] = True
104
  return result
 
105
  except Exception as e:
106
  log.error("Erro na API de IA: %s", e)
107
  return self._fallback()
108
 
109
  def get_embedding(self, description: dict) -> list:
110
- """
111
- Embedding da descricao. Se IA falhou (_ai_success=False),
112
- usa vetor aleatorio para evitar que todos os fallbacks virem o mesmo animal.
113
- """
114
  if not description.get("_ai_success", True):
115
  log.info("Fallback IA β€” embedding aleatorio")
116
  v = np.random.randn(384).astype(np.float32)
 
1
  """
2
+ ai.py β€” Visao via HuggingFace InferenceClient ou NVIDIA NIM.
3
 
4
  Variaveis de ambiente:
5
+ HF_TOKEN β€” token HuggingFace (usa HF Serverless Inference)
6
  NVIDIA_API_KEY β€” chave NVIDIA NIM (free tier em build.nvidia.com)
7
 
8
+ Modelo HF: meta-llama/Llama-3.2-11B-Vision-Instruct (disponivel no HF Serverless)
9
+ Modelo NIM: nvidia/nemotron-3-nano-omni-30b-a3b (Nemotron Omni via NVIDIA)
10
  """
11
  import base64
12
  import io
 
19
 
20
  log = logging.getLogger(__name__)
21
 
22
+ _HF_MODEL = "meta-llama/Llama-3.2-11B-Vision-Instruct"
23
  _NIM_MODEL = "nvidia/nemotron-3-nano-omni-30b-a3b"
24
 
25
  PROMPT = (
 
39
 
40
  class AnimalAI:
41
  def __init__(self):
42
+ self.mode = None # "hf" | "nim"
43
  self.model = None
44
+ self.client = None # OpenAI (NIM) ou InferenceClient (HF)
45
 
46
  hf_token = os.environ.get("HF_TOKEN", "")
47
  nvidia_key = os.environ.get("NVIDIA_API_KEY", "")
48
 
49
+ if nvidia_key:
50
+ try:
51
+ from openai import OpenAI
52
+ self.mode = "nim"
53
  self.model = os.environ.get("NVIDIA_MODEL", _NIM_MODEL)
54
  self.client = OpenAI(
55
  base_url="https://integrate.api.nvidia.com/v1",
56
  api_key=nvidia_key,
57
  )
58
+ log.info("AI: Nemotron Omni via NVIDIA NIM (%s)", self.model)
59
+ except ImportError:
60
+ log.warning("openai nao instalado")
61
 
62
+ elif hf_token:
63
+ try:
64
+ from huggingface_hub import InferenceClient
65
+ self.mode = "hf"
66
  self.model = os.environ.get("NVIDIA_MODEL", _HF_MODEL)
67
+ self.client = InferenceClient(model=self.model, token=hf_token)
68
+ log.info("AI: %s via HF InferenceClient", self.model)
69
+ except ImportError:
70
+ log.warning("huggingface_hub nao instalado")
 
 
 
 
71
 
72
+ else:
73
+ log.warning("Sem chave de API β€” IA desabilitada. Configure HF_TOKEN nos Secrets.")
74
 
75
  self.embedder = None
76
  try:
 
81
  log.warning("sentence-transformers nao carregou: %s", e)
82
 
83
  def analyze_image(self, image) -> dict:
84
+ """Analisa imagem. _ai_success=False indica que a IA nao foi usada."""
85
  if self.client is None:
86
  return self._fallback()
87
 
88
  try:
89
  img_b64 = self._to_b64(image)
90
+
91
+ if self.mode == "hf":
92
+ # HuggingFace InferenceClient β€” suporte nativo a multimodal
93
+ resp = self.client.chat_completion(
94
+ messages=[{
95
+ "role": "user",
96
+ "content": [
97
+ {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64," + img_b64}},
98
+ {"type": "text", "text": PROMPT},
99
+ ],
100
+ }],
101
+ max_tokens=400,
102
+ temperature=0.1,
103
+ )
104
+ raw = resp.choices[0].message.content or ""
105
+ else:
106
+ # NVIDIA NIM β€” OpenAI-compatible
107
+ resp = self.client.chat.completions.create(
108
+ model=self.model,
109
+ messages=[{
110
+ "role": "user",
111
+ "content": [
112
+ {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64," + img_b64}},
113
+ {"type": "text", "text": PROMPT},
114
+ ],
115
+ }],
116
+ max_tokens=400,
117
+ temperature=0.1,
118
+ )
119
+ raw = resp.choices[0].message.content or ""
120
+
121
+ log.info("AI resposta: %s", raw[:200])
122
  result = self._parse(raw)
123
  result["_ai_success"] = True
124
  return result
125
+
126
  except Exception as e:
127
  log.error("Erro na API de IA: %s", e)
128
  return self._fallback()
129
 
130
  def get_embedding(self, description: dict) -> list:
131
+ """Embedding da descricao. Aleatorio se IA falhou (evita falsos matches)."""
 
 
 
132
  if not description.get("_ai_success", True):
133
  log.info("Fallback IA β€” embedding aleatorio")
134
  v = np.random.randn(384).astype(np.float32)