Hug0endob commited on
Commit
e6159f2
·
verified ·
1 Parent(s): 5bf99a0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +16 -46
app.py CHANGED
@@ -1,6 +1,4 @@
1
  #!/usr/bin/env python3
2
- # Single-file Gradio app: reliable preview, image->image model, video->video model or frame fallback,
3
- # streaming disabled for safety; preserves default prompt text unchanged.
4
  import os
5
  import subprocess
6
  import tempfile
@@ -44,7 +42,6 @@ def ext_from_src(src: str) -> str:
44
 
45
  def fetch_bytes(src: str, stream_threshold=STREAM_THRESHOLD, timeout=60) -> bytes:
46
  if is_remote(src):
47
- # HEAD first to make preview/size decision; fallback to GET if HEAD fails
48
  try:
49
  h = requests.head(src, timeout=6, allow_redirects=True)
50
  h.raise_for_status()
@@ -98,19 +95,10 @@ def convert_to_jpeg_bytes(img_bytes: bytes, base_h: int = 480) -> bytes:
98
  def b64_jpeg(img_bytes: bytes) -> str:
99
  return base64.b64encode(img_bytes).decode("utf-8")
100
 
101
- def extract_best_frames_bytes(media_path: str, sample_count: int = 5, timeout_probe: int = 10, timeout_extract: int = 15) -> list:
102
  if not FFMPEG_BIN or not os.path.exists(media_path):
103
  return []
104
- # Use ffprobe fallback if available; avoid unsupported flags
105
- try:
106
- probe_cmd = [FFMPEG_BIN, "-v", "error", "-i", media_path, "-hide_banner"]
107
- subprocess.run(probe_cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=timeout_probe)
108
- # best-effort timestamps if probing failed to get duration
109
- # We'll still try a few timestamps
110
- except Exception:
111
- pass
112
- # generate timestamps heuristically
113
- timestamps = [0.5, 1.0, 2.0][:sample_count]
114
  frames = []
115
  for i, t in enumerate(timestamps):
116
  fd, tmp = tempfile.mkstemp(suffix=f"_{i}.jpg")
@@ -164,7 +152,7 @@ def extract_text_from_response(res, parts: list):
164
  return
165
  try:
166
  first = choices[0]
167
- msg = first.message if hasattr(first, "message") else first.get("message", first)
168
  if isinstance(msg, dict):
169
  content = msg.get("content")
170
  else:
@@ -183,7 +171,7 @@ def chat_complete(client: Mistral, model: str, messages: list) -> str:
183
  return "".join(parts).strip()
184
 
185
  def analyze_image(client: Mistral, img_bytes: bytes, prompt: str) -> str:
186
- jpeg = convert_to_jpeg_bytes(img_bytes, base_h=480)
187
  b64 = b64_jpeg(jpeg)
188
  msgs = build_messages_for_image(prompt, b64)
189
  return chat_complete(client, PIXTRAL_MODEL, msgs)
@@ -240,10 +228,7 @@ def process_media(src: str, custom_prompt: str, api_key: str) -> str:
240
  try:
241
  try:
242
  file_id = upload_file_to_mistral(client, tmp_path, filename=os.path.basename(src.split("?")[0]))
243
- extra = (
244
- f"Uploaded video to Mistral Files with id: {file_id}\n\n"
245
- "Instruction: Analyze the video contents using the uploaded file id. Do not invent frames not present."
246
- )
247
  msgs = build_messages_for_text(prompt, extra)
248
  return chat_complete(client, VIDEO_MODEL, msgs)
249
  except Exception:
@@ -260,39 +245,36 @@ css = ".preview_media img, .preview_media video { max-width: 100%; height: auto;
260
 
261
  def load_preview(url: str):
262
  if not url:
263
- return None, None, ""
264
- # Local file path handling
265
  if not is_remote(url) and os.path.exists(url):
266
  ext = ext_from_src(url)
267
  if ext in VIDEO_EXTS:
268
- return None, os.path.abspath(url), "Video"
269
  if ext in IMAGE_EXTS:
270
  try:
271
  img = Image.open(url)
272
  if getattr(img, "is_animated", False):
273
  img.seek(0)
274
- return img.convert("RGB"), None, "Image"
275
  except Exception:
276
- return None, None, "Preview failed"
277
- # Remote: HEAD then GET fallback; ensure returned types match Gradio Image/Video expectations
278
  try:
279
  h = requests.head(url, timeout=6, allow_redirects=True)
280
- h.raise_for_status()
281
- ctype = (h.headers.get("content-type") or "").lower()
282
- if ctype.startswith("video/") or any(url.lower().split("?")[0].endswith(ext) for ext in VIDEO_EXTS):
283
- return None, url, "Video"
284
  except Exception:
285
  pass
286
  try:
287
- # GET and try to open as image
288
  r = requests.get(url, timeout=15)
289
  r.raise_for_status()
290
  img = Image.open(BytesIO(r.content))
291
  if getattr(img, "is_animated", False):
292
  img.seek(0)
293
- return img.convert("RGB"), None, "Image"
294
  except Exception:
295
- return None, None, "Preview failed"
296
 
297
  with gr.Blocks(title="Flux Multimodal (fixed)", css=css) as demo:
298
  with gr.Row():
@@ -307,21 +289,9 @@ with gr.Blocks(title="Flux Multimodal (fixed)", css=css) as demo:
307
  with gr.Column(scale=2):
308
  final_md = gr.Markdown(value="")
309
 
310
- def preview_update(url):
311
- img, vid, label = load_preview(url)
312
- show_img = label == "Image"
313
- show_vid = label == "Video"
314
- # Return values in order matching outputs assigned below
315
- return (img if show_img else None, vid if show_vid else None, show_img, show_vid)
316
-
317
- # wire change: outputs must match component types exactly
318
- url_input.change(fn=preview_update,
319
- inputs=[url_input],
320
- outputs=[preview_image, preview_video, preview_image, preview_video])
321
-
322
  def submit_wrapper(url, prompt, key):
323
  return process_media(url, prompt, key)
324
-
325
  submit_btn.click(fn=submit_wrapper, inputs=[url_input, custom_prompt, api_key], outputs=[final_md])
326
 
327
  if __name__ == "__main__":
 
1
  #!/usr/bin/env python3
 
 
2
  import os
3
  import subprocess
4
  import tempfile
 
42
 
43
  def fetch_bytes(src: str, stream_threshold=STREAM_THRESHOLD, timeout=60) -> bytes:
44
  if is_remote(src):
 
45
  try:
46
  h = requests.head(src, timeout=6, allow_redirects=True)
47
  h.raise_for_status()
 
95
  def b64_jpeg(img_bytes: bytes) -> str:
96
  return base64.b64encode(img_bytes).decode("utf-8")
97
 
98
+ def extract_best_frames_bytes(media_path: str, sample_count: int = 5, timeout_extract: int = 15) -> list:
99
  if not FFMPEG_BIN or not os.path.exists(media_path):
100
  return []
101
+ timestamps = [0.5, 1.0, 2.0, 3.0, 4.0][:sample_count]
 
 
 
 
 
 
 
 
 
102
  frames = []
103
  for i, t in enumerate(timestamps):
104
  fd, tmp = tempfile.mkstemp(suffix=f"_{i}.jpg")
 
152
  return
153
  try:
154
  first = choices[0]
155
+ msg = first.message if hasattr(first, "message") else (first.get("message") if isinstance(first, dict) else first)
156
  if isinstance(msg, dict):
157
  content = msg.get("content")
158
  else:
 
171
  return "".join(parts).strip()
172
 
173
  def analyze_image(client: Mistral, img_bytes: bytes, prompt: str) -> str:
174
+ jpeg = convert_to_jpeg_bytes(img_bytes, base_h=640)
175
  b64 = b64_jpeg(jpeg)
176
  msgs = build_messages_for_image(prompt, b64)
177
  return chat_complete(client, PIXTRAL_MODEL, msgs)
 
228
  try:
229
  try:
230
  file_id = upload_file_to_mistral(client, tmp_path, filename=os.path.basename(src.split("?")[0]))
231
+ extra = f"Uploaded video to Mistral Files with id: {file_id}\n\nInstruction: Analyze the video contents using the uploaded file id. Do not invent frames not present."
 
 
 
232
  msgs = build_messages_for_text(prompt, extra)
233
  return chat_complete(client, VIDEO_MODEL, msgs)
234
  except Exception:
 
245
 
246
  def load_preview(url: str):
247
  if not url:
248
+ return gr.update(value=None, visible=False), gr.update(value=None, visible=False)
 
249
  if not is_remote(url) and os.path.exists(url):
250
  ext = ext_from_src(url)
251
  if ext in VIDEO_EXTS:
252
+ return gr.update(value=None, visible=False), gr.update(value=os.path.abspath(url), visible=True)
253
  if ext in IMAGE_EXTS:
254
  try:
255
  img = Image.open(url)
256
  if getattr(img, "is_animated", False):
257
  img.seek(0)
258
+ return gr.update(value=img.convert("RGB"), visible=True), gr.update(value=None, visible=False)
259
  except Exception:
260
+ return gr.update(value=None, visible=False), gr.update(value=None, visible=False)
 
261
  try:
262
  h = requests.head(url, timeout=6, allow_redirects=True)
263
+ if h.ok:
264
+ ctype = (h.headers.get("content-type") or "").lower()
265
+ if ctype.startswith("video/") or any(url.lower().split("?")[0].endswith(ext) for ext in VIDEO_EXTS):
266
+ return gr.update(value=None, visible=False), gr.update(value=url, visible=True)
267
  except Exception:
268
  pass
269
  try:
 
270
  r = requests.get(url, timeout=15)
271
  r.raise_for_status()
272
  img = Image.open(BytesIO(r.content))
273
  if getattr(img, "is_animated", False):
274
  img.seek(0)
275
+ return gr.update(value=img.convert("RGB"), visible=True), gr.update(value=None, visible=False)
276
  except Exception:
277
+ return gr.update(value=None, visible=False), gr.update(value=None, visible=False)
278
 
279
  with gr.Blocks(title="Flux Multimodal (fixed)", css=css) as demo:
280
  with gr.Row():
 
289
  with gr.Column(scale=2):
290
  final_md = gr.Markdown(value="")
291
 
292
+ url_input.change(fn=load_preview, inputs=[url_input], outputs=[preview_image, preview_video])
 
 
 
 
 
 
 
 
 
 
 
293
  def submit_wrapper(url, prompt, key):
294
  return process_media(url, prompt, key)
 
295
  submit_btn.click(fn=submit_wrapper, inputs=[url_input, custom_prompt, api_key], outputs=[final_md])
296
 
297
  if __name__ == "__main__":