vibesurf 0.1.26__tar.gz → 0.1.27__tar.gz

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.

Potentially problematic release.


This version of vibesurf might be problematic. Click here for more details.

Files changed (140) hide show
  1. vibesurf-0.1.27/LICENSE +22 -0
  2. {vibesurf-0.1.26/vibesurf.egg-info → vibesurf-0.1.27}/PKG-INFO +26 -5
  3. {vibesurf-0.1.26 → vibesurf-0.1.27}/README.md +24 -4
  4. vibesurf-0.1.27/README_zh.md +97 -0
  5. {vibesurf-0.1.26 → vibesurf-0.1.27}/pyproject.toml +1 -0
  6. {vibesurf-0.1.26 → vibesurf-0.1.27}/tests/test_browser.py +71 -1
  7. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/_version.py +3 -3
  8. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/agents/vibe_surf_agent.py +4 -5
  9. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/browser/agent_browser_session.py +26 -0
  10. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/tools/browser_use_tools.py +168 -1
  11. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/tools/vibesurf_tools.py +425 -3
  12. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/tools/views.py +75 -0
  13. vibesurf-0.1.27/vibe_surf/tools/website_api/__init__.py +0 -0
  14. vibesurf-0.1.27/vibe_surf/tools/website_api/douyin/__init__.py +0 -0
  15. vibesurf-0.1.27/vibe_surf/tools/website_api/douyin/client.py +845 -0
  16. vibesurf-0.1.27/vibe_surf/tools/website_api/douyin/douyin.js +435 -0
  17. vibesurf-0.1.27/vibe_surf/tools/website_api/douyin/helpers.py +239 -0
  18. vibesurf-0.1.27/vibe_surf/tools/website_api/weibo/__init__.py +0 -0
  19. vibesurf-0.1.27/vibe_surf/tools/website_api/weibo/client.py +846 -0
  20. vibesurf-0.1.27/vibe_surf/tools/website_api/weibo/helpers.py +997 -0
  21. vibesurf-0.1.27/vibe_surf/tools/website_api/xhs/__init__.py +0 -0
  22. vibesurf-0.1.27/vibe_surf/tools/website_api/xhs/client.py +807 -0
  23. vibesurf-0.1.27/vibe_surf/tools/website_api/xhs/helpers.py +301 -0
  24. vibesurf-0.1.27/vibe_surf/tools/website_api/youtube/__init__.py +32 -0
  25. vibesurf-0.1.27/vibe_surf/tools/website_api/youtube/client.py +1179 -0
  26. vibesurf-0.1.27/vibe_surf/tools/website_api/youtube/helpers.py +420 -0
  27. {vibesurf-0.1.26 → vibesurf-0.1.27/vibesurf.egg-info}/PKG-INFO +26 -5
  28. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibesurf.egg-info/SOURCES.txt +15 -0
  29. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibesurf.egg-info/requires.txt +1 -0
  30. vibesurf-0.1.26/LICENSE +0 -201
  31. {vibesurf-0.1.26 → vibesurf-0.1.27}/.env.example +0 -0
  32. {vibesurf-0.1.26 → vibesurf-0.1.27}/.github/workflows/publish.yml +0 -0
  33. {vibesurf-0.1.26 → vibesurf-0.1.27}/.gitignore +0 -0
  34. {vibesurf-0.1.26 → vibesurf-0.1.27}/.python-version +0 -0
  35. {vibesurf-0.1.26 → vibesurf-0.1.27}/MANIFEST.in +0 -0
  36. {vibesurf-0.1.26 → vibesurf-0.1.27}/docs/EXECUTABLE_BUILD.md +0 -0
  37. {vibesurf-0.1.26 → vibesurf-0.1.27}/docs/PYPI_SETUP.md +0 -0
  38. {vibesurf-0.1.26 → vibesurf-0.1.27}/scripts/build-local.bat +0 -0
  39. {vibesurf-0.1.26 → vibesurf-0.1.27}/scripts/build-local.sh +0 -0
  40. {vibesurf-0.1.26 → vibesurf-0.1.27}/setup.cfg +0 -0
  41. {vibesurf-0.1.26 → vibesurf-0.1.27}/tests/test_agents.py +0 -0
  42. {vibesurf-0.1.26 → vibesurf-0.1.27}/tests/test_backend_api.py +0 -0
  43. {vibesurf-0.1.26 → vibesurf-0.1.27}/tests/test_tools.py +0 -0
  44. {vibesurf-0.1.26 → vibesurf-0.1.27}/tests/test_voice_api.py +0 -0
  45. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/__init__.py +0 -0
  46. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/agents/__init__.py +0 -0
  47. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/agents/browser_use_agent.py +0 -0
  48. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/agents/prompts/__init__.py +0 -0
  49. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/agents/prompts/report_writer_prompt.py +0 -0
  50. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/agents/prompts/vibe_surf_prompt.py +0 -0
  51. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/agents/report_writer_agent.py +0 -0
  52. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/agents/views.py +0 -0
  53. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/__init__.py +0 -0
  54. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/api/__init__.py +0 -0
  55. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/api/activity.py +0 -0
  56. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/api/agent.py +0 -0
  57. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/api/browser.py +0 -0
  58. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/api/config.py +0 -0
  59. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/api/files.py +0 -0
  60. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/api/models.py +0 -0
  61. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/api/task.py +0 -0
  62. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/api/voices.py +0 -0
  63. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/database/__init__.py +0 -0
  64. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/database/manager.py +0 -0
  65. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/database/migrations/v001_initial_schema.sql +0 -0
  66. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/database/migrations/v002_add_agent_mode.sql +0 -0
  67. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/database/migrations/v003_fix_task_status_case.sql +0 -0
  68. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/database/migrations/v004_add_voice_profiles.sql +0 -0
  69. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/database/models.py +0 -0
  70. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/database/queries.py +0 -0
  71. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/database/schemas.py +0 -0
  72. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/llm_config.py +0 -0
  73. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/main.py +0 -0
  74. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/shared_state.py +0 -0
  75. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/utils/__init__.py +0 -0
  76. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/utils/encryption.py +0 -0
  77. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/utils/llm_factory.py +0 -0
  78. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/backend/voice_model_config.py +0 -0
  79. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/browser/__init__.py +0 -0
  80. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/browser/agen_browser_profile.py +0 -0
  81. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/browser/browser_manager.py +0 -0
  82. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/browser/utils.py +0 -0
  83. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/browser/watchdogs/__init__.py +0 -0
  84. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/browser/watchdogs/action_watchdog.py +0 -0
  85. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/browser/watchdogs/dom_watchdog.py +0 -0
  86. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/background.js +0 -0
  87. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/config.js +0 -0
  88. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/content.js +0 -0
  89. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/dev-reload.js +0 -0
  90. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/icons/logo.icns +0 -0
  91. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/icons/logo.png +0 -0
  92. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/manifest.json +0 -0
  93. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/permission-iframe.html +0 -0
  94. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/permission-request.html +0 -0
  95. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/popup.html +0 -0
  96. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/api-client.js +0 -0
  97. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/file-manager.js +0 -0
  98. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/history-manager.js +0 -0
  99. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/main.js +0 -0
  100. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/markdown-it.min.js +0 -0
  101. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/modal-manager.js +0 -0
  102. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/permission-iframe-request.js +0 -0
  103. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/permission-request.js +0 -0
  104. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/session-manager.js +0 -0
  105. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/settings-manager.js +0 -0
  106. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/ui-manager.js +0 -0
  107. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/user-settings-storage.js +0 -0
  108. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/scripts/voice-recorder.js +0 -0
  109. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/sidepanel.html +0 -0
  110. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/activity.css +0 -0
  111. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/animations.css +0 -0
  112. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/base.css +0 -0
  113. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/components.css +0 -0
  114. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/history-modal.css +0 -0
  115. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/input.css +0 -0
  116. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/layout.css +0 -0
  117. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/responsive.css +0 -0
  118. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/settings-environment.css +0 -0
  119. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/settings-forms.css +0 -0
  120. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/settings-modal.css +0 -0
  121. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/settings-profiles.css +0 -0
  122. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/settings-responsive.css +0 -0
  123. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/settings-utilities.css +0 -0
  124. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/chrome_extension/styles/variables.css +0 -0
  125. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/cli.py +0 -0
  126. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/common.py +0 -0
  127. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/llm/__init__.py +0 -0
  128. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/llm/openai_compatible.py +0 -0
  129. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/logger.py +0 -0
  130. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/tools/__init__.py +0 -0
  131. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/tools/file_system.py +0 -0
  132. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/tools/finance_tools.py +0 -0
  133. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/tools/mcp_client.py +0 -0
  134. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/tools/report_writer_tools.py +0 -0
  135. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/tools/vibesurf_registry.py +0 -0
  136. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibe_surf/tools/voice_asr.py +0 -0
  137. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibesurf.egg-info/dependency_links.txt +0 -0
  138. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibesurf.egg-info/entry_points.txt +0 -0
  139. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibesurf.egg-info/top_level.txt +0 -0
  140. {vibesurf-0.1.26 → vibesurf-0.1.27}/vibesurf.spec +0 -0
@@ -0,0 +1,22 @@
1
+ # Open Source License
2
+
3
+ VibeSurf is licensed under a modified version of the Apache License 2.0, with the following additional conditions:
4
+
5
+ 1. VibeSurf may be utilized commercially, including as a backend service for other applications or as an application development platform for enterprises. Should the conditions below be met, a commercial license must be obtained from the producer:
6
+
7
+ a. Multi-tenant service: Unless explicitly authorized by VibeSurf in writing, you may not use the VibeSurf source code to operate a multi-tenant environment.
8
+ - Tenant Definition: Within the context of VibeSurf, one tenant corresponds to one workspace. The workspace provides a separated area for each tenant's data and configurations.
9
+
10
+ b. LOGO and copyright information: In the process of using VibeSurf's frontend, you may not remove or modify the LOGO or copyright information in the VibeSurf console or applications. This restriction is inapplicable to uses of VibeSurf that do not involve its frontend.
11
+ - Frontend Definition: For the purposes of this license, the "frontend" of VibeSurf includes all components located in the `vibe_surf/chrome_extension/` directory when running VibeSurf from the raw source code, or the corresponding frontend container/image when running VibeSurf with Docker or other containerization.
12
+
13
+ 2. As a contributor, you should agree that:
14
+
15
+ a. The producer can adjust the open-source agreement to be more strict or relaxed as deemed necessary.
16
+ b. Your contributed code may be used for commercial purposes, including but not limited to its cloud business operations.
17
+
18
+ Apart from the specific conditions mentioned above, all other rights and restrictions follow the Apache License 2.0. Detailed information about the Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0.
19
+
20
+ The interactive design of this product is protected by appearance patent.
21
+
22
+ © 2025 VibeSurf Authors. This repository is licensed under the VibeSurf Open Source License, based on Apache 2.0 with additional conditions.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vibesurf
3
- Version: 0.1.26
3
+ Version: 0.1.27
4
4
  Summary: VibeSurf: A powerful browser assistant for vibe surfing
5
5
  Author: Shao Warm
6
6
  License: Apache-2.0
@@ -44,16 +44,19 @@ Requires-Dist: markdownify>=1.2.0
44
44
  Requires-Dist: pathvalidate>=3.3.1
45
45
  Requires-Dist: dashscope>=1.24.5
46
46
  Requires-Dist: yfinance>=0.2.66
47
+ Requires-Dist: pyexecjs>=1.5.1
47
48
  Dynamic: license-file
48
49
 
49
50
  # VibeSurf: A powerful browser assistant for vibe surfing
50
- [![Discord](https://img.shields.io/discord/1303749220842340412?color=7289DA&label=Discord&logo=discord&logoColor=white)](https://discord.gg/TXNnP9gJ)
51
+ [![Discord](https://img.shields.io/discord/1303749220842340412?color=7289DA&label=Discord&logo=discord&logoColor=white)](https://discord.gg/EZ2YnUXP)
51
52
  [![WarmShao](https://img.shields.io/twitter/follow/warmshao?style=social)](https://x.com/warmshao)
52
53
 
53
54
  VibeSurf is an open-source AI agentic browser that revolutionizes browser automation and research.
54
55
 
55
56
  If you're as excited about open-source AI browsing as I am, give it a star! ⭐
56
57
 
58
+ [中文](README_zh.md) | [English](README.md)
59
+
57
60
  ## ✨ Key Features
58
61
 
59
62
  - 🧠 **Advanced AI Automation**: Beyond browser automation, VibeSurf performs deep research, intelligent crawling, content summarization, and more to exploration.
@@ -90,11 +93,29 @@ uv pip install vibesurf -U
90
93
  uv run vibesurf
91
94
  ```
92
95
 
93
- ## 🗺️ Roadmap
96
+ ## 👩‍💻 For Contributors
97
+
98
+ Want to contribute to VibeSurf? Here are two ways to set up your development environment:
99
+
100
+ ### Method 1: Direct Server Run
101
+ Run the backend server directly using uvicorn:
102
+ ```bash
103
+ uvicorn vibe_surf.backend.main:app --host 127.0.0.1 --port 9335
104
+ ```
105
+
106
+ ### Method 2: Editable Installation
107
+ Install the package in editable mode and run using the CLI:
108
+ ```bash
109
+ uv pip install -e .
110
+ uv run vibesurf
111
+ ```
112
+
113
+ Choose the method that works best for your development workflow!
114
+ ## �️ Roadmap
94
115
 
95
116
  We're building VibeSurf to be your ultimate AI browser companion. Here's what's coming next:
96
117
 
97
- - [ ] **Smart Skills System**: Add `/search` for quick information search and `/crawl` for automatic website data extraction
118
+ - [x] **Smart Skills System**: Add `/search` for quick information search and `/crawl` for automatic website data extraction
98
119
  - [ ] **Powerful Coding Agent**: Build a comprehensive coding assistant for data processing and analysis directly in your browser
99
120
  - [ ] **Third-Party Integrations**: Connect with n8n workflows and other tools to combine browsing with automation
100
121
  - [ ] **Custom Workflow Templates**: Create reusable templates for auto-login, data collection, and complex browser automation
@@ -113,7 +134,7 @@ We're building VibeSurf to be your ultimate AI browser companion. Here's what's
113
134
 
114
135
  ## 📝 License
115
136
 
116
- Licensed under the [Apache License 2.0](LICENSE).
137
+ This repository is licensed under the [VibeSurf Open Source License](./LICENSE), based on Apache 2.0 with additional conditions.
117
138
 
118
139
  ## 👏 Acknowledgments
119
140
 
@@ -1,11 +1,13 @@
1
1
  # VibeSurf: A powerful browser assistant for vibe surfing
2
- [![Discord](https://img.shields.io/discord/1303749220842340412?color=7289DA&label=Discord&logo=discord&logoColor=white)](https://discord.gg/TXNnP9gJ)
2
+ [![Discord](https://img.shields.io/discord/1303749220842340412?color=7289DA&label=Discord&logo=discord&logoColor=white)](https://discord.gg/EZ2YnUXP)
3
3
  [![WarmShao](https://img.shields.io/twitter/follow/warmshao?style=social)](https://x.com/warmshao)
4
4
 
5
5
  VibeSurf is an open-source AI agentic browser that revolutionizes browser automation and research.
6
6
 
7
7
  If you're as excited about open-source AI browsing as I am, give it a star! ⭐
8
8
 
9
+ [中文](README_zh.md) | [English](README.md)
10
+
9
11
  ## ✨ Key Features
10
12
 
11
13
  - 🧠 **Advanced AI Automation**: Beyond browser automation, VibeSurf performs deep research, intelligent crawling, content summarization, and more to exploration.
@@ -42,11 +44,29 @@ uv pip install vibesurf -U
42
44
  uv run vibesurf
43
45
  ```
44
46
 
45
- ## 🗺️ Roadmap
47
+ ## 👩‍💻 For Contributors
48
+
49
+ Want to contribute to VibeSurf? Here are two ways to set up your development environment:
50
+
51
+ ### Method 1: Direct Server Run
52
+ Run the backend server directly using uvicorn:
53
+ ```bash
54
+ uvicorn vibe_surf.backend.main:app --host 127.0.0.1 --port 9335
55
+ ```
56
+
57
+ ### Method 2: Editable Installation
58
+ Install the package in editable mode and run using the CLI:
59
+ ```bash
60
+ uv pip install -e .
61
+ uv run vibesurf
62
+ ```
63
+
64
+ Choose the method that works best for your development workflow!
65
+ ## �️ Roadmap
46
66
 
47
67
  We're building VibeSurf to be your ultimate AI browser companion. Here's what's coming next:
48
68
 
49
- - [ ] **Smart Skills System**: Add `/search` for quick information search and `/crawl` for automatic website data extraction
69
+ - [x] **Smart Skills System**: Add `/search` for quick information search and `/crawl` for automatic website data extraction
50
70
  - [ ] **Powerful Coding Agent**: Build a comprehensive coding assistant for data processing and analysis directly in your browser
51
71
  - [ ] **Third-Party Integrations**: Connect with n8n workflows and other tools to combine browsing with automation
52
72
  - [ ] **Custom Workflow Templates**: Create reusable templates for auto-login, data collection, and complex browser automation
@@ -65,7 +85,7 @@ We're building VibeSurf to be your ultimate AI browser companion. Here's what's
65
85
 
66
86
  ## 📝 License
67
87
 
68
- Licensed under the [Apache License 2.0](LICENSE).
88
+ This repository is licensed under the [VibeSurf Open Source License](./LICENSE), based on Apache 2.0 with additional conditions.
69
89
 
70
90
  ## 👏 Acknowledgments
71
91
 
@@ -0,0 +1,97 @@
1
+ # VibeSurf:强大的浏览器助手,用于氛围冲浪
2
+
3
+ [![Discord](https://img.shields.io/discord/1303749220842340412?color=7289DA&label=Discord&logo=discord&logoColor=white)](https://discord.gg/EZ2YnUXP)
4
+ [![WarmShao](https://img.shields.io/twitter/follow/warmshao?style=social)](https://x.com/warmshao)
5
+
6
+ VibeSurf 是一个开源的 AI 代理浏览器,它革新了浏览器自动化和研究。
7
+
8
+ 如果你和我一样对开源 AI 浏览感到兴奋,请给它一个 star!⭐
9
+
10
+ [中文](README_zh.md) | [English](README.md)
11
+
12
+ ## ✨ 主要特性
13
+
14
+ - 🧠 **高级 AI 自动化**:超越浏览器自动化,VibeSurf 执行深度研究、智能爬取、内容摘要等,以进行探索。
15
+
16
+ - 🚀 **多代理并行处理**:在不同的浏览器标签页中同时运行多个 AI 代理,实现深度研究和广泛研究,大幅提升效率。
17
+
18
+ - 🥷 **隐身优先架构**:使用 Chrome DevTools 协议(CDP)而不是 Playwright,提供卓越的隐身能力,防止机器人检测。
19
+
20
+ - 🎨 **无缝的 Chrome 扩展 UI**:原生浏览器集成,无需切换应用程序,提供直观的界面,感觉就像浏览器的一部分。
21
+
22
+ - 🔒 **隐私优先的 LLM 支持**:支持本地 LLM(Ollama 等)和自定义 LLM API,确保在氛围冲浪期间您的浏览数据保持私密和安全。
23
+
24
+ ## 🛠️ 安装
25
+
26
+ ### 第一步:安装 uv
27
+ 从 [https://docs.astral.sh/uv/getting-started/installation/](https://docs.astral.sh/uv/getting-started/installation/) 安装 uv:
28
+
29
+ ```bash
30
+ # 在 macOS 和 Linux 上
31
+ curl -LsSf https://astral.sh/uv/install.sh | sh
32
+
33
+ # 在 Windows 上
34
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
35
+ ```
36
+
37
+ ### 第二步:设置和安装
38
+ ```bash
39
+ uv venv --python 3.12
40
+ uv pip install vibesurf -U
41
+ ```
42
+
43
+ ### 第三步:启动
44
+ ```bash
45
+ uv run vibesurf
46
+ ```
47
+
48
+ ## 👩‍💻 对贡献者
49
+
50
+ 想为 VibeSurf 做贡献?以下是设置开发环境的两种方法:
51
+
52
+ ### 方法 1:直接运行服务器
53
+ 使用 uvicorn 直接运行后端服务器:
54
+ ```bash
55
+ uvicorn vibe_surf.backend.main:app --host 127.0.0.1 --port 9335
56
+ ```
57
+
58
+ ### 方法 2:可编辑安装
59
+ 以可编辑模式安装包并使用 CLI 运行:
60
+ ```bash
61
+ uv pip install -e .
62
+ uv run vibesurf
63
+ ```
64
+
65
+ 选择最适合您开发工作流程的方法!
66
+
67
+ ## 🗺️ 路线图
68
+
69
+ 我们正在构建 VibeSurf,使其成为您终极的 AI 浏览器伴侣。以下是接下来的计划:
70
+
71
+ - [x] **智能技能系统**:添加 `/search` 用于快速信息搜索,`/crawl` 用于自动网站数据提取
72
+ - [ ] **强大的编码代理**:构建一个全面的编码助手,用于在浏览器中直接进行数据处理和分析
73
+ - [ ] **第三方集成**:与 n8n 工作流和其他工具连接,将浏览与自动化结合
74
+ - [ ] **自定义工作流模板**:创建可重用的模板,用于自动登录、数据收集和复杂的浏览器自动化
75
+ - [ ] **智能交互功能**:文本选择用于翻译/问答、截图分析和语音阅读功能
76
+ - [ ] **实时对话和记忆**:添加持久聊天功能和全局记忆,使 VibeSurf 真正理解您
77
+
78
+ ## 🎬 演示
79
+
80
+ ### 如何使用?
81
+ <video src="https://github.com/user-attachments/assets/0a4650c0-c4ed-423e-9e16-7889e9f9816d" controls="controls">您的浏览器不支持播放此视频!</video>
82
+
83
+ ### 在浏览器中运行数十个代理
84
+ <video src="https://github.com/user-attachments/assets/9c461a6e-5d97-4335-ba09-59e8ec4ad47b" controls="controls">您的浏览器不支持播放此视频!</video>
85
+
86
+ ## 📝 许可证
87
+
88
+ 本仓库采用 [VibeSurf 开源许可证](./LICENSE),基于 Apache 2.0 并附加额外条款。
89
+
90
+ ## 👏 致谢
91
+
92
+ VibeSurf 建立在其他优秀的开源项目之上:
93
+
94
+ - [Browser Use](https://github.com/browser-use/browser-use)
95
+ - [LangGraph](https://github.com/langchain-ai/langgraph)
96
+
97
+ 非常感谢他们的创作者和贡献者!
@@ -45,6 +45,7 @@ dependencies = [
45
45
  "pathvalidate>=3.3.1",
46
46
  "dashscope>=1.24.5",
47
47
  "yfinance>=0.2.66",
48
+ "pyexecjs>=1.5.1",
48
49
  ]
49
50
 
50
51
  [project.urls]
@@ -262,6 +262,75 @@ async def get_all_css_selector(browser_session: AgentBrowserSession):
262
262
  pdb.set_trace()
263
263
 
264
264
 
265
+ async def test_website_api(main_browser_session: AgentBrowserSession):
266
+ # from vibe_surf.tools.website_api.xhs.client import XiaoHongShuApiClient, SearchType
267
+ # xhs_client = XiaoHongShuApiClient(browser_session=main_browser_session)
268
+ # await xhs_client.setup()
269
+ # user_info = await xhs_client.get_me()
270
+ # user_id = user_info['user_id']
271
+ # ret = await xhs_client.search_content_by_keyword("browser-use", sort_type=SearchType.POPULAR)
272
+ # pdb.set_trace()
273
+ # ret = await xhs_client.get_home_recommendations()
274
+ # pdb.set_trace()
275
+ # ret = await xhs_client.get_user_profile(user_id=user_id)
276
+ # ret = await xhs_client.fetch_all_user_content(user_id=user_id)
277
+ # note_id = ret[1]['note_id']
278
+ # xsec_token = ret[1]['xsec_token']
279
+ # ret1 = await xhs_client.fetch_content_details(content_id=note_id, xsec_token=xsec_token)
280
+ # pdb.set_trace()
281
+ # ret2 = await xhs_client.fetch_all_content_comments(content_id=note_id, xsec_token=xsec_token)
282
+ # pdb.set_trace()
283
+
284
+ from vibe_surf.tools.website_api.weibo.client import WeiboApiClient
285
+ from vibe_surf.tools.website_api.weibo.helpers import SearchType
286
+ wb_client = WeiboApiClient(browser_session=main_browser_session)
287
+ await wb_client.setup()
288
+ # ret = await wb_client.search_posts_by_keyword("邓紫棋", page=4, search_type=SearchType.POPULAR)
289
+ # pdb.set_trace()
290
+ # mid = ret[0]['note_id']
291
+ # user_id = ret[0]['user_id']
292
+ # ret = await wb_client.get_post_detail(mid=mid)
293
+ # pdb.set_trace()
294
+ # ret = await wb_client.get_all_post_comments(mid=mid)
295
+ # pdb.set_trace()
296
+ # ret1 = await wb_client.get_user_info(user_id=user_id)
297
+ # ret3 = await wb_client.get_all_user_posts(user_id=user_id)
298
+ # pdb.set_trace()
299
+ ret = await wb_client.get_hot_posts()
300
+ pdb.set_trace()
301
+ ret = await wb_client.get_trending_posts()
302
+ pdb.set_trace()
303
+
304
+ # from vibe_surf.tools.website_api.douyin.client import DouyinApiClient
305
+ #
306
+ # dy_client = DouyinApiClient(main_browser_session)
307
+ # await dy_client.setup()
308
+ # ret = await dy_client.search_content_by_keyword("Sora2")
309
+ # aweme_id = ret[0]['aweme_id']
310
+ # user_id = ret[0]['user_id']
311
+ # ret1 = await dy_client.fetch_video_details(aweme_id=aweme_id)
312
+ # ret2 = await dy_client.fetch_video_comments(aweme_id=aweme_id)
313
+ # ret3 = await dy_client.fetch_user_info(sec_user_id=user_id)
314
+ # ret3 = await dy_client.fetch_user_videos(sec_user_id=user_id)
315
+ # pdb.set_trace()
316
+
317
+ # from vibe_surf.tools.website_api.youtube.client import YouTubeApiClient
318
+ # yt_client = YouTubeApiClient(browser_session=main_browser_session)
319
+ # await yt_client.setup()
320
+ # ret = await yt_client.get_trending_videos()
321
+ # pdb.set_trace()
322
+ # ret = await yt_client.search_videos(query="何同学", max_results=30)
323
+ # pdb.set_trace()
324
+ # ret = await yt_client.get_video_details(ret[0]['video_id'])
325
+ # pdb.set_trace()
326
+ # ret = await yt_client.get_video_comments(ret[0]['video_id'])
327
+ # pdb.set_trace()
328
+ # ret = await yt_client.get_channel_info(ret[0]['channel_id'])
329
+ # pdb.set_trace()
330
+ # ret = await yt_client.get_channel_videos(ret[0]['channel_id'], max_videos=50)
331
+ # pdb.set_trace()
332
+
333
+
265
334
  async def main():
266
335
  """
267
336
  Main function to run all browser session tests.
@@ -296,7 +365,8 @@ async def main():
296
365
  # await test_agent_cleanup(manager)
297
366
  # await test_agent_tab_isolation(manager)
298
367
  # await test_browser_state_capture(manager)
299
- await get_all_css_selector(main_browser_session)
368
+ # await get_all_css_selector(main_browser_session)
369
+ await test_website_api(main_browser_session)
300
370
 
301
371
  except Exception as e:
302
372
  logging.error(f"An error occurred during tests: {e}", exc_info=True)
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.1.26'
32
- __version_tuple__ = version_tuple = (0, 1, 26)
31
+ __version__ = version = '0.1.27'
32
+ __version_tuple__ = version_tuple = (0, 1, 27)
33
33
 
34
- __commit_id__ = commit_id = 'g98ca63073'
34
+ __commit_id__ = commit_id = 'gb87f28077'
@@ -479,17 +479,16 @@ async def _vibesurf_agent_node_impl(state: VibeSurfState) -> VibeSurfState:
479
479
  llm=vibesurf_agent.llm,
480
480
  file_system=vibesurf_agent.file_system,
481
481
  )
482
- if action_name in ["skill_search", "skill_crawl", "skill_summary", "skill_finance"]:
482
+ if action_name.startswith("skill_"):
483
483
  state.current_step = "END"
484
484
  # Format final response
485
- final_response = f"{result.extracted_content}"
486
- await log_agent_activity(state, agent_name, "result", final_response)
485
+ final_response = f"{result.extracted_content}" or f"{result.error}"
487
486
  state.final_response = final_response
488
487
  logger.debug(final_response)
489
488
  state.is_complete = True
490
- return state
489
+ else:
490
+ state.current_step = "vibesurf_agent"
491
491
 
492
- state.current_step = "vibesurf_agent"
493
492
  if result.extracted_content:
494
493
  vibesurf_agent.message_history.append(
495
494
  UserMessage(content=f'Action result:\n{result.extracted_content}'))
@@ -384,6 +384,32 @@ class AgentBrowserSession(BrowserSession):
384
384
  )
385
385
  ]
386
386
 
387
+ def model_post_init(self, __context) -> None:
388
+ """Register event handlers after model initialization."""
389
+ # Check if handlers are already registered to prevent duplicates
390
+
391
+ from browser_use.browser.watchdog_base import BaseWatchdog
392
+
393
+ start_handlers = self.event_bus.handlers.get('BrowserStartEvent', [])
394
+ start_handler_names = [getattr(h, '__name__', str(h)) for h in start_handlers]
395
+
396
+ if any('on_BrowserStartEvent' in name for name in start_handler_names):
397
+ raise RuntimeError(
398
+ '[BrowserSession] Duplicate handler registration attempted! '
399
+ 'on_BrowserStartEvent is already registered. '
400
+ 'This likely means BrowserSession was initialized multiple times with the same EventBus.'
401
+ )
402
+
403
+ BaseWatchdog.attach_handler_to_session(self, BrowserStartEvent, self.on_BrowserStartEvent)
404
+ BaseWatchdog.attach_handler_to_session(self, BrowserStopEvent, self.on_BrowserStopEvent)
405
+ BaseWatchdog.attach_handler_to_session(self, NavigateToUrlEvent, self.on_NavigateToUrlEvent)
406
+ BaseWatchdog.attach_handler_to_session(self, SwitchTabEvent, self.on_SwitchTabEvent)
407
+ BaseWatchdog.attach_handler_to_session(self, TabCreatedEvent, self.on_TabCreatedEvent)
408
+ BaseWatchdog.attach_handler_to_session(self, TabClosedEvent, self.on_TabClosedEvent)
409
+ BaseWatchdog.attach_handler_to_session(self, AgentFocusChangedEvent, self.on_AgentFocusChangedEvent)
410
+ # BaseWatchdog.attach_handler_to_session(self, FileDownloadedEvent, self.on_FileDownloadedEvent)
411
+ BaseWatchdog.attach_handler_to_session(self, CloseTabEvent, self.on_CloseTabEvent)
412
+
387
413
  async def attach_all_watchdogs(self) -> None:
388
414
  """Initialize and attach all watchdogs EXCEPT AboutBlankWatchdog to disable DVD animation."""
389
415
  # Prevent duplicate watchdog attachment
@@ -6,6 +6,9 @@ import enum
6
6
  import base64
7
7
  import mimetypes
8
8
  import datetime
9
+ import aiohttp
10
+ import re
11
+ import urllib.parse
9
12
  from pathvalidate import sanitize_filename
10
13
  from typing import Optional, Type, Callable, Dict, Any, Union, Awaitable, TypeVar
11
14
  from pydantic import BaseModel
@@ -40,7 +43,7 @@ from browser_use.browser.views import BrowserError
40
43
  from browser_use.mcp.client import MCPClient
41
44
 
42
45
  from vibe_surf.browser.agent_browser_session import AgentBrowserSession
43
- from vibe_surf.tools.views import HoverAction, ExtractionAction, FileExtractionAction
46
+ from vibe_surf.tools.views import HoverAction, ExtractionAction, FileExtractionAction, DownloadMediaAction
44
47
  from vibe_surf.tools.mcp_client import CustomMCPClient
45
48
  from vibe_surf.tools.file_system import CustomFileSystem
46
49
  from vibe_surf.logger import get_logger
@@ -501,3 +504,167 @@ class BrowserUseTools(Tools, VibeSurfTools):
501
504
  error_msg = f'❌ Failed to take screenshot: {str(e)}'
502
505
  logger.error(error_msg)
503
506
  return ActionResult(error=error_msg)
507
+
508
+ @self.registry.action(
509
+ 'Download media from URL and save to filesystem downloads folder',
510
+ param_model=DownloadMediaAction
511
+ )
512
+ async def download_media(params: DownloadMediaAction, file_system: FileSystem):
513
+ """Download media from URL with automatic file format detection"""
514
+ try:
515
+ # Get file system directory path (Path type)
516
+ fs_dir = file_system.get_dir()
517
+
518
+ # Create downloads directory if it doesn't exist
519
+ downloads_dir = fs_dir / "downloads"
520
+ downloads_dir.mkdir(exist_ok=True)
521
+
522
+ # Download the file and detect format
523
+ async with aiohttp.ClientSession() as session:
524
+ async with session.get(params.url) as response:
525
+ if response.status != 200:
526
+ raise Exception(f"HTTP {response.status}: Failed to download from {params.url}")
527
+
528
+ # Get content
529
+ content = await response.read()
530
+
531
+ # Detect file format and extension
532
+ file_extension = await self._detect_file_format(params.url, response.headers, content)
533
+
534
+ # Generate filename
535
+ if params.filename:
536
+ # Use provided filename, add extension if missing
537
+ filename = params.filename
538
+ if not filename.endswith(file_extension):
539
+ filename = f"{filename}{file_extension}"
540
+ else:
541
+ # Generate filename from URL or timestamp
542
+ url_path = urllib.parse.urlparse(params.url).path
543
+ url_filename = os.path.basename(url_path)
544
+
545
+ if url_filename and not url_filename.startswith('.'):
546
+ # Use URL filename, ensure correct extension
547
+ filename = url_filename
548
+ if not filename.endswith(file_extension):
549
+ base_name = os.path.splitext(filename)[0]
550
+ filename = f"{base_name}{file_extension}"
551
+ else:
552
+ # Generate timestamp-based filename
553
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
554
+ filename = f"media_{timestamp}{file_extension}"
555
+
556
+ # Sanitize filename
557
+ filename = sanitize_filename(filename)
558
+ filepath = downloads_dir / filename
559
+
560
+ # Save file
561
+ with open(filepath, "wb") as f:
562
+ f.write(content)
563
+
564
+ # Calculate file size for display
565
+ file_size = len(content)
566
+ size_str = self._format_file_size(file_size)
567
+
568
+ msg = f'📥 Downloaded media to: {str(filepath.relative_to(fs_dir))} ({size_str})'
569
+ logger.info(msg)
570
+ return ActionResult(
571
+ extracted_content=msg,
572
+ include_in_memory=True,
573
+ long_term_memory=f'Downloaded media from {params.url} to {str(filepath.relative_to(fs_dir))}',
574
+ )
575
+
576
+ except Exception as e:
577
+ error_msg = f'❌ Failed to download media: {str(e)}'
578
+ logger.error(error_msg)
579
+ return ActionResult(error=error_msg)
580
+
581
+ async def _detect_file_format(self, url: str, headers: dict, content: bytes) -> str:
582
+ """Detect file format from URL, headers, and content"""
583
+
584
+ # Try Content-Type header first
585
+ content_type = headers.get('content-type', '').lower()
586
+ if content_type:
587
+ # Common image formats
588
+ if 'image/jpeg' in content_type or 'image/jpg' in content_type:
589
+ return '.jpg'
590
+ elif 'image/png' in content_type:
591
+ return '.png'
592
+ elif 'image/gif' in content_type:
593
+ return '.gif'
594
+ elif 'image/webp' in content_type:
595
+ return '.webp'
596
+ elif 'image/svg' in content_type:
597
+ return '.svg'
598
+ elif 'image/bmp' in content_type:
599
+ return '.bmp'
600
+ elif 'image/tiff' in content_type:
601
+ return '.tiff'
602
+ # Video formats
603
+ elif 'video/mp4' in content_type:
604
+ return '.mp4'
605
+ elif 'video/webm' in content_type:
606
+ return '.webm'
607
+ elif 'video/avi' in content_type:
608
+ return '.avi'
609
+ elif 'video/mov' in content_type or 'video/quicktime' in content_type:
610
+ return '.mov'
611
+ # Audio formats
612
+ elif 'audio/mpeg' in content_type or 'audio/mp3' in content_type:
613
+ return '.mp3'
614
+ elif 'audio/wav' in content_type:
615
+ return '.wav'
616
+ elif 'audio/ogg' in content_type:
617
+ return '.ogg'
618
+ elif 'audio/webm' in content_type:
619
+ return '.webm'
620
+
621
+ # Try magic number detection
622
+ if len(content) >= 8:
623
+ # JPEG
624
+ if content.startswith(b'\xff\xd8\xff'):
625
+ return '.jpg'
626
+ # PNG
627
+ elif content.startswith(b'\x89PNG\r\n\x1a\n'):
628
+ return '.png'
629
+ # GIF
630
+ elif content.startswith(b'GIF87a') or content.startswith(b'GIF89a'):
631
+ return '.gif'
632
+ # WebP
633
+ elif content[8:12] == b'WEBP':
634
+ return '.webp'
635
+ # BMP
636
+ elif content.startswith(b'BM'):
637
+ return '.bmp'
638
+ # TIFF
639
+ elif content.startswith(b'II*\x00') or content.startswith(b'MM\x00*'):
640
+ return '.tiff'
641
+ # MP4
642
+ elif b'ftyp' in content[4:12]:
643
+ return '.mp4'
644
+ # PDF
645
+ elif content.startswith(b'%PDF'):
646
+ return '.pdf'
647
+
648
+ # Try URL path extension
649
+ url_path = urllib.parse.urlparse(url).path
650
+ if url_path:
651
+ ext = os.path.splitext(url_path)[1].lower()
652
+ if ext in ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp', '.tiff',
653
+ '.mp4', '.webm', '.avi', '.mov', '.wmv', '.flv',
654
+ '.mp3', '.wav', '.ogg', '.aac', '.flac',
655
+ '.pdf', '.doc', '.docx', '.txt']:
656
+ return ext
657
+
658
+ # Default fallback
659
+ return '.bin'
660
+
661
+ def _format_file_size(self, size_bytes: int) -> str:
662
+ """Format file size in human readable format"""
663
+ if size_bytes == 0:
664
+ return "0 B"
665
+ size_names = ["B", "KB", "MB", "GB", "TB"]
666
+ i = 0
667
+ while size_bytes >= 1024.0 and i < len(size_names) - 1:
668
+ size_bytes /= 1024.0
669
+ i += 1
670
+ return f"{size_bytes:.1f} {size_names[i]}"