Skip to content

Commit f16e274

Browse files
committed
updated doc; add _async suffix
1 parent 7f4be31 commit f16e274

File tree

4 files changed

+248
-41
lines changed

4 files changed

+248
-41
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,28 @@ for match in result.results:
487487

488488
---
489489

490+
## 🔄 Async API
491+
492+
For asyncio contexts (FastAPI, async frameworks):
493+
494+
```python
495+
from sentience.async_api import AsyncSentienceBrowser, snapshot_async, click_async, find
496+
497+
async def main():
498+
async with AsyncSentienceBrowser() as browser:
499+
await browser.goto("https://example.com")
500+
snap = await snapshot_async(browser)
501+
button = find(snap, "role=button")
502+
if button:
503+
await click_async(browser, button.id)
504+
505+
asyncio.run(main())
506+
```
507+
508+
**See example:** `examples/async_api_demo.py`
509+
510+
---
511+
490512
## 📋 Reference
491513

492514
<details>

examples/async_api_demo.py

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
"""
2+
Example: Using Async API for asyncio contexts
3+
4+
This example demonstrates how to use the Sentience SDK's async API
5+
when working with asyncio, FastAPI, or other async frameworks.
6+
7+
To run this example:
8+
python -m examples.async_api_demo
9+
10+
Or if sentience is installed:
11+
python examples/async_api_demo.py
12+
"""
13+
14+
import asyncio
15+
import os
16+
17+
# Import async API functions
18+
from sentience.async_api import AsyncSentienceBrowser, click_async, find, press_async, snapshot_async, type_text_async
19+
from sentience.models import SnapshotOptions, Viewport
20+
21+
22+
async def basic_async_example():
23+
"""Basic async browser usage with context manager"""
24+
api_key = os.environ.get("SENTIENCE_API_KEY")
25+
26+
# Use async context manager
27+
async with AsyncSentienceBrowser(api_key=api_key, headless=False) as browser:
28+
# Navigate to a page
29+
await browser.goto("https://example.com")
30+
31+
# Take a snapshot (async)
32+
snap = await snapshot_async(browser)
33+
print(f"✅ Found {len(snap.elements)} elements on the page")
34+
35+
# Find an element
36+
link = find(snap, "role=link")
37+
if link:
38+
print(f"Found link: {link.text} (id: {link.id})")
39+
40+
# Click it (async)
41+
result = await click_async(browser, link.id)
42+
print(f"Click result: success={result.success}, outcome={result.outcome}")
43+
44+
45+
async def custom_viewport_example():
46+
"""Example using custom viewport with Viewport class"""
47+
# Use Viewport class for type safety
48+
custom_viewport = Viewport(width=1920, height=1080)
49+
50+
async with AsyncSentienceBrowser(viewport=custom_viewport, headless=False) as browser:
51+
await browser.goto("https://example.com")
52+
53+
# Verify viewport size
54+
viewport_size = await browser.page.evaluate(
55+
"() => ({ width: window.innerWidth, height: window.innerHeight })"
56+
)
57+
print(f"✅ Viewport: {viewport_size['width']}x{viewport_size['height']}")
58+
59+
60+
async def snapshot_with_options_example():
61+
"""Example using SnapshotOptions with async API"""
62+
async with AsyncSentienceBrowser(headless=False) as browser:
63+
await browser.goto("https://example.com")
64+
65+
# Take snapshot with options
66+
options = SnapshotOptions(
67+
limit=10,
68+
screenshot=False,
69+
show_overlay=False,
70+
)
71+
snap = await snapshot_async(browser, options)
72+
print(f"✅ Snapshot with limit=10: {len(snap.elements)} elements")
73+
74+
75+
async def actions_example():
76+
"""Example of all async actions"""
77+
async with AsyncSentienceBrowser(headless=False) as browser:
78+
await browser.goto("https://example.com")
79+
80+
# Take snapshot
81+
snap = await snapshot_async(browser)
82+
83+
# Find a textbox if available
84+
textbox = find(snap, "role=textbox")
85+
if textbox:
86+
# Type text (async)
87+
result = await type_text_async(browser, textbox.id, "Hello, World!")
88+
print(f"✅ Typed text: success={result.success}")
89+
90+
# Press a key (async)
91+
result = await press_async(browser, "Enter")
92+
print(f"✅ Pressed Enter: success={result.success}")
93+
94+
95+
async def from_existing_context_example():
96+
"""Example using from_existing() with existing Playwright context"""
97+
from playwright.async_api import async_playwright
98+
99+
async with async_playwright() as p:
100+
# Create your own Playwright context
101+
context = await p.chromium.launch_persistent_context("", headless=True)
102+
103+
try:
104+
# Create SentienceBrowser from existing context
105+
browser = await AsyncSentienceBrowser.from_existing(context)
106+
await browser.goto("https://example.com")
107+
108+
# Use Sentience SDK functions
109+
snap = await snapshot_async(browser)
110+
print(f"✅ Using existing context: {len(snap.elements)} elements")
111+
finally:
112+
await context.close()
113+
114+
115+
async def from_existing_page_example():
116+
"""Example using from_page() with existing Playwright page"""
117+
from playwright.async_api import async_playwright
118+
119+
async with async_playwright() as p:
120+
browser_instance = await p.chromium.launch(headless=True)
121+
context = await browser_instance.new_context()
122+
page = await context.new_page()
123+
124+
try:
125+
# Create SentienceBrowser from existing page
126+
sentience_browser = await AsyncSentienceBrowser.from_page(page)
127+
await sentience_browser.goto("https://example.com")
128+
129+
# Use Sentience SDK functions
130+
snap = await snapshot_async(sentience_browser)
131+
print(f"✅ Using existing page: {len(snap.elements)} elements")
132+
finally:
133+
await context.close()
134+
await browser_instance.close()
135+
136+
137+
async def multiple_browsers_example():
138+
"""Example running multiple browsers concurrently"""
139+
async def process_site(url: str):
140+
async with AsyncSentienceBrowser(headless=True) as browser:
141+
await browser.goto(url)
142+
snap = await snapshot_async(browser)
143+
return {"url": url, "elements": len(snap.elements)}
144+
145+
# Process multiple sites concurrently
146+
urls = [
147+
"https://example.com",
148+
"https://httpbin.org/html",
149+
]
150+
151+
results = await asyncio.gather(*[process_site(url) for url in urls])
152+
for result in results:
153+
print(f"✅ {result['url']}: {result['elements']} elements")
154+
155+
156+
async def main():
157+
"""Run all examples"""
158+
print("=== Basic Async Example ===")
159+
await basic_async_example()
160+
161+
print("\n=== Custom Viewport Example ===")
162+
await custom_viewport_example()
163+
164+
print("\n=== Snapshot with Options Example ===")
165+
await snapshot_with_options_example()
166+
167+
print("\n=== Actions Example ===")
168+
await actions_example()
169+
170+
print("\n=== From Existing Context Example ===")
171+
await from_existing_context_example()
172+
173+
print("\n=== From Existing Page Example ===")
174+
await from_existing_page_example()
175+
176+
print("\n=== Multiple Browsers Concurrent Example ===")
177+
await multiple_browsers_example()
178+
179+
print("\n✅ All async examples completed!")
180+
181+
182+
if __name__ == "__main__":
183+
# Run the async main function
184+
asyncio.run(main())
185+

sentience/async_api.py

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ async def from_page(
498498
# ========== Async Snapshot Functions ==========
499499

500500

501-
async def snapshot(
501+
async def snapshot_async(
502502
browser: AsyncSentienceBrowser,
503503
options: SnapshotOptions | None = None,
504504
) -> Snapshot:
@@ -515,10 +515,10 @@ async def snapshot(
515515
516516
Example:
517517
# Basic snapshot with defaults
518-
snap = await snapshot(browser)
518+
snap = await snapshot_async(browser)
519519
520520
# With options
521-
snap = await snapshot(browser, SnapshotOptions(
521+
snap = await snapshot_async(browser, SnapshotOptions(
522522
screenshot=True,
523523
limit=100,
524524
show_overlay=True
@@ -535,13 +535,13 @@ async def snapshot(
535535

536536
if should_use_api and browser.api_key:
537537
# Use server-side API (Pro/Enterprise tier)
538-
return await _snapshot_via_api(browser, options)
538+
return await _snapshot_via_api_async(browser, options)
539539
else:
540540
# Use local extension (Free tier)
541-
return await _snapshot_via_extension(browser, options)
541+
return await _snapshot_via_extension_async(browser, options)
542542

543543

544-
async def _snapshot_via_extension(
544+
async def _snapshot_via_extension_async(
545545
browser: AsyncSentienceBrowser,
546546
options: SnapshotOptions,
547547
) -> Snapshot:
@@ -619,7 +619,7 @@ async def _snapshot_via_extension(
619619
return snapshot_obj
620620

621621

622-
async def _snapshot_via_api(
622+
async def _snapshot_via_api_async(
623623
browser: AsyncSentienceBrowser,
624624
options: SnapshotOptions,
625625
) -> Snapshot:
@@ -747,7 +747,7 @@ async def _snapshot_via_api(
747747
# ========== Async Action Functions ==========
748748

749749

750-
async def click(
750+
async def click_async(
751751
browser: AsyncSentienceBrowser,
752752
element_id: int,
753753
use_mouse: bool = True,
@@ -773,7 +773,7 @@ async def click(
773773

774774
if use_mouse:
775775
try:
776-
snap = await snapshot(browser)
776+
snap = await snapshot_async(browser)
777777
element = None
778778
for el in snap.elements:
779779
if el.id == element_id:
@@ -851,7 +851,7 @@ async def click(
851851
snapshot_after: Snapshot | None = None
852852
if take_snapshot:
853853
try:
854-
snapshot_after = await snapshot(browser)
854+
snapshot_after = await snapshot_async(browser)
855855
except Exception:
856856
pass
857857

@@ -872,7 +872,7 @@ async def click(
872872
)
873873

874874

875-
async def type_text(
875+
async def type_text_async(
876876
browser: AsyncSentienceBrowser, element_id: int, text: str, take_snapshot: bool = False
877877
) -> ActionResult:
878878
"""
@@ -927,7 +927,7 @@ async def type_text(
927927

928928
snapshot_after: Snapshot | None = None
929929
if take_snapshot:
930-
snapshot_after = await snapshot(browser)
930+
snapshot_after = await snapshot_async(browser)
931931

932932
return ActionResult(
933933
success=True,
@@ -938,7 +938,7 @@ async def type_text(
938938
)
939939

940940

941-
async def press(
941+
async def press_async(
942942
browser: AsyncSentienceBrowser, key: str, take_snapshot: bool = False
943943
) -> ActionResult:
944944
"""
@@ -972,7 +972,7 @@ async def press(
972972

973973
snapshot_after: Snapshot | None = None
974974
if take_snapshot:
975-
snapshot_after = await snapshot(browser)
975+
snapshot_after = await snapshot_async(browser)
976976

977977
return ActionResult(
978978
success=True,
@@ -983,7 +983,7 @@ async def press(
983983
)
984984

985985

986-
async def _highlight_rect(
986+
async def _highlight_rect_async(
987987
browser: AsyncSentienceBrowser, rect: dict[str, float], duration_sec: float = 2.0
988988
) -> None:
989989
"""Highlight a rectangle with a red border overlay (async)"""
@@ -1038,7 +1038,7 @@ async def _highlight_rect(
10381038
)
10391039

10401040

1041-
async def click_rect(
1041+
async def click_rect_async(
10421042
browser: AsyncSentienceBrowser,
10431043
rect: dict[str, float] | BBox,
10441044
highlight: bool = True,
@@ -1093,7 +1093,7 @@ async def click_rect(
10931093

10941094
# Show highlight before clicking
10951095
if highlight:
1096-
await _highlight_rect(browser, {"x": x, "y": y, "w": w, "h": h}, highlight_duration)
1096+
await _highlight_rect_async(browser, {"x": x, "y": y, "w": w, "h": h}, highlight_duration)
10971097
await browser.page.wait_for_timeout(50)
10981098

10991099
# Use Playwright's native mouse click
@@ -1123,7 +1123,7 @@ async def click_rect(
11231123
# Optional snapshot after
11241124
snapshot_after: Snapshot | None = None
11251125
if take_snapshot:
1126-
snapshot_after = await snapshot(browser)
1126+
snapshot_after = await snapshot_async(browser)
11271127

11281128
return ActionResult(
11291129
success=success,
@@ -1150,11 +1150,11 @@ async def click_rect(
11501150

11511151
__all__ = [
11521152
"AsyncSentienceBrowser",
1153-
"snapshot",
1154-
"click",
1155-
"type_text",
1156-
"press",
1157-
"click_rect",
1153+
"snapshot_async",
1154+
"click_async",
1155+
"type_text_async",
1156+
"press_async",
1157+
"click_rect_async",
11581158
"find",
11591159
"query",
11601160
]

0 commit comments

Comments
 (0)