sara.mesquita commited on
Commit
0446dcd
Β·
1 Parent(s): f9f4f9a

Changes nemotron model

Browse files
Files changed (2) hide show
  1. README.md +8 -8
  2. core/ai.py +71 -51
README.md CHANGED
@@ -61,7 +61,7 @@ There are two AI-powered flows: **registering a sighting** and **recording help*
61
 
62
  ```mermaid
63
  flowchart TD
64
- A["πŸ“· Photo from phone"] --> B["πŸ€– Vision AI\nLlama-3.2-11B-Vision\n(HF Serverless)"]
65
  B -->|"is it an animal?"| C{Animal detected?}
66
  C -->|"No"| ERR["❌ Error message\n'No dog or cat identified'"]
67
  C -->|"Yes"| D["πŸ“ Structured JSON\nNemotron Mini 4B Instruct normalizes\nspecies Β· breed Β· color Β· condition Β· marks"]
@@ -106,7 +106,7 @@ The map uses color to signal urgency: **🟒 green** = dog · **🟠 orange** =
106
 
107
  | Component | Model / Library | Where it runs |
108
  |---|---|---|
109
- | Visual identification | **Llama-3.2-11B-Vision-Instruct** (11B) via HF Serverless | remote API |
110
  | Text reasoning / JSON | **Nemotron Mini 4B Instruct** via NVIDIA NIM | remote API |
111
  | Semantic embedding | **all-MiniLM-L6-v2** (384 dim, 22M params) | CPU, local |
112
  | Animal matching | Cosine similarity (threshold 0.80) | CPU, local |
@@ -148,12 +148,12 @@ git clone https://huggingface.co/spaces/build-small-hackathon/viralata-mapper
148
  cd viralata-mapper
149
  pip install -r requirements.txt
150
 
151
- # Vision via HuggingFace Serverless (Llama-3.2-11B-Vision)
152
- HF_TOKEN=hf_... python app.py
153
-
154
- # Add NVIDIA NIM for Nemotron Mini 4B Instruct (structured-output normalization)
155
  NVIDIA_API_KEY=nvapi_... python app.py
156
 
 
 
 
157
  # no key β€” runs in fallback mode without AI identification
158
  python app.py
159
 
@@ -170,8 +170,8 @@ On first run the app seeds the database with demo animals around BrasΓ­lia so th
170
 
171
  | Secret | Description |
172
  |---|---|
173
- | `HF_TOKEN` | HuggingFace token for Llama-3.2-11B-Vision via Serverless Inference |
174
- | `NVIDIA_API_KEY` | NVIDIA NIM key for Nemotron Mini 4B Instruct (structured-output normalization) |
175
  | `MATCH_THRESHOLD` | Optional. Similarity threshold. Default: `0.80` |
176
  | `HF_DATASET_ID` | Optional. Hub dataset for trace publishing (e.g. `org/dataset-name`) |
177
 
 
61
 
62
  ```mermaid
63
  flowchart TD
64
+ A["πŸ“· Photo from phone"] --> B["πŸ€– Vision AI\nLlama-3.2-11B-Vision\n(NVIDIA NIM / HF)"]
65
  B -->|"is it an animal?"| C{Animal detected?}
66
  C -->|"No"| ERR["❌ Error message\n'No dog or cat identified'"]
67
  C -->|"Yes"| D["πŸ“ Structured JSON\nNemotron Mini 4B Instruct normalizes\nspecies Β· breed Β· color Β· condition Β· marks"]
 
106
 
107
  | Component | Model / Library | Where it runs |
108
  |---|---|---|
109
+ | Visual identification | **Llama-3.2-11B-Vision-Instruct** (11B) via NVIDIA NIM (or HF Serverless) | remote API |
110
  | Text reasoning / JSON | **Nemotron Mini 4B Instruct** via NVIDIA NIM | remote API |
111
  | Semantic embedding | **all-MiniLM-L6-v2** (384 dim, 22M params) | CPU, local |
112
  | Animal matching | Cosine similarity (threshold 0.80) | CPU, local |
 
148
  cd viralata-mapper
149
  pip install -r requirements.txt
150
 
151
+ # Recommended: NVIDIA NIM powers both vision (Llama-3.2-11B-Vision) and Nemotron Mini 4B
 
 
 
152
  NVIDIA_API_KEY=nvapi_... python app.py
153
 
154
+ # Alternative: vision via HuggingFace Serverless
155
+ HF_TOKEN=hf_... python app.py
156
+
157
  # no key β€” runs in fallback mode without AI identification
158
  python app.py
159
 
 
170
 
171
  | Secret | Description |
172
  |---|---|
173
+ | `NVIDIA_API_KEY` | NVIDIA NIM key β€” powers **both** vision (Llama-3.2-11B-Vision) and Nemotron Mini 4B normalization. A single key is enough. |
174
+ | `HF_TOKEN` | Optional β€” vision via HF Serverless if you don't use NVIDIA NIM |
175
  | `MATCH_THRESHOLD` | Optional. Similarity threshold. Default: `0.80` |
176
  | `HF_DATASET_ID` | Optional. Hub dataset for trace publishing (e.g. `org/dataset-name`) |
177
 
core/ai.py CHANGED
@@ -1,21 +1,26 @@
1
  """
2
- ai.py β€” Visao via HuggingFace InferenceClient + normalizacao via NVIDIA NIM.
3
 
4
  Arquitetura (todos os modelos < 32B):
5
- - Visao : meta-llama/Llama-3.2-11B-Vision-Instruct (11B, HF Serverless) -> precisa HF_TOKEN
6
- - Texto : nvidia/nemotron-mini-4b-instruct (4B, NVIDIA NIM) -> precisa NVIDIA_API_KEY (opcional)
7
- - Embed : sentence-transformers/all-MiniLM-L6-v2 (22M, local/CPU)
 
8
 
9
- O Llama enxerga a foto e devolve a descricao bruta. Se NVIDIA_API_KEY estiver
10
- configurada, o Nemotron Mini 4B Instruct (texto puro) normaliza esse JSON para o schema
11
  estrito (raca da lista permitida, cores simples, condicao, frase de matching).
12
- Sem NVIDIA_API_KEY, usa-se direto a saida do Llama.
 
 
 
13
 
14
  Variaveis de ambiente:
15
- HF_TOKEN β€” token HuggingFace (HF Serverless Inference) β€” obrigatorio p/ visao
16
- NVIDIA_API_KEY β€” chave NVIDIA NIM (free tier em build.nvidia.com) β€” opcional
17
- HF_VISION_MODEL β€” override do modelo de visao (default Llama-3.2-11B-Vision)
18
- NVIDIA_MODEL β€” override do modelo NIM (default nvidia/nemotron-mini-4b-instruct)
 
19
  """
20
  import base64
21
  import io
@@ -28,10 +33,9 @@ import numpy as np
28
 
29
  log = logging.getLogger(__name__)
30
 
31
- _HF_MODEL = "meta-llama/Llama-3.2-11B-Vision-Instruct"
32
- # String do modelo na API NVIDIA NIM (integrate.api.nvidia.com).
33
- # Confirme o id exato em build.nvidia.com; pode sobrescrever via NVIDIA_MODEL.
34
- _NIM_MODEL = "nvidia/nemotron-mini-4b-instruct" # Nemotron Mini 4B Instruct (texto, 4B)
35
 
36
  PROMPT = (
37
  "Examine this image carefully.\n"
@@ -76,38 +80,45 @@ NORMALIZE_PROMPT = (
76
 
77
  class AnimalAI:
78
  def __init__(self):
79
- self.vision_model = _HF_MODEL
80
- self.vision_client = None # InferenceClient (HF) β€” visao
81
- self.nim_model = _NIM_MODEL
82
- self.nim_client = None # OpenAI client -> NVIDIA NIM β€” texto
 
83
 
84
- hf_token = os.environ.get("HF_TOKEN", "")
85
  nvidia_key = os.environ.get("NVIDIA_API_KEY", "")
 
86
 
87
- # Visao: Llama-3.2-11B-Vision via HF Serverless (obrigatorio para identificar foto)
88
- if hf_token:
89
- try:
90
- from huggingface_hub import InferenceClient
91
- self.vision_model = os.environ.get("HF_VISION_MODEL", _HF_MODEL)
92
- self.vision_client = InferenceClient(model=self.vision_model, token=hf_token)
93
- log.info("Visao: %s via HF InferenceClient", self.vision_model)
94
- except ImportError:
95
- log.warning("huggingface_hub nao instalado")
96
- else:
97
- log.warning("Sem HF_TOKEN β€” visao desabilitada. Configure HF_TOKEN nos Secrets.")
98
-
99
- # Texto: Nemotron Mini 4B Instruct via NVIDIA NIM (opcional β€” normaliza o JSON)
100
  if nvidia_key:
101
  try:
102
  from openai import OpenAI
103
- self.nim_model = os.environ.get("NVIDIA_MODEL", _NIM_MODEL)
104
  self.nim_client = OpenAI(
105
  base_url="https://integrate.api.nvidia.com/v1",
106
  api_key=nvidia_key,
107
  )
108
- log.info("Texto: Nemotron Mini 4B Instruct via NVIDIA NIM (%s)", self.nim_model)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  except ImportError:
110
- log.warning("openai nao instalado β€” normalizacao Nemotron desabilitada")
 
 
 
111
 
112
  self.embedder = None
113
  try:
@@ -124,20 +135,29 @@ class AnimalAI:
124
 
125
  try:
126
  img_b64 = self._to_b64(image)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
- # Visao multimodal β€” Llama-3.2-11B-Vision (HF InferenceClient)
129
- resp = self.vision_client.chat_completion(
130
- messages=[{
131
- "role": "user",
132
- "content": [
133
- {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64," + img_b64}},
134
- {"type": "text", "text": PROMPT},
135
- ],
136
- }],
137
- max_tokens=400,
138
- temperature=0.1,
139
- )
140
- raw = resp.choices[0].message.content or ""
141
  log.info("Visao resposta: %s", raw[:200])
142
  result = self._parse(raw)
143
 
@@ -163,7 +183,7 @@ class AnimalAI:
163
  try:
164
  payload = json.dumps(result, ensure_ascii=False)
165
  resp = self.nim_client.chat.completions.create(
166
- model=self.nim_model,
167
  messages=[{"role": "user", "content": NORMALIZE_PROMPT + payload}],
168
  max_tokens=400,
169
  temperature=0.2,
@@ -178,7 +198,7 @@ class AnimalAI:
178
  "description_text"):
179
  if k in cleaned and cleaned[k] not in (None, "", []):
180
  result[k] = cleaned[k]
181
- log.info("Nemotron 4B normalizou os campos.")
182
  return result
183
  except Exception as e:
184
  log.warning("Nemotron normalize falhou, usando saida da visao: %s", e)
 
1
  """
2
+ ai.py β€” Visao + normalizacao de texto, ambas via NVIDIA NIM (ou HF como alternativa).
3
 
4
  Arquitetura (todos os modelos < 32B):
5
+ - Visao : meta/llama-3.2-11b-vision-instruct (11B, NVIDIA NIM) -> NVIDIA_API_KEY
6
+ (ou meta-llama/Llama-3.2-11B-Vision-Instruct via HF, se so houver HF_TOKEN)
7
+ - Texto : nvidia/nemotron-mini-4b-instruct (4B, NVIDIA NIM) -> NVIDIA_API_KEY
8
+ - Embed : sentence-transformers/all-MiniLM-L6-v2 (22M, local/CPU)
9
 
10
+ Fluxo: o Llama-3.2-11B-Vision enxerga a foto e devolve a descricao bruta. Em
11
+ seguida o Nemotron Mini 4B Instruct (texto puro) normaliza esse JSON para o schema
12
  estrito (raca da lista permitida, cores simples, condicao, frase de matching).
13
+
14
+ Basta a NVIDIA_API_KEY: ela serve tanto para a visao quanto para o Nemotron.
15
+ Se nao houver NVIDIA_API_KEY mas houver HF_TOKEN, a visao usa o HF Serverless
16
+ (sem a etapa de normalizacao do Nemotron).
17
 
18
  Variaveis de ambiente:
19
+ NVIDIA_API_KEY β€” chave NVIDIA NIM (free tier em build.nvidia.com)
20
+ HF_TOKEN β€” token HuggingFace (alternativa de visao via HF Serverless)
21
+ NVIDIA_VISION_MODEL β€” override do modelo de visao NIM (default meta/llama-3.2-11b-vision-instruct)
22
+ NVIDIA_MODEL β€” override do modelo de texto NIM (default nvidia/nemotron-mini-4b-instruct)
23
+ HF_VISION_MODEL β€” override do modelo de visao HF (default meta-llama/Llama-3.2-11B-Vision-Instruct)
24
  """
25
  import base64
26
  import io
 
33
 
34
  log = logging.getLogger(__name__)
35
 
36
+ _HF_MODEL = "meta-llama/Llama-3.2-11B-Vision-Instruct" # id HF Serverless
37
+ _NIM_VISION_MODEL = "meta/llama-3.2-11b-vision-instruct" # id NVIDIA NIM (11B, free)
38
+ _NIM_TEXT_MODEL = "nvidia/nemotron-mini-4b-instruct" # id NVIDIA NIM (4B, free)
 
39
 
40
  PROMPT = (
41
  "Examine this image carefully.\n"
 
80
 
81
  class AnimalAI:
82
  def __init__(self):
83
+ self.vision_mode = None # "nim" | "hf"
84
+ self.vision_model = None
85
+ self.vision_client = None # OpenAI (NIM) ou InferenceClient (HF)
86
+ self.nim_text_model = _NIM_TEXT_MODEL
87
+ self.nim_client = None # OpenAI -> NVIDIA NIM, p/ normalizacao Nemotron
88
 
 
89
  nvidia_key = os.environ.get("NVIDIA_API_KEY", "")
90
+ hf_token = os.environ.get("HF_TOKEN", "")
91
 
92
+ # Cliente NVIDIA NIM (serve para visao Llama E texto Nemotron)
 
 
 
 
 
 
 
 
 
 
 
 
93
  if nvidia_key:
94
  try:
95
  from openai import OpenAI
 
96
  self.nim_client = OpenAI(
97
  base_url="https://integrate.api.nvidia.com/v1",
98
  api_key=nvidia_key,
99
  )
100
+ self.nim_text_model = os.environ.get("NVIDIA_MODEL", _NIM_TEXT_MODEL)
101
+ # Visao via NIM (Llama-3.2-11B-Vision)
102
+ self.vision_mode = "nim"
103
+ self.vision_model = os.environ.get("NVIDIA_VISION_MODEL", _NIM_VISION_MODEL)
104
+ self.vision_client = self.nim_client
105
+ log.info("Visao: %s + Texto: %s via NVIDIA NIM", self.vision_model, self.nim_text_model)
106
+ except ImportError:
107
+ log.warning("openai nao instalado")
108
+
109
+ # Alternativa: visao via HF Serverless (Llama-3.2-11B-Vision) se nao houver NVIDIA
110
+ if self.vision_client is None and hf_token:
111
+ try:
112
+ from huggingface_hub import InferenceClient
113
+ self.vision_mode = "hf"
114
+ self.vision_model = os.environ.get("HF_VISION_MODEL", _HF_MODEL)
115
+ self.vision_client = InferenceClient(model=self.vision_model, token=hf_token)
116
+ log.info("Visao: %s via HF InferenceClient", self.vision_model)
117
  except ImportError:
118
+ log.warning("huggingface_hub nao instalado")
119
+
120
+ if self.vision_client is None:
121
+ log.warning("Sem NVIDIA_API_KEY nem HF_TOKEN β€” IA desabilitada. Configure um dos Secrets.")
122
 
123
  self.embedder = None
124
  try:
 
135
 
136
  try:
137
  img_b64 = self._to_b64(image)
138
+ content = [
139
+ {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64," + img_b64}},
140
+ {"type": "text", "text": PROMPT},
141
+ ]
142
+
143
+ if self.vision_mode == "nim":
144
+ # NVIDIA NIM β€” Llama-3.2-11B-Vision (OpenAI-compatible)
145
+ resp = self.vision_client.chat.completions.create(
146
+ model=self.vision_model,
147
+ messages=[{"role": "user", "content": content}],
148
+ max_tokens=400,
149
+ temperature=0.1,
150
+ )
151
+ raw = resp.choices[0].message.content or ""
152
+ else:
153
+ # HuggingFace InferenceClient β€” suporte nativo a multimodal
154
+ resp = self.vision_client.chat_completion(
155
+ messages=[{"role": "user", "content": content}],
156
+ max_tokens=400,
157
+ temperature=0.1,
158
+ )
159
+ raw = resp.choices[0].message.content or ""
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  log.info("Visao resposta: %s", raw[:200])
162
  result = self._parse(raw)
163
 
 
183
  try:
184
  payload = json.dumps(result, ensure_ascii=False)
185
  resp = self.nim_client.chat.completions.create(
186
+ model=self.nim_text_model,
187
  messages=[{"role": "user", "content": NORMALIZE_PROMPT + payload}],
188
  max_tokens=400,
189
  temperature=0.2,
 
198
  "description_text"):
199
  if k in cleaned and cleaned[k] not in (None, "", []):
200
  result[k] = cleaned[k]
201
+ log.info("Nemotron Mini 4B normalizou os campos.")
202
  return result
203
  except Exception as e:
204
  log.warning("Nemotron normalize falhou, usando saida da visao: %s", e)