entari-plugin-hyw 4.0.0rc17__py3-none-any.whl → 4.0.0rc19__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.
Potentially problematic release.
This version of entari-plugin-hyw might be problematic. Click here for more details.
- entari_plugin_hyw-4.0.0rc19.dist-info/METADATA +26 -0
- entari_plugin_hyw-4.0.0rc19.dist-info/RECORD +4 -0
- entari_plugin_hyw-4.0.0rc19.dist-info/top_level.txt +1 -0
- entari_plugin_hyw/__init__.py +0 -914
- entari_plugin_hyw/filters.py +0 -83
- entari_plugin_hyw/history.py +0 -251
- entari_plugin_hyw/misc.py +0 -214
- entari_plugin_hyw/search_cache.py +0 -253
- entari_plugin_hyw-4.0.0rc17.dist-info/METADATA +0 -119
- entari_plugin_hyw-4.0.0rc17.dist-info/RECORD +0 -52
- entari_plugin_hyw-4.0.0rc17.dist-info/top_level.txt +0 -2
- hyw_core/__init__.py +0 -94
- hyw_core/agent.py +0 -876
- hyw_core/browser_control/__init__.py +0 -63
- hyw_core/browser_control/assets/card-dist/index.html +0 -429
- hyw_core/browser_control/assets/card-dist/logos/anthropic.svg +0 -1
- hyw_core/browser_control/assets/card-dist/logos/cerebras.svg +0 -9
- hyw_core/browser_control/assets/card-dist/logos/deepseek.png +0 -0
- hyw_core/browser_control/assets/card-dist/logos/gemini.svg +0 -1
- hyw_core/browser_control/assets/card-dist/logos/google.svg +0 -1
- hyw_core/browser_control/assets/card-dist/logos/grok.png +0 -0
- hyw_core/browser_control/assets/card-dist/logos/huggingface.png +0 -0
- hyw_core/browser_control/assets/card-dist/logos/microsoft.svg +0 -15
- hyw_core/browser_control/assets/card-dist/logos/minimax.png +0 -0
- hyw_core/browser_control/assets/card-dist/logos/mistral.png +0 -0
- hyw_core/browser_control/assets/card-dist/logos/nvida.png +0 -0
- hyw_core/browser_control/assets/card-dist/logos/openai.svg +0 -1
- hyw_core/browser_control/assets/card-dist/logos/openrouter.png +0 -0
- hyw_core/browser_control/assets/card-dist/logos/perplexity.svg +0 -24
- hyw_core/browser_control/assets/card-dist/logos/qwen.png +0 -0
- hyw_core/browser_control/assets/card-dist/logos/xai.png +0 -0
- hyw_core/browser_control/assets/card-dist/logos/xiaomi.png +0 -0
- hyw_core/browser_control/assets/card-dist/logos/zai.png +0 -0
- hyw_core/browser_control/assets/card-dist/vite.svg +0 -1
- hyw_core/browser_control/engines/__init__.py +0 -15
- hyw_core/browser_control/engines/base.py +0 -13
- hyw_core/browser_control/engines/default.py +0 -166
- hyw_core/browser_control/engines/duckduckgo.py +0 -171
- hyw_core/browser_control/landing.html +0 -172
- hyw_core/browser_control/manager.py +0 -173
- hyw_core/browser_control/renderer.py +0 -446
- hyw_core/browser_control/service.py +0 -1002
- hyw_core/config.py +0 -154
- hyw_core/core.py +0 -454
- hyw_core/crawling/__init__.py +0 -18
- hyw_core/crawling/completeness.py +0 -437
- hyw_core/crawling/models.py +0 -88
- hyw_core/definitions.py +0 -166
- hyw_core/image_cache.py +0 -274
- hyw_core/pipeline.py +0 -502
- hyw_core/search.py +0 -169
- hyw_core/stages/__init__.py +0 -21
- hyw_core/stages/base.py +0 -95
- hyw_core/stages/summary.py +0 -218
- {entari_plugin_hyw-4.0.0rc17.dist-info → entari_plugin_hyw-4.0.0rc19.dist-info}/WHEEL +0 -0
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<title>entari-plugin-hyw Browser</title>
|
|
7
|
-
<style>
|
|
8
|
-
:root {
|
|
9
|
-
--theme-color: #ef4444;
|
|
10
|
-
--text-primary: #2c2c2e;
|
|
11
|
-
--text-body: #3a3a3c;
|
|
12
|
-
--text-muted: #86868b;
|
|
13
|
-
--bg-border: #f2f2f2;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
body {
|
|
17
|
-
background-color: var(--bg-border);
|
|
18
|
-
color: var(--text-primary);
|
|
19
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
20
|
-
margin: 0;
|
|
21
|
-
padding: 0;
|
|
22
|
-
display: flex;
|
|
23
|
-
align-items: center;
|
|
24
|
-
justify-content: center;
|
|
25
|
-
height: 100vh;
|
|
26
|
-
overflow: hidden;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
#main-container {
|
|
30
|
-
width: 560px;
|
|
31
|
-
background: white;
|
|
32
|
-
padding: 40px;
|
|
33
|
-
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
34
|
-
position: relative;
|
|
35
|
-
transform: scale(1.1);
|
|
36
|
-
/* Slightly larger for visibility */
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.corner-badge {
|
|
40
|
-
position: absolute;
|
|
41
|
-
top: -10px;
|
|
42
|
-
left: -10px;
|
|
43
|
-
height: 28px;
|
|
44
|
-
padding: 0 12px;
|
|
45
|
-
background-color: var(--theme-color);
|
|
46
|
-
color: white;
|
|
47
|
-
display: flex;
|
|
48
|
-
align-items: center;
|
|
49
|
-
font-size: 12px;
|
|
50
|
-
font-weight: 800;
|
|
51
|
-
text-transform: uppercase;
|
|
52
|
-
letter-spacing: 0.5px;
|
|
53
|
-
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.15);
|
|
54
|
-
z-index: 10;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
h1 {
|
|
58
|
-
font-size: 32px;
|
|
59
|
-
font-weight: 900;
|
|
60
|
-
text-transform: uppercase;
|
|
61
|
-
letter-spacing: -1px;
|
|
62
|
-
margin: 0 0 24px 0;
|
|
63
|
-
line-height: 1.1;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.brand-text {
|
|
67
|
-
color: var(--theme-color);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.section-title {
|
|
71
|
-
font-size: 17px;
|
|
72
|
-
font-bold: 700;
|
|
73
|
-
text-transform: uppercase;
|
|
74
|
-
letter-spacing: -0.5px;
|
|
75
|
-
margin-bottom: 12px;
|
|
76
|
-
color: var(--text-primary);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.content-box {
|
|
80
|
-
padding-top: 24px;
|
|
81
|
-
border-top: 1px solid #eee;
|
|
82
|
-
margin-top: 32px;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.summary {
|
|
86
|
-
font-size: 15px;
|
|
87
|
-
line-height: 1.6;
|
|
88
|
-
color: var(--text-body);
|
|
89
|
-
text-align: justify;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.summary-en {
|
|
93
|
-
margin-top: 16px;
|
|
94
|
-
color: var(--text-muted);
|
|
95
|
-
font-size: 13px;
|
|
96
|
-
font-style: italic;
|
|
97
|
-
line-height: 1.5;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
b {
|
|
101
|
-
color: var(--theme-color);
|
|
102
|
-
font-weight: 700;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/* Subtle loading animation to show it's "live" */
|
|
106
|
-
.progress-bar {
|
|
107
|
-
height: 3px;
|
|
108
|
-
background: #f3f3f3;
|
|
109
|
-
width: 100%;
|
|
110
|
-
margin-top: 32px;
|
|
111
|
-
position: relative;
|
|
112
|
-
overflow: hidden;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.progress-fill {
|
|
116
|
-
position: absolute;
|
|
117
|
-
height: 100%;
|
|
118
|
-
background: var(--theme-color);
|
|
119
|
-
width: 30%;
|
|
120
|
-
left: -30%;
|
|
121
|
-
animation: moveProgress 2s infinite ease-in-out;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
@keyframes moveProgress {
|
|
125
|
-
0% {
|
|
126
|
-
left: -30%;
|
|
127
|
-
width: 20%;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
50% {
|
|
131
|
-
width: 50%;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
100% {
|
|
135
|
-
left: 100%;
|
|
136
|
-
width: 20%;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
</style>
|
|
140
|
-
</head>
|
|
141
|
-
|
|
142
|
-
<body>
|
|
143
|
-
<div id="main-container">
|
|
144
|
-
<!-- Corner Badge Style -->
|
|
145
|
-
<div class="corner-badge">
|
|
146
|
-
Status: Ready
|
|
147
|
-
</div>
|
|
148
|
-
|
|
149
|
-
<h1>entari-plugin-<span class="brand-text">hyw</span></h1>
|
|
150
|
-
|
|
151
|
-
<div class="content-box">
|
|
152
|
-
<div class="section-title">Browser Service</div>
|
|
153
|
-
<div class="summary">
|
|
154
|
-
这是一个受 <b>entari-plugin-hyw</b> 插件控制的自动化浏览器实例。<br>
|
|
155
|
-
它负责网络搜索、内容爬取以及卡片 UI 的实时渲染。<br>
|
|
156
|
-
请勿关闭此窗口,以确保插件功能正常运行。
|
|
157
|
-
</div>
|
|
158
|
-
|
|
159
|
-
<div class="summary-en">
|
|
160
|
-
This is an automated browser instance controlled by the <b>entari-plugin-hyw</b> plugin.
|
|
161
|
-
It handles web searches, content crawling, and real-time Card UI rendering.
|
|
162
|
-
Please do not close this window to ensure the plugin functions correctly.
|
|
163
|
-
</div>
|
|
164
|
-
</div>
|
|
165
|
-
|
|
166
|
-
<div class="progress-bar">
|
|
167
|
-
<div class="progress-fill"></div>
|
|
168
|
-
</div>
|
|
169
|
-
</div>
|
|
170
|
-
</body>
|
|
171
|
-
|
|
172
|
-
</html>
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Shared Browser Manager (DrissionPage)
|
|
3
|
-
|
|
4
|
-
Manages a single ChromiumPage browser instance.
|
|
5
|
-
Supports multi-tab concurrency via DrissionPage's built-in tab management.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import threading
|
|
9
|
-
from typing import Optional, Any
|
|
10
|
-
from loguru import logger
|
|
11
|
-
from DrissionPage import ChromiumPage, ChromiumOptions
|
|
12
|
-
from DrissionPage.errors import PageDisconnectedError
|
|
13
|
-
|
|
14
|
-
class SharedBrowserManager:
|
|
15
|
-
"""
|
|
16
|
-
Manages a shared DrissionPage Chromium browser.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
_instance: Optional["SharedBrowserManager"] = None
|
|
20
|
-
_lock = threading.Lock()
|
|
21
|
-
|
|
22
|
-
def __init__(self, headless: bool = True):
|
|
23
|
-
self.headless = headless
|
|
24
|
-
self._page: Optional[ChromiumPage] = None
|
|
25
|
-
self._starting = False
|
|
26
|
-
self._tab_lock = threading.Lock()
|
|
27
|
-
|
|
28
|
-
@classmethod
|
|
29
|
-
def get_instance(cls, headless: bool = True) -> "SharedBrowserManager":
|
|
30
|
-
"""Get or create the singleton SharedBrowserManager."""
|
|
31
|
-
with cls._lock:
|
|
32
|
-
if cls._instance is None:
|
|
33
|
-
cls._instance = cls(headless=headless)
|
|
34
|
-
return cls._instance
|
|
35
|
-
|
|
36
|
-
def start(self) -> bool:
|
|
37
|
-
"""Start the Chromium browser."""
|
|
38
|
-
if self._page is not None:
|
|
39
|
-
# Check if alive
|
|
40
|
-
try:
|
|
41
|
-
if self._page.run_cdp('Browser.getVersion'):
|
|
42
|
-
return True
|
|
43
|
-
except (PageDisconnectedError, Exception):
|
|
44
|
-
self._page = None
|
|
45
|
-
|
|
46
|
-
with self._lock:
|
|
47
|
-
if self._starting:
|
|
48
|
-
return False
|
|
49
|
-
self._starting = True
|
|
50
|
-
|
|
51
|
-
try:
|
|
52
|
-
logger.info("SharedBrowserManager: Starting DrissionPage browser...")
|
|
53
|
-
|
|
54
|
-
# Configure options
|
|
55
|
-
co = ChromiumOptions()
|
|
56
|
-
co.headless(self.headless)
|
|
57
|
-
co.auto_port() # Auto find available port
|
|
58
|
-
|
|
59
|
-
# Anti-detection settings
|
|
60
|
-
co.set_argument('--no-sandbox')
|
|
61
|
-
co.set_argument('--disable-gpu')
|
|
62
|
-
# Essential for loading local files and avoiding CORS issues
|
|
63
|
-
co.set_argument('--allow-file-access-from-files')
|
|
64
|
-
co.set_argument('--disable-web-security')
|
|
65
|
-
# Hide scrollbars globally
|
|
66
|
-
co.set_argument('--hide-scrollbars')
|
|
67
|
-
# 十万的原因是滚动条屏蔽(大概吧)
|
|
68
|
-
co.set_argument('--window-size=1280,800')
|
|
69
|
-
self._page = ChromiumPage(addr_or_opts=co)
|
|
70
|
-
|
|
71
|
-
# Show Landing Page
|
|
72
|
-
try:
|
|
73
|
-
import os
|
|
74
|
-
landing_path = os.path.join(os.path.dirname(__file__), 'landing.html')
|
|
75
|
-
if os.path.exists(landing_path):
|
|
76
|
-
self._page.get(f"file://{landing_path}")
|
|
77
|
-
except Exception as e:
|
|
78
|
-
logger.warning(f"SharedBrowserManager: Failed to show landing page: {e}")
|
|
79
|
-
|
|
80
|
-
logger.success(f"SharedBrowserManager: Browser ready (port={self._page.address})")
|
|
81
|
-
return True
|
|
82
|
-
|
|
83
|
-
except Exception as e:
|
|
84
|
-
logger.error(f"SharedBrowserManager: Failed to start browser: {e}")
|
|
85
|
-
self._page = None
|
|
86
|
-
raise
|
|
87
|
-
finally:
|
|
88
|
-
self._starting = False
|
|
89
|
-
|
|
90
|
-
@property
|
|
91
|
-
def page(self) -> Optional[ChromiumPage]:
|
|
92
|
-
"""Get the main ChromiumPage instance."""
|
|
93
|
-
if self._page is None:
|
|
94
|
-
self.start()
|
|
95
|
-
return self._page
|
|
96
|
-
|
|
97
|
-
def new_tab(self, url: str = None) -> Any:
|
|
98
|
-
"""
|
|
99
|
-
Thread-safe tab creation.
|
|
100
|
-
DrissionPage is thread-safe for tab creation, so we call it directly
|
|
101
|
-
to allow atomic creation+navigation (Target.createTarget with url)
|
|
102
|
-
without blocking other threads.
|
|
103
|
-
"""
|
|
104
|
-
page = self.page
|
|
105
|
-
if not page:
|
|
106
|
-
raise RuntimeError("Browser not available")
|
|
107
|
-
|
|
108
|
-
# Direct call allows Chrome to handle creation and navigation atomically and concurrently
|
|
109
|
-
return page.new_tab(url)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def close(self):
|
|
113
|
-
"""Shutdown the browser."""
|
|
114
|
-
with self._lock:
|
|
115
|
-
if self._page:
|
|
116
|
-
try:
|
|
117
|
-
self._page.quit()
|
|
118
|
-
logger.info("SharedBrowserManager: Browser closed.")
|
|
119
|
-
except Exception as e:
|
|
120
|
-
logger.warning(f"SharedBrowserManager: Error closing browser: {e}")
|
|
121
|
-
finally:
|
|
122
|
-
self._page = None
|
|
123
|
-
|
|
124
|
-
@staticmethod
|
|
125
|
-
def hide_scrollbars(page: ChromiumPage):
|
|
126
|
-
"""
|
|
127
|
-
Robustly hide scrollbars using CDP commands AND CSS injection.
|
|
128
|
-
This provides double protection against scrollbar gutters.
|
|
129
|
-
"""
|
|
130
|
-
try:
|
|
131
|
-
# 1. CDP Command
|
|
132
|
-
page.run_cdp('Emulation.setScrollbarsHidden', hidden=True)
|
|
133
|
-
|
|
134
|
-
# 2. CSS Injection (Standard + Webkit)
|
|
135
|
-
css = """
|
|
136
|
-
::-webkit-scrollbar { display: none !important; width: 0 !important; height: 0 !important; }
|
|
137
|
-
* { -ms-overflow-style: none !important; scrollbar-width: none !important; }
|
|
138
|
-
"""
|
|
139
|
-
# Inject into current page
|
|
140
|
-
page.run_js(f"""
|
|
141
|
-
const style = document.createElement('style');
|
|
142
|
-
style.textContent = `{css}`;
|
|
143
|
-
document.head.appendChild(style);
|
|
144
|
-
""")
|
|
145
|
-
|
|
146
|
-
logger.debug("SharedBrowserManager: Scrollbars hidden via CDP + CSS.")
|
|
147
|
-
except Exception as e:
|
|
148
|
-
logger.warning(f"SharedBrowserManager: Failed to hide scrollbars: {e}")
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
# Module-level singleton accessor
|
|
152
|
-
_shared_manager: Optional[SharedBrowserManager] = None
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
def get_shared_browser_manager(headless: bool = True) -> SharedBrowserManager:
|
|
156
|
-
"""
|
|
157
|
-
Get or create the shared browser manager.
|
|
158
|
-
"""
|
|
159
|
-
global _shared_manager
|
|
160
|
-
|
|
161
|
-
if _shared_manager is None:
|
|
162
|
-
_shared_manager = SharedBrowserManager.get_instance(headless=headless)
|
|
163
|
-
_shared_manager.start()
|
|
164
|
-
|
|
165
|
-
return _shared_manager
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
def close_shared_browser():
|
|
169
|
-
"""Close the shared browser manager."""
|
|
170
|
-
global _shared_manager
|
|
171
|
-
if _shared_manager:
|
|
172
|
-
_shared_manager.close()
|
|
173
|
-
_shared_manager = None
|