| |
| |
| |
| |
| import spaces |
| import ast |
| import torch |
| import gradio as gr |
| from transformers import Qwen2VLForConditionalGeneration, AutoProcessor |
| from qwen_vl_utils import process_vision_info |
|
|
| MODEL_ID = "showlab/ShowUI-2B" |
|
|
| _SYSTEM = ( |
| "Based on the screenshot of the page, I give a text description and you give its " |
| "corresponding location. The coordinate represents a clickable location [x, y] " |
| "for an element, which is a relative coordinate on the screenshot, scaled from 0 to 1." |
| ) |
|
|
| min_pixels = 256 * 28 * 28 |
| max_pixels = 1344 * 28 * 28 |
|
|
| |
| model = Qwen2VLForConditionalGeneration.from_pretrained( |
| MODEL_ID, torch_dtype=torch.bfloat16 |
| ) |
| processor = AutoProcessor.from_pretrained( |
| "Qwen/Qwen2-VL-2B-Instruct", min_pixels=min_pixels, max_pixels=max_pixels |
| ) |
|
|
|
|
| @spaces.GPU(duration=60) |
| def localizar(imagen, consulta): |
| """imagen: ruta de la captura. consulta: qué elemento clicar (mejor en inglés).""" |
| if imagen is None or not (consulta or "").strip(): |
| return "ERROR: falta imagen o consulta" |
| model.to("cuda") |
| messages = [{ |
| "role": "user", |
| "content": [ |
| {"type": "text", "text": _SYSTEM}, |
| {"type": "image", "image": imagen, |
| "min_pixels": min_pixels, "max_pixels": max_pixels}, |
| {"type": "text", "text": consulta}, |
| ], |
| }] |
| text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) |
| image_inputs, video_inputs = process_vision_info(messages) |
| inputs = processor(text=[text], images=image_inputs, videos=video_inputs, |
| padding=True, return_tensors="pt").to("cuda") |
| generated = model.generate(**inputs, max_new_tokens=128) |
| trimmed = [out[len(inp):] for inp, out in zip(inputs.input_ids, generated)] |
| out_text = processor.batch_decode( |
| trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False |
| )[0] |
| try: |
| coords = ast.literal_eval(out_text) |
| return f"{float(coords[0]):.4f},{float(coords[1]):.4f}" |
| except Exception: |
| return f"ERROR: {out_text}" |
|
|
|
|
| with gr.Blocks(title="Fénix Grounding") as demo: |
| gr.Markdown("## 🎯 Fénix Grounding — ShowUI-2B\n" |
| "Sube una captura y describe el elemento; devuelve x,y (0-1).") |
| with gr.Row(): |
| img = gr.Image(label="Captura", type="filepath") |
| with gr.Column(): |
| q = gr.Textbox(label="Qué clicar (mejor en inglés)", |
| placeholder="Notepad icon in the taskbar") |
| btn = gr.Button("Localizar", variant="primary") |
| out = gr.Textbox(label="Coordenadas x,y (0-1)") |
| btn.click(localizar, [img, q], out, api_name="localizar") |
|
|
| demo.launch() |
|
|