SonicaB commited on
Commit
88239ed
·
verified ·
1 Parent(s): 5a39642

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. fusion-app/app_local.py +55 -53
fusion-app/app_local.py CHANGED
@@ -7,6 +7,8 @@ from pydub import AudioSegment
7
  from utils_media import video_to_frame_audio, load_audio_16k, log_inference
8
  from fusion import clip_image_probs, wav2vec2_embed_energy, wav2vec2_zero_shot_probs, audio_prior_from_rms, fuse_probs, top1_label_from_probs
9
  from fusion import _ensure_audio_prototypes, _proto_embs
 
 
10
 
11
  HERE = Path(__file__).parent
12
  lables_PATH = HERE / "labels.json"
@@ -28,41 +30,31 @@ def _img_to_jpeg_bytes(pil: Image.Image) -> bytes:
28
  pil.convert("RGB").save(buf, format="JPEG", quality=90)
29
  return buf.getvalue()
30
 
31
- def clip_api_probs(pil: Image.Image, prompts_list=None):
32
- if prompts_list is None:
33
- prompts_list = prompts
34
- if USER_HF_TOKEN is None:
35
- raise RuntimeError("Please sign in with your HuggingFace token to use API mode.")
36
-
37
  try:
38
- img_bytes = _img_to_jpeg_bytes(pil)
39
- url = f"https://api-inference.huggingface.co/models/{CLIP_MODEL}"
40
- headers = {"Authorization": f"Bearer {USER_HF_TOKEN}"}
41
- payload = {
42
- "parameters": {
43
- "candidate_labels": prompts_list,
44
- "hypothesis_template": "{}"
45
- }
46
- }
47
- files = {"file": ("image.jpg", img_bytes, "image/jpeg")}
48
- data = {"inputs": "", "parameters": json.dumps(payload["parameters"])}
49
-
50
- response = requests.post(url, headers=headers, files=files, data=data, timeout=60)
51
- response.raise_for_status()
52
- result = response.json()
53
-
54
- if isinstance(result, list) and len(result) > 0:
55
- scores = {item["label"]: item["score"] for item in result}
56
- else:
57
- scores = {p: 1.0/len(prompts_list) for p in prompts_list}
58
-
59
- arr = np.array([scores.get(p, 0.0) for p in prompts_list], dtype=np.float32)
60
- s = arr.sum()
61
- arr = arr / s if s > 0 else np.ones_like(arr)/len(arr)
62
- return arr
63
- except Exception as e:
64
- print(f"CLIP API error: {e}")
65
- return np.ones(len(prompts_list), dtype=np.float32) / len(prompts_list)
66
 
67
  def _wave_float32_to_wav_bytes(wave_16k: np.ndarray, sr=16000) -> bytes:
68
  samples = (np.clip(wave_16k, -1, 1) * 32767.0).astype(np.int16)
@@ -71,16 +63,26 @@ def _wave_float32_to_wav_bytes(wave_16k: np.ndarray, sr=16000) -> bytes:
71
  seg.export(out, format="wav")
72
  return out.getvalue()
73
 
74
- def w2v2_api_embed(wave_16k: np.ndarray) -> np.ndarray:
75
- if USER_HF_TOKEN is None:
76
- raise RuntimeError("Please sign in with your HuggingFace token to use API mode.")
77
-
78
- wav_bytes = _wave_float32_to_wav_bytes(wave_16k)
79
- url = f"https://api-inference.huggingface.co/models/{W2V2_MODEL}"
80
- hdrs = {"Authorization": f"Bearer {USER_HF_TOKEN}"}
81
- r = requests.post(url, headers=hdrs, data=wav_bytes, timeout=60)
82
- r.raise_for_status()
83
- arr = np.asarray(r.json(), dtype=np.float32)
 
 
 
 
 
 
 
 
 
 
84
  if arr.ndim == 3:
85
  arr = arr[0]
86
  vec = arr.mean(axis=0)
@@ -117,20 +119,20 @@ def _synthesize_audio_prototypes_api(sr=16000, dur=2.0):
117
  "sad": _triad(sr, 262, minor=True, dur=dur, amp=0.20),
118
  }
119
 
120
- def _ensure_proto_embs_api():
121
  global _PROTO_EMBS_API
122
  if _PROTO_EMBS_API is not None:
123
  return
124
  waves = _synthesize_audio_prototypes_api()
125
  embs = {}
126
  for lbl, wav in waves.items():
127
- e = w2v2_api_embed(wav)
128
  embs[lbl] = e
129
  _PROTO_EMBS_API = embs
130
 
131
- def w2v2_api_zero_shot_probs(wave_16k: np.ndarray, temperature: float = 1.0) -> np.ndarray:
132
- _ensure_proto_embs_api()
133
- emb = w2v2_api_embed(wave_16k)
134
  sims = np.array([float(np.dot(emb, _PROTO_EMBS_API[lbl])) for lbl in lables], dtype=np.float32)
135
  z = sims / max(1e-6, float(temperature))
136
  z = z - z.max()
@@ -217,12 +219,12 @@ def predict_vid_api(video, alpha=0.7):
217
  frames, wave, meta = video_to_frame_audio(video, target_frames=24, fps_cap=2.0)
218
 
219
  t_img0 = time.time()
220
- per_frame = [clip_api_probs(pil) for pil in frames]
221
  p_img = np.mean(np.stack(per_frame, axis=0), axis=0)
222
  t_img = time.time() - t_img0
223
 
224
  t_aud0 = time.time()
225
- p_aud = w2v2_api_zero_shot_probs(wave, temperature=1.0)
226
  t_aud = time.time() - t_aud0
227
 
228
  t_fus0 = time.time()
@@ -251,11 +253,11 @@ def predict_image_audio_api(image, audio_path, alpha=0.7):
251
  wave = load_audio_16k(audio_path)
252
 
253
  t_img0 = time.time()
254
- p_img = clip_api_probs(image)
255
  t_img = time.time() - t_img0
256
 
257
  t_aud0 = time.time()
258
- p_aud = w2v2_api_zero_shot_probs(wave, temperature=1.0)
259
  t_aud = time.time() - t_aud0
260
 
261
  t_fus0 = time.time()
 
7
  from utils_media import video_to_frame_audio, load_audio_16k, log_inference
8
  from fusion import clip_image_probs, wav2vec2_embed_energy, wav2vec2_zero_shot_probs, audio_prior_from_rms, fuse_probs, top1_label_from_probs
9
  from fusion import _ensure_audio_prototypes, _proto_embs
10
+ from huggingface_hub import InferenceClient
11
+ import requests
12
 
13
  HERE = Path(__file__).parent
14
  lables_PATH = HERE / "labels.json"
 
30
  pil.convert("RGB").save(buf, format="JPEG", quality=90)
31
  return buf.getvalue()
32
 
33
+ def clip_api_probs(pil_img, prompts, token):
34
+ """
35
+ Zero-shot image classification via CLIP using the official client.
36
+ Returns a normalized np.array of shape [len(prompts)].
37
+ """
38
+ client = InferenceClient(token=token)
39
  try:
40
+ # Note: parameter name is candidate_labels (not labels)
41
+ result = client.zero_shot_image_classification(
42
+ image=pil_img,
43
+ candidate_labels=prompts,
44
+ hypothesis_template="{}",
45
+ model="openai/clip-vit-base-patch32",
46
+ ) # -> list of {label, score}
47
+ except requests.HTTPError as e:
48
+ # Graceful fallback: if serverless 404s, call your local CLIP path
49
+ if getattr(e, "response", None) and e.response.status_code == 404:
50
+ from fusion import clip_image_probs as local_clip
51
+ return local_clip(pil_img)
52
+ raise
53
+
54
+ scores = {d["label"]: float(d["score"]) for d in result}
55
+ arr = np.array([scores.get(p, 0.0) for p in prompts], dtype=np.float32)
56
+ s = arr.sum()
57
+ return (arr / s) if s > 0 else np.ones(len(prompts), dtype=np.float32) / len(prompts)
 
 
 
 
 
 
 
 
 
 
58
 
59
  def _wave_float32_to_wav_bytes(wave_16k: np.ndarray, sr=16000) -> bytes:
60
  samples = (np.clip(wave_16k, -1, 1) * 32767.0).astype(np.int16)
 
63
  seg.export(out, format="wav")
64
  return out.getvalue()
65
 
66
+ def w2v2_api_embed(wave_16k, token):
67
+ """
68
+ Feature extraction via the official client.
69
+ Returns a mean-pooled, L2-normalized embedding (np.float32).
70
+ """
71
+ client = InferenceClient(token=token)
72
+ try:
73
+ feats = client.feature_extraction(
74
+ audio=wave_16k, # 1-D float32 mono PCM @ 16kHz
75
+ model="facebook/wav2vec2-base",
76
+ )
77
+ except requests.HTTPError as e:
78
+ # Graceful fallback to local audio features/classifier if serverless 404s
79
+ if getattr(e, "response", None) and e.response.status_code == 404:
80
+ from fusion import wav2vec2_embed_energy # or your local audio path
81
+ emb, _ = wav2vec2_embed_energy(wave_16k)
82
+ return emb
83
+ raise
84
+
85
+ arr = np.asarray(feats, dtype=np.float32) # [T, D] or [1, T, D]
86
  if arr.ndim == 3:
87
  arr = arr[0]
88
  vec = arr.mean(axis=0)
 
119
  "sad": _triad(sr, 262, minor=True, dur=dur, amp=0.20),
120
  }
121
 
122
+ def _ensure_proto_embs_api(token: str):
123
  global _PROTO_EMBS_API
124
  if _PROTO_EMBS_API is not None:
125
  return
126
  waves = _synthesize_audio_prototypes_api()
127
  embs = {}
128
  for lbl, wav in waves.items():
129
+ e = w2v2_api_embed(wav, token)
130
  embs[lbl] = e
131
  _PROTO_EMBS_API = embs
132
 
133
+ def w2v2_api_zero_shot_probs(wave_16k: np.ndarray, token: str, temperature: float = 1.0) -> np.ndarray:
134
+ _ensure_proto_embs_api(token)
135
+ emb = w2v2_api_embed(wave_16k, token)
136
  sims = np.array([float(np.dot(emb, _PROTO_EMBS_API[lbl])) for lbl in lables], dtype=np.float32)
137
  z = sims / max(1e-6, float(temperature))
138
  z = z - z.max()
 
219
  frames, wave, meta = video_to_frame_audio(video, target_frames=24, fps_cap=2.0)
220
 
221
  t_img0 = time.time()
222
+ per_frame = [clip_api_probs(pil, prompts, USER_HF_TOKEN) for pil in frames]
223
  p_img = np.mean(np.stack(per_frame, axis=0), axis=0)
224
  t_img = time.time() - t_img0
225
 
226
  t_aud0 = time.time()
227
+ p_aud = w2v2_api_zero_shot_probs(wave, USER_HF_TOKEN, temperature=1.0)
228
  t_aud = time.time() - t_aud0
229
 
230
  t_fus0 = time.time()
 
253
  wave = load_audio_16k(audio_path)
254
 
255
  t_img0 = time.time()
256
+ p_img = clip_api_probs(image, prompts, USER_HF_TOKEN)
257
  t_img = time.time() - t_img0
258
 
259
  t_aud0 = time.time()
260
+ p_aud = w2v2_api_zero_shot_probs(wave, USER_HF_TOKEN, temperature=1.0)
261
  t_aud = time.time() - t_aud0
262
 
263
  t_fus0 = time.time()