create-browser-app 0.1.12__py3-none-any.whl → 0.1.14__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,13 +10,13 @@ from rich.panel import Panel
10
10
  from rich.text import Text
11
11
  import shutil
12
12
  from .templates import TEMPLATE_BASIC, TEMPLATE_REQUIREMENTS, TEMPLATE_ENV, TEMPLATE_README, TEMPLATE_GITIGNORE
13
- from .template_fetcher import get_template_by_name, fetch_template_content
13
+ from .template_fetcher import fetch_all_template_files
14
14
 
15
15
  console = Console()
16
16
 
17
17
  @click.command()
18
18
  @click.argument('name', default='my-stagehand-app', required=False)
19
- @click.option('--template', '-t', default='basic', help='Template to use (basic or GitHub examples: quickstart, example, agent-example)')
19
+ @click.option('--template', '-t', default='basic', help='Template to use (basic or dynamically fetched from GitHub)')
20
20
  def main(name, template):
21
21
  """Start your Stagehand project with a single command"""
22
22
 
@@ -36,7 +36,11 @@ def main(name, template):
36
36
  console.print("[yellow]Stagehand[/yellow]")
37
37
  console.print("[dim]The AI Browser Framework[/dim]\n")
38
38
 
39
- project_name = name
39
+ # If user specified a template but not a custom name, use the template name
40
+ if name == 'my-stagehand-app' and template != 'basic':
41
+ project_name = template
42
+ else:
43
+ project_name = name
40
44
 
41
45
  # Sanitize project name for directory
42
46
  project_dir = project_name.lower().replace(" ", "-").replace("_", "-")
@@ -54,42 +58,27 @@ def main(name, template):
54
58
  # Create directories
55
59
  project_path.mkdir(parents=True, exist_ok=True)
56
60
 
57
- # Determine which template to use
58
- template_content = TEMPLATE_BASIC
59
-
60
- # If not using basic template, try to fetch from GitHub
61
+ # Fetch template files from GitHub (if not basic)
62
+ template_files = {}
61
63
  if template != 'basic':
62
64
  console.print(f"Fetching template [cyan]{template}[/cyan] from GitHub...")
63
- template_info = get_template_by_name(template)
64
- if template_info:
65
- fetched_content = fetch_template_content(template_info)
66
- if fetched_content:
67
- template_content = fetched_content
68
- console.print(f"[green]✓[/green] Using template from GitHub: {template}")
69
- else:
70
- console.print(f"[yellow]⚠[/yellow] Could not fetch template, using basic template")
65
+ template_files = fetch_all_template_files(template)
66
+ if template_files:
67
+ console.print(f"[green]✓[/green] Fetched {len(template_files)} files from GitHub: {template}")
71
68
  else:
72
- console.print(f"[yellow]⚠[/yellow] Template '{template}' not found, using basic template")
73
-
74
- # Create main.py
75
- main_file = project_path / "main.py"
76
- main_file.write_text(template_content)
77
-
78
- # Create requirements.txt
79
- requirements_file = project_path / "requirements.txt"
80
- requirements_file.write_text(TEMPLATE_REQUIREMENTS)
81
-
82
- # Create .env.example
83
- env_file = project_path / ".env.example"
84
- env_file.write_text(TEMPLATE_ENV)
85
-
86
- # Create README.md
87
- readme_file = project_path / "README.md"
88
- readme_file.write_text(TEMPLATE_README.format(project_name=project_name))
89
-
90
- # Create .gitignore
91
- gitignore_file = project_path / ".gitignore"
92
- gitignore_file.write_text(TEMPLATE_GITIGNORE)
69
+ console.print(f"[yellow]⚠[/yellow] Could not fetch template, using basic template")
70
+
71
+ # Write all template files to the project
72
+ if template_files:
73
+ for filename, content in template_files.items():
74
+ (project_path / filename).write_text(content)
75
+ else:
76
+ # Fallback to basic template defaults
77
+ (project_path / "main.py").write_text(TEMPLATE_BASIC)
78
+ (project_path / "requirements.txt").write_text(TEMPLATE_REQUIREMENTS)
79
+ (project_path / "README.md").write_text(TEMPLATE_README.format(project_name=project_name))
80
+ (project_path / ".env.example").write_text(TEMPLATE_ENV)
81
+ (project_path / ".gitignore").write_text(TEMPLATE_GITIGNORE)
93
82
 
94
83
  # Success message
95
84
  console.print(f"[green]✓[/green] Find your project at [cyan]{project_path}[/cyan]\n")
@@ -8,50 +8,42 @@ class TemplateInfo:
8
8
  name: str
9
9
  url: str
10
10
 
11
- GITHUB_TEMPLATES: List[TemplateInfo] = [
12
- TemplateInfo(
13
- name="example",
14
- url="https://raw.githubusercontent.com/browserbase/stagehand-python/main/examples/example.py",
15
- ),
16
- TemplateInfo(
17
- name="cua-example",
18
- url="https://raw.githubusercontent.com/browserbase/stagehand-python/main/examples/cua-example.py",
19
- ),
20
- TemplateInfo(
21
- name="form-filling",
22
- url="https://raw.githubusercontent.com/browserbase/templates/refs/heads/dev/python/form-filling/main.py",
23
- ),
24
- TemplateInfo(
25
- name="gift-finder",
26
- url="https://raw.githubusercontent.com/browserbase/templates/refs/heads/dev/python/gift-finder/main.py",
27
- ),
28
- TemplateInfo(
29
- name="pickleball",
30
- url="https://raw.githubusercontent.com/browserbase/templates/refs/heads/dev/python/pickleball/main.py",
31
- ),
32
- TemplateInfo(
33
- name="license-verification",
34
- url="https://raw.githubusercontent.com/browserbase/templates/refs/heads/dev/python/license-verification/main.py",
35
- ),
36
- TemplateInfo(
37
- name="context",
38
- url="https://raw.githubusercontent.com/browserbase/templates/refs/heads/dev/python/context/main.py",
39
- ),
40
- TemplateInfo(
41
- name="proxies",
42
- url="https://raw.githubusercontent.com/browserbase/templates/refs/heads/dev/python/proxies/main.py",
43
- ),
44
- TemplateInfo(
45
- name="gemini-cua",
46
- url="https://raw.githubusercontent.com/browserbase/templates/refs/heads/dev/python/gemini-cua/main.py",
47
- ),
48
- ]
11
+ def fetch_github_templates() -> List[str]:
12
+ """Fetch list of Python templates from GitHub API."""
13
+ try:
14
+ response = requests.get(
15
+ "https://api.github.com/repos/browserbase/templates/contents/python",
16
+ headers={"User-Agent": "create-browser-app-py"},
17
+ timeout=10
18
+ )
19
+
20
+ if response.status_code != 200:
21
+ raise Exception(f"GitHub API returned status {response.status_code}")
22
+
23
+ data = response.json()
24
+ if not isinstance(data, list):
25
+ raise Exception("Invalid response format from GitHub API")
26
+
27
+ # Filter directories and exclude README.md
28
+ template_names = []
29
+ for item in data:
30
+ if (isinstance(item, dict) and
31
+ item.get("type") == "dir" and
32
+ item.get("name") != "README.md"):
33
+ template_names.append(item["name"])
34
+
35
+ return sorted(template_names)
36
+
37
+ except Exception as e:
38
+ # Re-raise with more context for debugging
39
+ raise Exception(f"Failed to fetch templates from GitHub: {e}")
40
+
49
41
  def get_template_by_name(name: str) -> Optional[TemplateInfo]:
50
42
  """Get a specific template by name."""
51
- for template in GITHUB_TEMPLATES:
52
- if template.name == name:
53
- return template
54
- return None
43
+ # Normalize to lowercase to match GitHub directory naming convention
44
+ normalized_name = name.lower()
45
+ url = f"https://raw.githubusercontent.com/browserbase/templates/refs/heads/dev/python/{normalized_name}/main.py"
46
+ return TemplateInfo(name=normalized_name, url=url)
55
47
 
56
48
  def fetch_template_content(template: TemplateInfo) -> Optional[str]:
57
49
  """Fetch the content of a specific template from GitHub."""
@@ -67,11 +59,68 @@ def fetch_template_content(template: TemplateInfo) -> Optional[str]:
67
59
  except Exception:
68
60
  return None
69
61
 
62
+ def fetch_template_files(template_name: str) -> List[Dict]:
63
+ """Fetch list of files in a template directory from GitHub API."""
64
+ normalized_name = template_name.lower()
65
+ try:
66
+ response = requests.get(
67
+ f"https://api.github.com/repos/browserbase/templates/contents/python/{normalized_name}",
68
+ headers={"User-Agent": "create-browser-app-py"},
69
+ timeout=10
70
+ )
71
+ if response.status_code != 200:
72
+ return []
73
+
74
+ data = response.json()
75
+ if not isinstance(data, list):
76
+ return []
77
+
78
+ # Return file info for each file (not directories)
79
+ files = []
80
+ for item in data:
81
+ if isinstance(item, dict) and item.get("type") == "file":
82
+ files.append({
83
+ "name": item["name"],
84
+ "download_url": item.get("download_url")
85
+ })
86
+ return files
87
+ except Exception:
88
+ return []
89
+
90
+ def fetch_all_template_files(template_name: str) -> Dict[str, str]:
91
+ """Fetch all files from a template directory.
92
+
93
+ Returns dict mapping filename -> content.
94
+ """
95
+ files = fetch_template_files(template_name)
96
+ if not files:
97
+ return {}
98
+
99
+ result = {}
100
+ for file_info in files:
101
+ name = file_info["name"]
102
+ download_url = file_info.get("download_url")
103
+ if download_url:
104
+ try:
105
+ response = requests.get(
106
+ download_url,
107
+ headers={"User-Agent": "create-browser-app-py"},
108
+ timeout=10
109
+ )
110
+ if response.status_code == 200:
111
+ result[name] = response.text
112
+ except Exception:
113
+ pass # Skip files that fail to download
114
+
115
+ return result
116
+
70
117
  def get_available_templates() -> List[str]:
71
- """Get a list of available template names."""
72
- default_templates = ["basic"]
73
- github_templates = [t.name for t in GITHUB_TEMPLATES]
74
- return default_templates + github_templates
118
+ """Get templates from GitHub API, fallback to basic only."""
119
+ try:
120
+ github_templates = fetch_github_templates()
121
+ return ["basic"] + github_templates
122
+ except Exception:
123
+ return ["basic"] # Fallback when GitHub unreachable
75
124
 
76
125
  def list_templates() -> List[str]:
77
126
  """Get a list of template names."""
@@ -1,69 +1,84 @@
1
- TEMPLATE_BASIC = '''from stagehand import Stagehand
2
- import asyncio
1
+ TEMPLATE_BASIC = '''import asyncio
3
2
  import os
3
+
4
4
  from dotenv import load_dotenv
5
5
  from pydantic import BaseModel
6
+ from stagehand import AsyncStagehand
7
+
6
8
  load_dotenv()
7
9
 
10
+
11
+ class StagehandDescription(BaseModel):
12
+ answer: str
13
+
14
+
15
+ class ModelInfo(BaseModel):
16
+ name: str
17
+ provider: str = ""
18
+ accuracy: float = 0.0
19
+
20
+
8
21
  async def main():
9
22
  """Basic Stagehand browser automation example."""
10
23
 
11
- # Check all the configurations in StagehandConfig
12
- stagehand = Stagehand(
13
- env="LOCAL", # or "BROWSERBASE"
14
- verbose=1, # 0: silent, 1: info, 2: debug
15
- model_name="gpt-4.1",
16
- model_api_key=os.getenv("OPENAI_API_KEY"),
17
- )
18
- await stagehand.init()
19
-
20
- page = stagehand.page
21
- await page.goto("https://docs.stagehand.dev")
22
- result = await page.extract("In a few words, what is Stagehand?")
23
- print()
24
- print(result)
25
- print()
26
-
27
- await page.act("click on models")
28
- await page.act({
29
- "method": "click",
30
- "selector": "/html/body[1]/div[2]/div[2]/div[3]/div[2]/div[2]/a[1]",
31
- "description": "the model evaluation card",
32
- "args": []
33
- })
34
- elements = await page.observe("find the graph with the list of most accurate models")
35
- print()
36
- print(elements)
37
- print()
38
-
39
- class Model(BaseModel):
40
- name: str
41
- provider: str
42
- accuracy: float
43
-
44
- extraction = await page.extract(
45
- "the most accurate model",
46
- schema=Model
24
+ client = AsyncStagehand(
25
+ browserbase_api_key=os.getenv("BROWSERBASE_API_KEY"),
26
+ browserbase_project_id=os.getenv("BROWSERBASE_PROJECT_ID"),
27
+ model_api_key=os.getenv("MODEL_API_KEY"),
47
28
  )
48
- print()
49
- print(extraction)
50
- print()
29
+
30
+ # Start a Stagehand session
31
+ session = await client.sessions.create(model_name="google/gemini-3-flash-preview")
32
+ print(f"Session started: {session.id}")
33
+ print(f"View live: https://www.browserbase.com/sessions/{session.id}")
34
+
35
+ try:
36
+ # Navigate to a webpage
37
+ await session.navigate(url="https://docs.stagehand.dev")
38
+
39
+ # Extract data using Stagehand AI
40
+ result = await session.extract(
41
+ instruction="In a few words, what is Stagehand?",
42
+ schema=StagehandDescription.model_json_schema(),
43
+ )
44
+ print(f"Extracted: {result.data.result}")
45
+
46
+ # Perform AI-powered action
47
+ await session.act(input="click on models")
48
+
49
+ # Observe elements on the page
50
+ observe_response = await session.observe(
51
+ instruction="find the graph with the list of most accurate models",
52
+ )
53
+ print(f"Found {len(observe_response.data.result)} elements")
54
+
55
+ # Extract structured data
56
+ result = await session.extract(
57
+ instruction="the most accurate model",
58
+ schema=ModelInfo.model_json_schema(),
59
+ )
60
+ print(f"Most accurate model: {result.data.result}")
61
+
62
+ finally:
63
+ await session.end()
64
+ print("Session ended")
65
+
66
+
51
67
  if __name__ == "__main__":
52
68
  asyncio.run(main())
53
-
54
69
  '''
55
70
 
56
- TEMPLATE_REQUIREMENTS = '''stagehand
71
+ TEMPLATE_REQUIREMENTS = '''stagehand>=3.4.0
72
+ pydantic
57
73
  python-dotenv
58
74
  '''
59
75
 
60
- TEMPLATE_ENV = '''# Add your environment variables here
61
- # BROWSERBASE_API_KEY=your_api_key_here
62
- # BROWSERBASE_PROJECT_ID=your_project_id_here
63
- # Add your LLM key
64
- # OPENAI_API_KEY=your_api_key_here
65
- # ANTHROPIC=your_api_key_here
66
- # GOOGLE_API_KEY=your_api_key_here
76
+ TEMPLATE_ENV = '''# Browserbase credentials (required)
77
+ BROWSERBASE_API_KEY=your_api_key_here
78
+ BROWSERBASE_PROJECT_ID=your_project_id_here
79
+
80
+ # LLM API key (required - using Google Gemini by default)
81
+ MODEL_API_KEY=your_api_key_here
67
82
  '''
68
83
 
69
84
  TEMPLATE_README = '''# {project_name}
@@ -81,6 +96,7 @@ pip install -r requirements.txt
81
96
  ```bash
82
97
  BROWSERBASE_API_KEY=your_api_key_here
83
98
  BROWSERBASE_PROJECT_ID=your_project_id_here
99
+ MODEL_API_KEY=your_api_key_here
84
100
  ```
85
101
 
86
102
  3. Run the project:
@@ -90,8 +106,8 @@ python main.py
90
106
 
91
107
  ## About Stagehand
92
108
 
93
- Stagehand is a Python library for browser automation built on Playwright. Learn more at:
94
- - [Stagehand Documentation](https://github.com/browserbase/stagehand)
109
+ Stagehand is the AI browser automation framework. Learn more at:
110
+ - [Stagehand Documentation](https://docs.stagehand.dev/v3/sdk/python)
95
111
  - [Browserbase](https://browserbase.com)
96
112
  '''
97
113
 
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: create-browser-app
3
- Version: 0.1.12
3
+ Version: 0.1.14
4
4
  Summary: Start your Stagehand project with a single command
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
7
- Requires-Dist: stagehand
7
+ Requires-Dist: stagehand>=3.4.0
8
8
  Requires-Dist: click>=8.0
9
9
  Requires-Dist: rich>=13.0
10
10
  Requires-Dist: inquirer>=3.0
@@ -0,0 +1,9 @@
1
+ create_browser_app/__init__.py,sha256=izlkaSvrxNqPnulbHlD8VYldR618NxRQRlKQFgQn0Gk,42
2
+ create_browser_app/main.py,sha256=oU02yImNWoDAVyk5ULupJUJ4WDfnSreW2TCpjmHwkbw,4637
3
+ create_browser_app/template_fetcher.py,sha256=vpt19HVQLZ8_3It9cEAJhZzAh1KLVj0-ajV4CvgKXBg,4297
4
+ create_browser_app/templates.py,sha256=Vt1oGrWuYfpM0Z8QsY20B7d3x2qHVoUTS3poDihsTvM,3172
5
+ create_browser_app-0.1.14.dist-info/METADATA,sha256=mRBPpJkk4QXzqn8X5C2fbQcc53T2hbkHn7lHmvIunf0,656
6
+ create_browser_app-0.1.14.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
7
+ create_browser_app-0.1.14.dist-info/entry_points.txt,sha256=yyAKhFZs2kraGA_ixwnRZeStL0uxWvBCMzysg8S-0VE,68
8
+ create_browser_app-0.1.14.dist-info/top_level.txt,sha256=sLW8imVtlXvOy1D5aGPBDxbMP3Yvonif7VxcLu_Izy4,19
9
+ create_browser_app-0.1.14.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,9 +0,0 @@
1
- create_browser_app/__init__.py,sha256=izlkaSvrxNqPnulbHlD8VYldR618NxRQRlKQFgQn0Gk,42
2
- create_browser_app/main.py,sha256=8n6Mot1AAM5Vwd7YhzUjresboJtwnt-hwFo1_jBI98Q,4864
3
- create_browser_app/template_fetcher.py,sha256=iu1hhs9RDZJrwpSwdyGJRaGwboMcfkLmzh5PecnYH_U,2690
4
- create_browser_app/templates.py,sha256=ipfp4zmfbD4-vhoggEW9M_EBXYvvyCzvmHew9tTgi7w,2636
5
- create_browser_app-0.1.12.dist-info/METADATA,sha256=U_lzsuZJnDfMe-PpL7Lrks0VyrVwa0ri7c2fVuMA7s0,649
6
- create_browser_app-0.1.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
- create_browser_app-0.1.12.dist-info/entry_points.txt,sha256=yyAKhFZs2kraGA_ixwnRZeStL0uxWvBCMzysg8S-0VE,68
8
- create_browser_app-0.1.12.dist-info/top_level.txt,sha256=sLW8imVtlXvOy1D5aGPBDxbMP3Yvonif7VxcLu_Izy4,19
9
- create_browser_app-0.1.12.dist-info/RECORD,,