entari-plugin-hyw 4.0.0rc9__py3-none-any.whl → 4.0.0rc11__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.

@@ -108,6 +108,13 @@ def parse_filter_syntax(query: str, max_count: int = 3):
108
108
  if total > max_count:
109
109
  return [], search_query, f"最多选择{max_count}个结果 (当前选择了{total}个)"
110
110
 
111
+ # Append filter names to search query
112
+ # Extract filter names (only 'link' type, skip 'index' type)
113
+ filter_names = [f[1] for f in filters if f[0] == 'link']
114
+ if filter_names:
115
+ # Append filter names to search query: "search_query filter1 filter2"
116
+ search_query = f"{search_query} {' '.join(filter_names)}"
117
+
111
118
  return filters, search_query, None
112
119
 
113
120
 
@@ -162,6 +169,7 @@ class HywConfig(BasicConfModel):
162
169
  admins: List[str] = field(default_factory=list)
163
170
  models: List[Dict[str, Any]] = field(default_factory=list)
164
171
  question_command: str = "/q"
172
+ web_command: str = "/w"
165
173
  language: str = "Simplified Chinese"
166
174
  temperature: float = 0.4
167
175
 
@@ -169,7 +177,7 @@ class HywConfig(BasicConfModel):
169
177
  api_key: Optional[str] = None
170
178
  base_url: str = "https://openrouter.ai/api/v1"
171
179
 
172
- search_engine: str = "google"
180
+ search_engine: str = "duckduckgo"
173
181
 
174
182
  headless: bool = False
175
183
  save_conversation: bool = False
@@ -177,19 +185,14 @@ class HywConfig(BasicConfModel):
177
185
  quote: bool = False
178
186
  theme_color: str = "#ff0000"
179
187
 
180
- # Nested configurations
188
+ # Main model configuration (used for summary/main LLM calls)
181
189
  main: Optional[Dict[str, Any]] = None
182
- instruct: Optional[Dict[str, Any]] = None
183
- vision: Optional[Dict[str, Any]] = None
184
- deepsearch_instruct: Optional[Dict[str, Any]] = None
185
- deepsearch_agent: Optional[Dict[str, Any]] = None
186
190
 
187
191
  def __post_init__(self):
188
192
  self.theme_color = parse_color(self.theme_color)
189
193
 
190
194
  def to_hyw_core_config(self) -> HywCoreConfig:
191
195
  main_cfg = self.main or {}
192
- instruct_cfg = self.instruct or {}
193
196
 
194
197
  return HywCoreConfig.from_dict({
195
198
  "models": self.models,
@@ -207,20 +210,7 @@ class HywConfig(BasicConfModel):
207
210
  "summary_api_key": main_cfg.get("api_key"),
208
211
  "summary_base_url": main_cfg.get("base_url"),
209
212
  "summary_extra_body": main_cfg.get("extra_body"),
210
-
211
- # Map nested 'instruct' config to instruct stage
212
- "instruct_model": instruct_cfg.get("model_name"),
213
- "instruct_api_key": instruct_cfg.get("api_key"),
214
- "instruct_base_url": instruct_cfg.get("base_url"),
215
- "instruct_extra_body": instruct_cfg.get("extra_body"),
216
213
  })
217
-
218
- def get_model_config(self, stage: str) -> Dict[str, Any]:
219
- return {
220
- "model_name": self.model_name,
221
- "api_key": self.api_key,
222
- "base_url": self.base_url,
223
- }
224
214
 
225
215
 
226
216
  conf = plugin_config(HywConfig)
@@ -229,12 +219,11 @@ renderer = ContentRenderer(headless=conf.headless)
229
219
  set_global_renderer(renderer)
230
220
  search_cache = SearchResultCache(ttl_seconds=600.0) # 10 minutes
231
221
 
232
- _hyw_core: Optional[HywCore] = None
222
+ # Initialize HywCore immediately at plugin load time (not lazy)
223
+ # This avoids the 2s delay on first user request caused by AsyncOpenAI client creation
224
+ _hyw_core: HywCore = HywCore(conf.to_hyw_core_config())
233
225
 
234
226
  def get_hyw_core() -> HywCore:
235
- global _hyw_core
236
- if _hyw_core is None:
237
- _hyw_core = HywCore(conf.to_hyw_core_config())
238
227
  return _hyw_core
239
228
 
240
229
 
@@ -690,7 +679,7 @@ async def handle_question_command(session: Session[MessageCreatedEvent], result:
690
679
 
691
680
 
692
681
  # Search/Web Command (/w)
693
- alc_search = Alconna("/w", Args["query;?", AllParam])
682
+ alc_search = Alconna(conf.web_command, Args["query;?", AllParam])
694
683
 
695
684
  @command.on(alc_search)
696
685
  async def handle_web_command(session: Session[MessageCreatedEvent], result: Arparma):
@@ -756,6 +745,17 @@ async def handle_web_command(session: Session[MessageCreatedEvent], result: Arpa
756
745
 
757
746
  search_cache.cleanup()
758
747
  return
748
+ else:
749
+ # Reply to a non-cached message: append reply content to query
750
+ try:
751
+ # session.reply.origin.message is a list, wrap it in MessageChain
752
+ reply_msg = MessageChain(session.reply.origin.message)
753
+ reply_content = str(reply_msg.get(Text)).strip()
754
+ if reply_content:
755
+ query = f"{query} {reply_content}".strip() if query else reply_content
756
+ logger.info(f"/w appended reply content, new query: '{query}'")
757
+ except Exception as e:
758
+ logger.warning(f"/w failed to extract reply content: {e}")
759
759
 
760
760
  # No query and no cache context - nothing to do
761
761
  if not query:
@@ -805,9 +805,15 @@ async def handle_web_command(session: Session[MessageCreatedEvent], result: Arpa
805
805
  await session.send(filter_error)
806
806
  return
807
807
 
808
- # Search first
808
+ # Start search first
809
+ local_renderer = await get_content_renderer()
809
810
  search_task = asyncio.create_task(core.search([search_query]))
810
811
 
812
+ # Only pre-warm tab if NOT in filter mode (filter mode = screenshots only, no card render)
813
+ tab_task = None
814
+ if not filters:
815
+ tab_task = asyncio.create_task(local_renderer.prepare_tab())
816
+
811
817
  if conf.reaction:
812
818
  asyncio.create_task(react(session, "🔍"))
813
819
 
@@ -815,17 +821,24 @@ async def handle_web_command(session: Session[MessageCreatedEvent], result: Arpa
815
821
  flat_results = results[0] if results else []
816
822
 
817
823
  if not flat_results:
824
+ if tab_task:
825
+ try: await tab_task
826
+ except: pass
818
827
  await session.send("Search returned no results.")
819
828
  return
820
829
 
821
830
  visible = [r for r in flat_results if not r.get("_hidden", False)]
822
831
 
823
832
  if not visible:
833
+ if tab_task:
834
+ try: await tab_task
835
+ except: pass
824
836
  await session.send("Search returned no visible results.")
825
837
  return
826
838
 
827
- # === Filter Mode: Screenshot matching links ===
839
+ # === Filter Mode: Screenshot matching links (NO tab needed) ===
828
840
  if filters:
841
+
829
842
  urls_to_screenshot = []
830
843
 
831
844
  for filter_type, filter_value, count in filters:
@@ -881,20 +894,42 @@ async def handle_web_command(session: Session[MessageCreatedEvent], result: Arpa
881
894
  await session.send("截图失败")
882
895
  return
883
896
 
884
- # === Normal Search Mode: Screenshot search results page ===
885
- search_service = core._search_service
886
- search_url = search_service._build_search_url(search_query)
897
+ # === Normal Search Mode: Render search results as Sources card ===
898
+
899
+ # Build references from search results for Sources card
900
+ references = []
901
+ for i, res in enumerate(visible[:10]):
902
+ references.append({
903
+ "title": res.get("title", f"Result {i+1}"),
904
+ "url": res.get("url", ""),
905
+ "snippet": res.get("content", "") or res.get("snippet", ""),
906
+ "original_idx": i + 1,
907
+ })
908
+
909
+ try:
910
+ tab_id = await tab_task
911
+ except Exception:
912
+ tab_id = None
887
913
 
888
- # Handle address bar search marker
889
- if search_url.startswith("__ADDRESS_BAR_SEARCH__:"):
890
- import urllib.parse
891
- encoded_query = urllib.parse.quote_plus(search_query)
892
- search_url = f"https://www.google.com/search?q={encoded_query}"
914
+ with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tf:
915
+ output_path = tf.name
893
916
 
894
- b64_img = await core.screenshot(search_url)
917
+ # Render Sources card with search results (no markdown content, just references)
918
+ render_ok = await core.render(
919
+ markdown_content=f"# 搜索结果: {search_query}",
920
+ output_path=output_path,
921
+ stats={"total_time": 0},
922
+ references=references,
923
+ page_references=[],
924
+ stages_used=[{"name": "search", "description": f"搜索 \"{search_query}\"", "time": 0}],
925
+ tab_id=tab_id
926
+ )
895
927
 
896
- if b64_img:
897
- msg_chain = MessageChain(Image(src=f'data:image/jpeg;base64,{b64_img}'))
928
+ if render_ok and os.path.exists(output_path):
929
+ with open(output_path, "rb") as f:
930
+ img_data = base64.b64encode(f.read()).decode()
931
+
932
+ msg_chain = MessageChain(Image(src=f'data:image/png;base64,{img_data}'))
898
933
  if conf.quote:
899
934
  msg_chain = MessageChain(Quote(session.event.message.id)) + msg_chain
900
935
 
@@ -909,8 +944,10 @@ async def handle_web_command(session: Session[MessageCreatedEvent], result: Arpa
909
944
  mid = str(session.event.message.id) if getattr(session.event, "message", None) else str(session.event.id)
910
945
  context_id = f"guild_{session.guild.id}" if session.guild else "user"
911
946
  history_manager.remember(mid, [{"role": "user", "content": f"/w {query}"}], [], {}, context_id=context_id)
947
+
948
+ os.remove(output_path)
912
949
  else:
913
- await session.send(f"截图搜索页面失败: {search_url}")
950
+ await session.send("渲染搜索结果失败")
914
951
 
915
952
  search_cache.cleanup() # Lazy cleanup
916
953
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: entari_plugin_hyw
3
- Version: 4.0.0rc9
3
+ Version: 4.0.0rc11
4
4
  Summary: Use large language models to interpret chat messages
5
5
  Author-email: kumoSleeping <zjr2992@outlook.com>
6
6
  License: MIT
@@ -1,22 +1,22 @@
1
1
  entari_plugin_hyw/Untitled-1,sha256=wbsr5i9iorqBMIYK4aAnpNTek3mXbhvyo2YOYw38pE4,30187
2
- entari_plugin_hyw/__init__.py,sha256=laQrEH-CdofBg3EEqIEOTwJu0pHlMG0wIvdQo8AycZk,35057
2
+ entari_plugin_hyw/__init__.py,sha256=QctcJLLU2B86EiiNZPS5HDK7vVwm2PpOmd5aL2Ge0J0,36757
3
3
  entari_plugin_hyw/history.py,sha256=0XJwbfvXH5T1EPt4G1J5wWMJsKi0FfmajY5cvw8CQWE,12065
4
4
  entari_plugin_hyw/misc.py,sha256=4ABzCHbEA87UCQfBX7AgAqACQwjQIhCSZuqHXPFGokg,5527
5
5
  entari_plugin_hyw/search_cache.py,sha256=7MIhTm5_YnZjc0aBaX7AE4AJp0VT8eU6ObR6mTkoerc,4285
6
6
  hyw_core/__init__.py,sha256=Jlr9Ic-BLOPTnff6OctUCdjDMdK4nssTF_vHie4QKTo,1958
7
7
  hyw_core/config.py,sha256=DHxwToUVLm1nT88gG05e3hVzSLxXMk9BjgjAnhGCADk,4918
8
- hyw_core/core.py,sha256=G96C9mhmuXRwFOwIYm5M6q0ys1QD_2eQYvP89e_bmWg,10455
8
+ hyw_core/core.py,sha256=TVtZd0ufppThNlqygpp84u7eNwcAs17SquTHqLTXM1g,10236
9
9
  hyw_core/definitions.py,sha256=syYMNy3vdey7VuSlD3JUZ0gjlp5tmVkGHup-nimT0X0,3264
10
10
  hyw_core/image_cache.py,sha256=t8pr1kgH2ngK9IhrBAhzUqhBWERNztUywMzgCFZEtQk,9899
11
11
  hyw_core/pipeline.py,sha256=ZWwF0DHa29-65lUMU1_Fem3xQmxl7X_vgeni0ErOb8Q,22826
12
- hyw_core/search.py,sha256=IqYCeWkIPpssLx8vHEv3qbqndLuPy5z6cE_L-IhNcNk,7468
13
- hyw_core/browser_control/__init__.py,sha256=X1vHZpYXLG-P1RRivVyK014WKnv48GN1ibF9TbMp_-c,1482
12
+ hyw_core/search.py,sha256=L9LF3s4o4-ypDRyevvIlAqC0pa7xNYv-nESAql9N-pk,7345
13
+ hyw_core/browser_control/__init__.py,sha256=IeMErRC6fbq1PJWNK3klSbarSrUwOM4yyd_kJ6uWCPM,1406
14
14
  hyw_core/browser_control/landing.html,sha256=wgqldumdylz69T83pvOkrigT1Mdb9GY0_KU0ceLGwdY,4642
15
- hyw_core/browser_control/manager.py,sha256=U8dVpkWTG5pcIE5WiSQSfTx4gEo9PnBbmBD0KZcLBbU,5513
16
- hyw_core/browser_control/renderer.py,sha256=hsCjJPMSCAvqTFtiAmyjaw0IE8xmbIjq5VK9dd70gfc,15539
17
- hyw_core/browser_control/service.py,sha256=tuNaEnxRZVkLgQczWnWDyEHXhyvhF9RboDmnT3OFX34,35905
15
+ hyw_core/browser_control/manager.py,sha256=-dHb0FamRsLfuU3jqX5cKaDo8DOOFV32zY912GuMdXU,6048
16
+ hyw_core/browser_control/renderer.py,sha256=s-QNIU-NMVQGLd_drLmeERgHsTm6C9XYm78CObt2KXc,17409
17
+ hyw_core/browser_control/service.py,sha256=L2_gwEqOXZJBZGJSgWfqEBNZoGNHaDhJSq9gl7NqIuQ,41009
18
18
  hyw_core/browser_control/assets/index.html,sha256=BpbM0vD9OYicE5MBHSVLo3j_y-MpULI82PMqmBKpWT8,2328623
19
- hyw_core/browser_control/assets/card-dist/index.html,sha256=fNfT_0TgSZLqwuTtKAl3Wzc4lKRAY_rbWxc_mQHfaCs,2209006
19
+ hyw_core/browser_control/assets/card-dist/index.html,sha256=Xw-hQ5ctdQkK-1jV8_gqMdgVGNZDwWZvIAqNrh2eK7g,2210054
20
20
  hyw_core/browser_control/assets/card-dist/vite.svg,sha256=SnSK_UQ5GLsWWRyDTEAdrjPoeGGrXbrQgRw6O0qSFPs,1497
21
21
  hyw_core/browser_control/assets/card-dist/logos/anthropic.svg,sha256=ASsy1ypo3osNc3n-B0R81tk_dIFsVgg7qQORrd5T2kA,558
22
22
  hyw_core/browser_control/assets/card-dist/logos/cerebras.svg,sha256=bpmiiYTODwc06knTmPj3GQ7NNtosMog5lkggvB_Z-7M,44166
@@ -54,15 +54,17 @@ hyw_core/browser_control/assets/logos/qwen.png,sha256=eqLbnIPbjh2_PsODU_mmqjeD82
54
54
  hyw_core/browser_control/assets/logos/xai.png,sha256=uSulvvDVqoA4RUOW0ZAkdvBVM2rpyGJRZIbn5dEFspw,362
55
55
  hyw_core/browser_control/assets/logos/xiaomi.png,sha256=WHxlDFGU5FCjb-ure3ngdGG18-efYZUUfqA3_lqCUN0,4084
56
56
  hyw_core/browser_control/assets/logos/zai.png,sha256=K-gnabdsjMLInppHA1Op7Nyt33iegrx1x-yNlvCZ0Tc,2351
57
- hyw_core/browser_control/engines/__init__.py,sha256=G-bjcxWMaPZoR4tUz-OcGhZDkQwkXjK234qVEFvjEbE,338
57
+ hyw_core/browser_control/engines/__init__.py,sha256=01-jOjvtQcqWIwwY56ql3j00oSHGE2XhDHjkIi1Ij3Q,284
58
58
  hyw_core/browser_control/engines/base.py,sha256=q5y4SM1G6xS7-6TQ-nZz9iTWw3XonjJn01fWzoTxr6c,414
59
59
  hyw_core/browser_control/engines/default.py,sha256=BlHCQI4-rN9cEzLLfqvRD4bvhyP2G2KUGlo92J4kFNw,6092
60
60
  hyw_core/browser_control/engines/duckduckgo.py,sha256=QVYj1I6Fw6--2-f3DYdHVlOmeLPzet9qG4HUT7ynrSE,6789
61
- hyw_core/browser_control/engines/google.py,sha256=PmU0_n8UrnQ1oyYVS-Y_jLS6rzgkQZK_7yHlGeAUooY,6098
61
+ hyw_core/crawling/__init__.py,sha256=W5Be02uQueAyADFhPXVbDAFpNUJ_W7KdMtMr923_N24,437
62
+ hyw_core/crawling/completeness.py,sha256=OKdS8XlYYWDU1Vl1k-u7yEFqppukuJv-YQB0Px5KC2Q,16371
63
+ hyw_core/crawling/models.py,sha256=pCKe0k9xT3taSAlTlh0PazcLV0xYsm8p3XIkLHGf-LM,2353
62
64
  hyw_core/stages/__init__.py,sha256=W89cWpq-HBLi2FprtJQSjQNLzpbhM8ZCkqPG61D_imE,521
63
65
  hyw_core/stages/base.py,sha256=EfnTkISXbBNxjARykqIhmMrVqw2tqZl7ozJbJEbRnhI,2806
64
66
  hyw_core/stages/summary.py,sha256=ODOwhIAmBZJuA4KOhUP7Lygch7XSkshrTZj-MdZjbEs,7085
65
- entari_plugin_hyw-4.0.0rc9.dist-info/METADATA,sha256=ofBdYe9A6sFakK9NDDpnmTczWuh1mbm6OpzpLO1j3cc,3844
66
- entari_plugin_hyw-4.0.0rc9.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
67
- entari_plugin_hyw-4.0.0rc9.dist-info/top_level.txt,sha256=ah76OrufRX0okOl4Fv8MO6PXiT0IaZ1oG0eDrdAPoNo,27
68
- entari_plugin_hyw-4.0.0rc9.dist-info/RECORD,,
67
+ entari_plugin_hyw-4.0.0rc11.dist-info/METADATA,sha256=2ljFQCOFDAcJDu-M_UnHxS2acIbUSPMXd57Yvyrj5S4,3845
68
+ entari_plugin_hyw-4.0.0rc11.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
69
+ entari_plugin_hyw-4.0.0rc11.dist-info/top_level.txt,sha256=ah76OrufRX0okOl4Fv8MO6PXiT0IaZ1oG0eDrdAPoNo,27
70
+ entari_plugin_hyw-4.0.0rc11.dist-info/RECORD,,
@@ -5,7 +5,7 @@ This subpackage provides:
5
5
  - BrowserManager: Shared browser instance management
6
6
  - PageService: Page fetching and screenshot capabilities
7
7
  - RenderService: Vue-based card rendering
8
- - Search engines: Bing, Google, DuckDuckGo adapters
8
+ - Search engines: DuckDuckGo adapter
9
9
  """
10
10
 
11
11
  from .manager import (
@@ -28,7 +28,6 @@ from .renderer import (
28
28
  )
29
29
 
30
30
  from .engines.base import SearchEngine
31
- from .engines.google import GoogleEngine
32
31
  from .engines.duckduckgo import DuckDuckGoEngine
33
32
  from .engines.default import DefaultEngine
34
33
 
@@ -59,7 +58,6 @@ __all__ = [
59
58
 
60
59
  # Search Engines
61
60
  "SearchEngine",
62
- "GoogleEngine",
63
61
  "DuckDuckGoEngine",
64
62
  "DefaultEngine",
65
63
  ]