PEFT
Safetensors
English
web-agents
gui-agents
mind2web
lora
pointer-network
selective-prediction
calibration
decision-making
fast-decision-model
system-1
model-routing
gui-grounding
Instructions to use senpaicq/m2w-gemma4-e2b-pointer with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use senpaicq/m2w-gemma4-e2b-pointer with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Download code/m2w_prep.py from senpaicq/m2w-gemma4-e2b-pointer: direct link, hf CLI and curl.
- Browser
- Download file 9.25 kB
-
https://huggingface.co/senpaicq/m2w-gemma4-e2b-pointer/resolve/main/code/m2w_prep.py
- Command line
-
hf download hf://senpaicq/m2w-gemma4-e2b-pointer/code/m2w_prep.py
-
curl -L -o m2w_prep.py https://huggingface.co/senpaicq/m2w-gemma4-e2b-pointer/resolve/main/code/m2w_prep.py
9.25 kB
| #!/usr/bin/env python3 | |
| """Multimodal-Mind2Web hazırlığı: her adım için ilk-K aday listesi (görüntüsüz). | |
| Çıktı (her split için bir jsonl.gz): adım başına görev, geçmiş eylemler, işlem türü, | |
| adaylar (tag, kısa metin, kutu; K=0 ise hepsi, TF-IDF sırasıyla), doğru adayın sırası. Ekran görüntüleri BURADA | |
| kaydedilmez; öznitelik çıkarırken akıştan tekrar okunur. | |
| Buradaki sıralama yalnızca ön sıralama (TF-IDF). Gerçek ilk-50 süzgeci m2w_ranker.py'deki DeBERTa. | |
| Gerçek bir satırda TF-IDF doğru öğeyi 554 adayın 349. sırasına koydu: tek başına yetmez. | |
| Kullanım: | |
| python m2w_prep.py --splits train --max_rows 300 --out m2w_smoke | |
| python m2w_prep.py --splits train test_task test_website test_domain --out m2w_all | |
| """ | |
| import argparse | |
| import gzip | |
| import itertools | |
| import json | |
| import os | |
| import re | |
| import zlib | |
| from collections import Counter | |
| import numpy as np | |
| from lxml import etree | |
| from sklearn.feature_extraction.text import TfidfVectorizer | |
| NAME = "osunlp/Multimodal-Mind2Web" | |
| COLS = ["action_uid", "raw_html", "cleaned_html", "operation", "pos_candidates", "neg_candidates", | |
| "website", "domain", "subdomain", "annotation_id", "confirmed_task", | |
| "action_reprs", "target_action_index", "target_action_reprs"] | |
| LABEL_ATTRS = ("aria_label", "placeholder", "title", "name", "alt", "value", "id") | |
| # Yapısal alanlar (aday biçimi denemeleri için): metin öznitelikleri boş değilse, mantıksal öznitelikler varsa (boş değerle bile) saklanır | |
| TEXT_AT = ("role", "type", "aria_label", "aria-label", "placeholder", "title", "name", "alt", "value", "id", | |
| "aria_checked", "aria-checked", "aria_expanded", "aria-expanded", "aria_disabled", "aria-disabled", | |
| "aria_selected", "aria-selected", "aria_haspopup", "aria-haspopup") | |
| BOOL_AT = ("checked", "disabled", "readonly", "required", "selected") | |
| ATTR_KEYS = Counter() # doğru adaylarda hangi öznitelik anahtarları görülüyor (özet için) | |
| def small_attrs(a): | |
| out = {} | |
| for k in TEXT_AT: | |
| v = a.get(k) | |
| if v is not None and str(v).strip(): | |
| out[k] = str(v).strip()[:120] | |
| for k in BOOL_AT: | |
| if k in a: | |
| out[k] = str(a[k])[:10] | |
| return out | |
| def _load(c): | |
| return json.loads(c) if isinstance(c, str) else c | |
| def parse_cand(c): | |
| c = _load(c) | |
| a = _load(c["attributes"]) if c.get("attributes") else {} | |
| bbox = None | |
| r = a.get("bounding_box_rect") | |
| if r: | |
| try: | |
| v = [float(x) for x in (r.split(",") if isinstance(r, str) else r)] | |
| if len(v) == 4: | |
| bbox = v | |
| except ValueError: | |
| pass | |
| return {"tag": c.get("tag", ""), "bid": str(c.get("backend_node_id", a.get("backend_node_id", ""))), | |
| "attrs": a, "bbox": bbox, "orig": bool(c.get("is_original_target", False))} | |
| def node_texts(cleaned_html, bids): | |
| """backend_node_id -> kısa iç metin (alt ağaçtan, ilk birkaç parça).""" | |
| out = {} | |
| if not cleaned_html or not bids: | |
| return out | |
| try: | |
| root = etree.fromstring(cleaned_html.encode("utf-8", "ignore"), | |
| etree.HTMLParser(recover=True, huge_tree=True)) | |
| except Exception: | |
| return out | |
| if root is None: | |
| return out | |
| for el in root.iter(): | |
| b = el.get("backend_node_id") | |
| if b in bids: | |
| t = " ".join("".join(itertools.islice(el.itertext(), 40)).split()) | |
| out[b] = t[:200] | |
| return out | |
| def cand_text(cd, inner): | |
| a = cd["attrs"] | |
| parts = [cd["tag"]] | |
| for k in ("role", "type"): | |
| if a.get(k): | |
| parts.append(str(a[k])) | |
| for k in LABEL_ATTRS: | |
| v = a.get(k) | |
| if v and str(v).strip(): | |
| parts.append(str(v).strip()[:60]) | |
| if inner: | |
| parts.append(inner) | |
| return " | ".join(parts)[:160] | |
| def page_size(raw_html): | |
| m = re.search(r'bounding_box_rect="([^"]+)"', raw_html[:4000]) | |
| if m: | |
| v = m.group(1).split(",") | |
| if len(v) == 4: | |
| return float(v[2]), float(v[3]) | |
| return None, None | |
| def rank(query, texts, bboxes, drop_zero_area): | |
| """Benzerlik puanı ile sıralı indeksler. Alanı sıfır olan öğeler en sona.""" | |
| n = len(texts) | |
| if n == 0: | |
| return [] | |
| try: | |
| vec = TfidfVectorizer(token_pattern=r"[A-Za-z0-9]{2,}", lowercase=True, sublinear_tf=True) | |
| M = vec.fit_transform(texts + [query]) | |
| sc = (M[:n] @ M[n].T).toarray().ravel() | |
| except ValueError: | |
| sc = np.zeros(n) | |
| sc = sc.astype(float) | |
| for i, b in enumerate(bboxes): | |
| if b is None or b[2] <= 0 or b[3] <= 0: | |
| sc[i] = -1.0 if drop_zero_area else sc[i] - 0.05 | |
| return list(np.argsort(-sc, kind="stable")) | |
| def process_row(r, K, drop_zero_area): | |
| pos = [parse_cand(c) for c in r["pos_candidates"]] | |
| neg = [parse_cand(c) for c in r["neg_candidates"]] | |
| allc = pos + neg | |
| bids = {c["bid"] for c in allc} | |
| texts_in = node_texts(r["cleaned_html"], bids) | |
| texts = [cand_text(c, texts_in.get(c["bid"], "")[:100]) for c in allc] # eski metin: iç metin 100 karakter | |
| idx = int(r["target_action_index"]) | |
| hist = list(r["action_reprs"][:idx]) | |
| query = r["confirmed_task"] + " " + " ".join(re.sub(r"->.*", "", h) for h in hist[-3:]) | |
| order = rank(query, texts, [c["bbox"] for c in allc], drop_zero_area) | |
| if K: | |
| order = order[:K] | |
| pos_b = {c["bid"] for c in pos} | |
| for c in pos: | |
| ATTR_KEYS.update(c["attrs"].keys()) | |
| cands, pos_idx = [], [] | |
| for j, i in enumerate(order): | |
| c = allc[i] | |
| cands.append({"bid": c["bid"], "tag": c["tag"], "text": texts[i], "bbox": c["bbox"], | |
| "inner": texts_in.get(c["bid"], ""), "at": small_attrs(c["attrs"])}) | |
| if c["bid"] in pos_b: | |
| pos_idx.append(j) | |
| pw, ph = page_size(r["raw_html"]) | |
| op = _load(r["operation"]) # gerçek veride JSON metni | |
| return { | |
| "action_uid": r["action_uid"], "ann": r["annotation_id"], "step": idx, | |
| "website": r["website"], "domain": r["domain"], "task": r["confirmed_task"], | |
| "history": hist, "target": r["target_action_reprs"], | |
| "op": op["op"], "value": op.get("value", ""), | |
| "page_w": pw, "page_h": ph, "n_total": len(allc), "n_pos": len(pos), | |
| "cands": cands, "pos_idx": pos_idx, | |
| } | |
| def open_stream(split): | |
| from datasets import load_dataset | |
| try: | |
| return load_dataset(NAME, split=split, streaming=True, columns=COLS) | |
| except Exception as e: # columns desteklenmiyorsa | |
| print("columns= çalışmadı, tüm kolonlarla akış:", type(e).__name__) | |
| ds = load_dataset(NAME, split=split, streaming=True) | |
| return ds.remove_columns([c for c in ("screenshot",) if c]) | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--splits", nargs="+", default=["train"]) | |
| ap.add_argument("--out", default="m2w") | |
| ap.add_argument("--K", type=int, default=0, help="0 = tüm adaylar") | |
| ap.add_argument("--max_rows", type=int, default=0) | |
| ap.add_argument("--val_mod", type=int, default=8, help="eğitim sitelerinin 1/val_mod kadarı doğrulamaya") | |
| ap.add_argument("--keep_zero_area", action="store_true") | |
| args = ap.parse_args() | |
| os.makedirs(args.out, exist_ok=True) | |
| for split in args.splits: | |
| ds = open_stream(split) | |
| if args.max_rows: | |
| ds = ds.take(args.max_rows) | |
| outs = {} | |
| st = Counter() | |
| n_cand = [] | |
| for k, r in enumerate(ds): | |
| ex = process_row(r, args.K, not args.keep_zero_area) | |
| name = split | |
| if split == "train": | |
| name = "val" if zlib.crc32(ex["website"].encode()) % args.val_mod == 0 else "train" | |
| if name not in outs: | |
| outs[name] = gzip.open(os.path.join(args.out, f"{name}.jsonl.gz"), "wt", encoding="utf-8") | |
| ex["split"] = name | |
| outs[name].write(json.dumps(ex, ensure_ascii=False) + "\n") | |
| st[f"{name}/n"] += 1 | |
| st[f"{name}/op_{ex['op']}"] += 1 | |
| st[f"{name}/pos_yok"] += ex["n_pos"] == 0 | |
| st[f"{name}/pos_ilkK_icinde"] += len(ex["pos_idx"]) > 0 | |
| st[f"{name}/pos_ilk1"] += 0 in ex["pos_idx"] | |
| n_cand.append(ex["n_total"]) | |
| if (k + 1) % 500 == 0: | |
| print(f" {split}: {k + 1} adım", flush=True) | |
| for f in outs.values(): | |
| f.close() | |
| print(f"\n== {split} == adaylar/adım: ortanca {int(np.median(n_cand))}, en çok {max(n_cand)}") | |
| for name in sorted({k.split('/')[0] for k in st}): | |
| n = st[f"{name}/n"] | |
| print(f" [{name}] adım={n} | doğru aday listede yok={st[name+'/pos_yok']} " | |
| f"| recall@{args.K or 'hepsi'}={st[name+'/pos_ilkK_icinde']/n:.3f} | top1={st[name+'/pos_ilk1']/n:.3f} " | |
| f"| CLICK={st[name+'/op_CLICK']} TYPE={st[name+'/op_TYPE']} SELECT={st[name+'/op_SELECT']}") | |
| print("\ndoğru adaylarda görülen öznitelik anahtarları (ilk 40):", ATTR_KEYS.most_common(40)) | |
| json.dump(dict(ATTR_KEYS.most_common(200)), open(os.path.join(args.out, "oznitelik_anahtarlari.json"), "w"), indent=1) | |
| print("\nyazıldı:", args.out) | |
| if __name__ == "__main__": | |
| main() | |