Feature Extraction
Transformers
Safetensors
Laya
English
multilingual
laya_browser
custom_code
system-1
browser-agent
web-navigation
decision-model
mmbert
mind2web
tilelang
Instructions to use cklxx/laya-browser with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use cklxx/laya-browser with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("feature-extraction", model="cklxx/laya-browser", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("cklxx/laya-browser", trust_remote_code=True, device_map="auto") - Laya
How to use cklxx/laya-browser with Laya:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
File size: 12,444 Bytes
454b3e6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | """Scripted (model-free) solutions for suite C, used to validate every task before it enters the suite.
python apps/suite_c_scripts.py [name-filter] REPEATS=3 -> each script must pass its check every run
python apps/suite_c_scripts.py --probe URL [step ...] interactive probe: print the observed actions after the steps
A script is a list of steps executed against jev's Browser (observe -> pick the action by label -> act):
("click", "label substring") ("fill", "label substring", "text")
("select", "label substring", "option label substring") ("enter",) ("scroll", n) ("sleep", seconds)
Labels match case-insensitively; a "re:" prefix means a regular expression; "#k" suffix picks the k-th match (0-based);
an "@role " prefix (e.g. "@button re:^Search$") restricts the match to that role.
Each task's check is run on the start page too (must FAIL there) and on the final page (must PASS).
"""
import json, os, re, sys, time
sys.path.insert(0, "/home/ckl/projects/S/jev-ultrafast")
os.environ.setdefault("BU_CDP_URL", "http://127.0.0.1:9222")
from jev_ultrafast.browser import Browser, StalePage # noqa: E402
def observe(br, tries=12, settle=0.0):
time.sleep(settle)
for i in range(tries):
try:
return br.observe(screenshot=False)
except StalePage:
if i == tries - 1:
raise
time.sleep(0.5)
def find(page, kind, label):
"""First action of `kind` whose label matches; "@role " prefix restricts the role, "re:" = regex, "#k" = k-th match."""
idx = 0; role = None
if label.startswith("@"):
role, _, label = label[1:].partition(" ")
m = re.search(r"#(\d+)$", label)
if m:
idx, label = int(m.group(1)), label[: m.start()]
if label.startswith("re:"):
pat = re.compile(label[3:], re.I)
hits = [a for a in page["actions"] if a["kind"] == kind and pat.search(a["label"])]
else:
hits = [a for a in page["actions"] if a["kind"] == kind and label.lower() in a["label"].lower()]
if role:
hits = [a for a in hits if a.get("role") == role]
if len(hits) <= idx:
raise LookupError(f"no {kind} action matching {label!r} (have {[a['label'][:40] for a in page['actions'] if a['kind']==kind][:40]})")
return hits[idx]
def find_select(page, label, option):
"""Select action whose <select> label contains `label` and whose option label equals/contains `option`."""
hits = [a for a in page["actions"] if a["kind"] == "select" and label.lower() in a["label"].rsplit(" → ", 1)[0].lower()]
exact = [a for a in hits if a["label"].rsplit(" → ", 1)[1].strip().lower() == option.lower()]
part = [a for a in hits if option.lower() in a["label"].rsplit(" → ", 1)[1].lower()]
if not (exact or part):
raise LookupError(f"no select option {option!r} in dropdown {label!r} (have {[a['label'][-45:] for a in hits][:30]})")
return (exact or part)[0]
def run_steps(br, steps, verbose=False):
"""Execute the steps; returns (final page, number of browser actions performed)."""
page = observe(br)
n = 0
for step in steps:
op = step[0]
if op == "sleep":
page = observe(br, settle=step[1]); continue
if op == "scroll":
for _ in range(step[1] if len(step) > 1 else 1):
a = next((x for x in page["actions"] if x["id"] == "scroll_down"), None)
if a is None: break
try:
br.act(a, page)
except StalePage: # page changed under us: observe again, then scroll
page = observe(br, settle=0.5); continue
page = observe(br); n += 1
if verbose:
print(f" {n:2d}. scroll")
continue
for attempt in range(4): # retry a stale/covered target after a fresh observation
try:
if op == "click":
a = find(page, "click", step[1]); br.act(a, page)
elif op == "fill":
a = find(page, "fill", step[1]); br.act(a, page, text=step[2])
elif op == "select":
a = find_select(page, step[1], step[2]); br.act(a, page)
elif op == "enter":
a = next(x for x in page["actions"] if x["kind"] == "key"); br.act(a, page)
else:
raise ValueError(op)
break
except (StalePage, LookupError, StopIteration) as e:
if attempt == 3:
raise
time.sleep(0.8); page = observe(br)
n += 1
if verbose:
print(f" {n:2d}. {op} {step[1:]}")
page = observe(br, settle=0.6)
time.sleep(1.5) # let a slow navigation land before judging (same as suite run())
return observe(br), n
def show(page, limit=120):
print("URL:", page["url"]); print("TITLE:", page["title"])
print("TEXT:", page["text"][:500].replace("\n", " | "))
for a in page["actions"][:limit]:
extra = "" if a["kind"] != "select" else f" [current={a.get('current_value')}]"
chk = f" checked={a['checked']}" if "checked" in a else ""
print(f" {a['id']:5s} {a['kind']:6s} {a.get('role') or '':9s} {a['label'][:90]!r}{extra}{chk}")
if len(page["actions"]) > limit:
print(f" ... {len(page['actions'])-limit} more")
def parse_cli_step(s):
op, _, rest = s.partition(":")
if op in ("enter",): return ("enter",)
if op == "scroll": return ("scroll", int(rest or 1))
if op == "sleep": return ("sleep", float(rest))
if op == "fill":
lab, _, txt = rest.partition("="); return ("fill", lab, txt)
if op == "select":
lab, _, opt = rest.partition("="); return ("select", lab, opt)
return (op, rest)
# name -> steps (the start URL and the check live in browser_suite_c.TASKS)
SCRIPTS = {
# ---- multi-step ----
"met-sunflowers": [("fill", "Search by subject", "sunflowers"), ("enter",), ("click", "Has image"),
("select", "Relevance", "Date (oldest-newest)")],
"nuget-serilog-tool": [("fill", "Enter packages", "serilog"), ("enter",), ("click", "Package Type: .NET tool"),
("select", "sort package", "Downloads")],
"alpine-curl-filter": [("fill", "Package name", "curl"), ("select", "Branch", "v3.20"), ("select", "Repository", "main"),
("select", "Architecture", "aarch64"), ("enter",)],
"freesound-rain-cc0": [("fill", "Search sounds", "rain"), ("enter",), ("click", "Creative Commons 0"), ("click", "Soundscapes")],
"ats-shampoo-haircare": [("fill", "Search Keywords", "shampoo"), ("enter",), ("select", "All Categories", "Hair Care"),
("click", "Search in product descriptions"), ("click", "@button re:^Search$"), ("select", "Date Old", "Price High > Low")],
"bnf-hugo-printed-p2": [("fill", "Rechercher une notice", "victor hugo"), ("click", "Submit"), ("click", "Texte imprimé"),
("click", "Page suivante")],
"vsm-python-installs": [("fill", "Search Visual Studio Code extensions", "python"), ("enter",), ("click", "Sort By"), ("click", "re:^Installs")],
"wp-cache-commercial-redis": [("fill", "re:^Search$", "cache"), ("enter",), ("click", "Commercial"), ("click", "re:^Redis Object Cache")],
"todomvc-active": [("fill", "What needs to be done", "buy milk"), ("enter",), ("fill", "What needs to be done", "walk the dog"),
("enter",), ("click", "re:^Active$")],
"setlist-radiohead-uk": [("fill", "Artist, Venue", "radiohead"), ("enter",), ("select", "Artist", "Radiohead ("),
("select", "Country", "United Kingdom")],
"jetbrains-rust-free": [("fill", "re:^Search", "rust"), ("enter",), ("click", "re:^free$"), ("click", "re:^plugin icon Rust JetBrains")],
"luarocks-rapidjson": [("fill", "Search modules", "json"), ("enter",), ("click", "Include non-root"), ("click", "@button re:^Search$"),
("click", "re:^rapidjson$")],
"letcode-dropdowns": [("select", "apple", "Apple"), ("select", "super hero", "Batman"), ("select", "programming language", "Swift"),
("scroll", 1), ("select", "Select India", "India")],
"letcode-radio": [("click", "re:^Foo$"), ("click", "re:^Going$"), ("click", "I agree"), ("click", "Remember me")],
"clojars-ring-page3": [("fill", "Search projects", "ring"), ("enter",), ("scroll", 4), ("click", "re:^3$")],
"fred-unemployment-pop": [("fill", "re:^Search", "unemployment rate"), ("enter",), ("click", "Sort by Relevance"), ("click", "re:^Popularity")],
"modrinth-sodium": [("fill", "Search mods", "sodium"), ("enter",), ("click", "re:^1\\.21\\.11$"), ("click", "Sort by"), ("click", "re:^Downloads$")],
"tvmaze-friends-episodes": [("fill", "Search Shows", "friends"), ("enter",), ("click", "re:^Friends$"), ("click", "re:^Episodes$")],
"qaclickjet-form": [("click", "Round Trip"), ("click", "Senior Citizen"), ("select", "INR", "USD"), ("fill", "Type to Select", "India")],
# ---- shorter ----
"cocktail-margarita": [("fill", "Search for a Cocktail", "margarita"), ("enter",), ("click", "re:^Margarita")],
"mealdb-arrabiata": [("fill", "Search for a Meal", "arrabiata"), ("enter",), ("click", "Spicy Arrabiata")],
"gentoo-openrc-talk": [("fill", "Search Gentoo Wiki", "OpenRC"), ("enter",), ("click", "re:^Discussion$")],
"webkit-css-bugs": [("click", "re:^Browse$"), ("click", "re:^WebKit \n"), ("click", "re:^CSS \n")],
"govdata-wetter-energie": [("fill", "Suchbegriff", "Wetter"), ("enter",), ("click", "Energie")],
"fedora-vim-common": [("fill", "re:^Search$", "vim"), ("enter",), ("click", "re:^vim-common$")],
"racket-argo": [("fill", "Search packages", "json"), ("enter",), ("click", "re:^argo$")],
"rdrr-ggplot": [("fill", "packages, doc text", "ggplot"), ("enter",)],
}
def main():
if len(sys.argv) > 1 and sys.argv[1] == "--probe":
br = Browser(sys.argv[2])
try:
page, n = run_steps(br, [parse_cli_step(s) for s in sys.argv[3:]], verbose=True)
show(page)
finally:
br.close()
return
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from browser_suite_c import TASKS, check_page, final_state # noqa: E402
flt = sys.argv[1] if len(sys.argv) > 1 else ""
repeats = int(os.environ.get("REPEATS", "1"))
rows = []
shard, nshards = (int(v) for v in os.environ.get("SHARD", "0/1").split("/")) # SHARD=i/n runs every n-th task
for i, (name, url, goal, check, *extra) in enumerate(TASKS):
if (flt and flt not in name) or i % nshards != shard: continue
for rep in range(repeats):
t0 = time.time(); ok = start_ok = None; n = 0; err = ""
try:
if extra: extra[0](url) # per-task setup (e.g. clear localStorage)
br = Browser(url)
try:
start_ok = check_page(name, check, final_state(br))
page, n = run_steps(br, SCRIPTS[name])
page = final_state(br)
ok = check_page(name, check, page)
final = page["url"]
finally:
br.close()
except Exception as e:
err = f"{type(e).__name__}: {str(e)[:120]}"; final = ""
verdict = "PASS" if (ok and not start_ok) else "FAIL"
rows.append((name, verdict == "PASS", n))
print(f"{verdict} {name:26s} steps={n:2d} start_check={start_ok!s:5s} final_check={ok!s:5s} {time.time()-t0:5.1f}s {final[:60]} {err}", flush=True)
good = sum(r[1] for r in rows)
print(f"\n== {good}/{len(rows)} scripted runs passed")
per = {}; steps = {}
for r in rows: per.setdefault(r[0], []).append(r[1]); steps[r[0]] = max(steps.get(r[0], 0), r[2])
print(" per task: " + " ".join(f"{k}={sum(v)}/{len(v)}({steps[k]} steps)" for k, v in per.items()))
json.dump({k: {"pass": sum(v), "runs": len(v), "steps": steps[k]} for k, v in per.items()},
open(os.environ.get("SCRIPTS_OUT", "/tmp/suite_c_scripts.json"), "w"), indent=1)
if __name__ == "__main__":
main()
|