entari-plugin-hyw 0.3.5__py3-none-any.whl → 4.0.0rc14__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.

Files changed (78) hide show
  1. entari_plugin_hyw/Untitled-1 +1865 -0
  2. entari_plugin_hyw/__init__.py +979 -116
  3. entari_plugin_hyw/filters.py +83 -0
  4. entari_plugin_hyw/history.py +251 -0
  5. entari_plugin_hyw/misc.py +214 -0
  6. entari_plugin_hyw/search_cache.py +154 -0
  7. entari_plugin_hyw-4.0.0rc14.dist-info/METADATA +118 -0
  8. entari_plugin_hyw-4.0.0rc14.dist-info/RECORD +72 -0
  9. {entari_plugin_hyw-0.3.5.dist-info → entari_plugin_hyw-4.0.0rc14.dist-info}/WHEEL +1 -1
  10. {entari_plugin_hyw-0.3.5.dist-info → entari_plugin_hyw-4.0.0rc14.dist-info}/top_level.txt +1 -0
  11. hyw_core/__init__.py +94 -0
  12. hyw_core/agent.py +768 -0
  13. hyw_core/browser_control/__init__.py +63 -0
  14. hyw_core/browser_control/assets/card-dist/index.html +425 -0
  15. hyw_core/browser_control/assets/card-dist/logos/anthropic.svg +1 -0
  16. hyw_core/browser_control/assets/card-dist/logos/cerebras.svg +9 -0
  17. hyw_core/browser_control/assets/card-dist/logos/deepseek.png +0 -0
  18. hyw_core/browser_control/assets/card-dist/logos/gemini.svg +1 -0
  19. hyw_core/browser_control/assets/card-dist/logos/google.svg +1 -0
  20. hyw_core/browser_control/assets/card-dist/logos/grok.png +0 -0
  21. hyw_core/browser_control/assets/card-dist/logos/huggingface.png +0 -0
  22. hyw_core/browser_control/assets/card-dist/logos/microsoft.svg +15 -0
  23. hyw_core/browser_control/assets/card-dist/logos/minimax.png +0 -0
  24. hyw_core/browser_control/assets/card-dist/logos/mistral.png +0 -0
  25. hyw_core/browser_control/assets/card-dist/logos/nvida.png +0 -0
  26. hyw_core/browser_control/assets/card-dist/logos/openai.svg +1 -0
  27. hyw_core/browser_control/assets/card-dist/logos/openrouter.png +0 -0
  28. hyw_core/browser_control/assets/card-dist/logos/perplexity.svg +24 -0
  29. hyw_core/browser_control/assets/card-dist/logos/qwen.png +0 -0
  30. hyw_core/browser_control/assets/card-dist/logos/xai.png +0 -0
  31. hyw_core/browser_control/assets/card-dist/logos/xiaomi.png +0 -0
  32. hyw_core/browser_control/assets/card-dist/logos/zai.png +0 -0
  33. hyw_core/browser_control/assets/card-dist/vite.svg +1 -0
  34. hyw_core/browser_control/assets/index.html +5691 -0
  35. hyw_core/browser_control/assets/logos/anthropic.svg +1 -0
  36. hyw_core/browser_control/assets/logos/cerebras.svg +9 -0
  37. hyw_core/browser_control/assets/logos/deepseek.png +0 -0
  38. hyw_core/browser_control/assets/logos/gemini.svg +1 -0
  39. hyw_core/browser_control/assets/logos/google.svg +1 -0
  40. hyw_core/browser_control/assets/logos/grok.png +0 -0
  41. hyw_core/browser_control/assets/logos/huggingface.png +0 -0
  42. hyw_core/browser_control/assets/logos/microsoft.svg +15 -0
  43. hyw_core/browser_control/assets/logos/minimax.png +0 -0
  44. hyw_core/browser_control/assets/logos/mistral.png +0 -0
  45. hyw_core/browser_control/assets/logos/nvida.png +0 -0
  46. hyw_core/browser_control/assets/logos/openai.svg +1 -0
  47. hyw_core/browser_control/assets/logos/openrouter.png +0 -0
  48. hyw_core/browser_control/assets/logos/perplexity.svg +24 -0
  49. hyw_core/browser_control/assets/logos/qwen.png +0 -0
  50. hyw_core/browser_control/assets/logos/xai.png +0 -0
  51. hyw_core/browser_control/assets/logos/xiaomi.png +0 -0
  52. hyw_core/browser_control/assets/logos/zai.png +0 -0
  53. hyw_core/browser_control/engines/__init__.py +15 -0
  54. hyw_core/browser_control/engines/base.py +13 -0
  55. hyw_core/browser_control/engines/default.py +166 -0
  56. hyw_core/browser_control/engines/duckduckgo.py +171 -0
  57. hyw_core/browser_control/landing.html +172 -0
  58. hyw_core/browser_control/manager.py +173 -0
  59. hyw_core/browser_control/renderer.py +446 -0
  60. hyw_core/browser_control/service.py +940 -0
  61. hyw_core/config.py +154 -0
  62. hyw_core/core.py +462 -0
  63. hyw_core/crawling/__init__.py +18 -0
  64. hyw_core/crawling/completeness.py +437 -0
  65. hyw_core/crawling/models.py +88 -0
  66. hyw_core/definitions.py +104 -0
  67. hyw_core/image_cache.py +274 -0
  68. hyw_core/pipeline.py +502 -0
  69. hyw_core/search.py +171 -0
  70. hyw_core/stages/__init__.py +21 -0
  71. hyw_core/stages/base.py +95 -0
  72. hyw_core/stages/summary.py +191 -0
  73. entari_plugin_hyw/agent.py +0 -419
  74. entari_plugin_hyw/compressor.py +0 -59
  75. entari_plugin_hyw/tools.py +0 -236
  76. entari_plugin_hyw/vision.py +0 -35
  77. entari_plugin_hyw-0.3.5.dist-info/METADATA +0 -112
  78. entari_plugin_hyw-0.3.5.dist-info/RECORD +0 -9
@@ -1,236 +0,0 @@
1
- import asyncio
2
- import httpx
3
- import json
4
- from typing import List, Optional
5
- from langchain_core.tools import tool
6
- from langchain_openai import ChatOpenAI
7
- from loguru import logger
8
-
9
- from .compressor import WebpageCompressor
10
-
11
-
12
- # 全局搜索引擎配置
13
- _global_search_engines = ["auto"]
14
-
15
- # 全局压缩器配置
16
- _global_compressor: Optional[WebpageCompressor] = None
17
-
18
-
19
- def set_global_search_engines(engines: List[str]):
20
- """设置全局搜索引擎列表"""
21
- global _global_search_engines
22
- _global_search_engines = engines
23
-
24
-
25
- def set_global_compressor_llm(llm: ChatOpenAI):
26
- """设置全局压缩器LLM"""
27
- global _global_compressor
28
- _global_compressor = WebpageCompressor(llm)
29
- logger.info("[工具] 压缩器已初始化")
30
-
31
-
32
-
33
- # 智能搜索工具
34
- @tool
35
- async def web_search(query: str) -> str:
36
- """
37
- - web_search 每个查询只能包含一个的关键词建议在 1-2 个词之间 不超过 3 个词
38
- - 多引擎并发搜索工具,使用配置文件指定的搜索引擎进行搜索
39
- - 支持同时搜索多个搜索引擎并合并结果
40
- - 搜索引擎配置在 entari.yml 中的 search_engines 字段,如 ["duckduckgo::exact", "duckduckgo"],::exact 表示精确搜索
41
- - 自动去重和合并来自不同搜索引擎的结果,提供更全面的信息
42
- 智能搜索工具, 返回JSON格式文本结果
43
- query: 要搜索的关键词
44
- """
45
-
46
- async def ddsg_search(keyword: str, backend: str, is_exact: bool = False) -> dict:
47
- """单个搜索引擎搜索"""
48
- from ddgs import DDGS
49
-
50
- def _sync_search():
51
- # 简化的搜索逻辑
52
- search_keyword = f'"{keyword}"' if is_exact else keyword
53
- logger.info(f"DDGS 搜索: 关键词='{search_keyword}', 引擎='{backend}'")
54
- return DDGS().text(search_keyword, safesearch="off", timelimit="y", max_results=7, backend=backend)
55
-
56
- try:
57
- results = await asyncio.to_thread(_sync_search)
58
- logger.info(f"搜索完成: {backend} -> {len(results)} 个结果")
59
- return {"engine": backend, "results": results, "success": True}
60
- except Exception as e:
61
- logger.error(f"搜索失败: {backend} -> {e}")
62
- return {"engine": backend, "results": [], "success": False, "error": str(e)}
63
-
64
- def parse_engines(engines_list: List[str]) -> List[tuple]:
65
- """解析搜索引擎列表,提取引擎名称和是否精确搜索"""
66
- parsed = []
67
- for engine in engines_list:
68
- if "::exact" in engine:
69
- base_engine = engine.replace("::exact", "")
70
- parsed.append((base_engine, True))
71
- else:
72
- parsed.append((engine, False))
73
- return parsed
74
-
75
- try:
76
- # 使用全局配置的搜索引擎列表
77
- if len(_global_search_engines) == 1:
78
- logger.info(f"使用单引擎搜索模式: {_global_search_engines[0]}")
79
- parsed_engines = parse_engines(_global_search_engines)
80
- engine_name, is_exact = parsed_engines[0]
81
- single_result = await ddsg_search(query, engine_name, is_exact)
82
- # 对精确模式进行客户端二次过滤,确保只保留包含完整查询词的结果
83
- filtered_results = single_result.get("results", [])
84
- if is_exact:
85
- q = (query or "").lower()
86
- def _hit(res: dict) -> bool:
87
- title = (res.get("title") or "").lower()
88
- body = (res.get("body") or "").lower()
89
- href = (res.get("href") or "").lower()
90
- return (q in title) or (q in body) or (q in href)
91
- filtered_results = [r for r in filtered_results if _hit(r)]
92
-
93
- result_data = {
94
- "query": query,
95
- "results": filtered_results,
96
- "search_type": "single_engine",
97
- "engine": _global_search_engines[0],
98
- "search_mode": "exact" if is_exact else "normal",
99
- "success": single_result.get("success", False),
100
- "exact_matched": (len(filtered_results) > 0) if is_exact else None,
101
- "note": ("没有精确匹配结果" if (is_exact and len(filtered_results) == 0) else None),
102
- "error": single_result.get("error")
103
- }
104
-
105
- return json.dumps(result_data, ensure_ascii=False, indent=2)
106
-
107
- # 使用全局配置的搜索引擎列表进行多引擎搜索
108
- search_engines = _global_search_engines
109
- parsed_engines = parse_engines(search_engines)
110
- logger.info(f"开始多引擎并发搜索: 查询='{query}', 引擎={search_engines}")
111
-
112
- # 并发执行所有搜索引擎的搜索
113
- search_tasks = [ddsg_search(query, engine_name, is_exact) for engine_name, is_exact in parsed_engines]
114
- search_results = await asyncio.gather(*search_tasks, return_exceptions=True)
115
-
116
- # 简化的结果处理
117
- merged_results = {}
118
- successful_engines = []
119
- failed_engines = []
120
-
121
- for i, result in enumerate(search_results):
122
- if isinstance(result, Exception) or not isinstance(result, dict):
123
- continue
124
-
125
- engine_config = parsed_engines[i] if i < len(parsed_engines) else ("unknown", False)
126
- engine_name, is_exact = engine_config
127
- display_name = f"{engine_name}(精确)" if is_exact else f"{engine_name}(普通)"
128
-
129
- # 简单格式化结果 + 精确模式客户端二次过滤
130
- raw_results = result.get("results", [])
131
- if is_exact:
132
- q = (query or "").lower()
133
- def _hit(res: dict) -> bool:
134
- title = (res.get("title") or "").lower()
135
- body = (res.get("body") or "").lower()
136
- href = (res.get("href") or "").lower()
137
- return (q in title) or (q in body) or (q in href)
138
- raw_results = [r for r in raw_results if _hit(r)]
139
- if len(raw_results) == 0:
140
- logger.info(f"精确模式无匹配: 查询='{query}', 引擎='{engine_name}'")
141
- formatted_results = []
142
- for j, res in enumerate(raw_results):
143
- formatted_results.append({
144
- "title": res.get("title", ""),
145
- "href": res.get("href", ""),
146
- "body": res.get("body", ""),
147
- "source": display_name
148
- })
149
-
150
- # 使用不同的键名来区分同一引擎的不同搜索模式
151
- result_key = f"{engine_name}_exact" if is_exact else engine_name
152
- merged_results[result_key] = {
153
- "results": formatted_results,
154
- "success": result.get("success", False),
155
- "display_name": display_name,
156
- "engine_name": engine_name,
157
- "is_exact": is_exact,
158
- "exact_matched": (len(formatted_results) > 0) if is_exact else None,
159
- "note": ("没有精确匹配结果" if (is_exact and len(formatted_results) == 0) else None)
160
- }
161
-
162
- if result.get("success", False):
163
- successful_engines.append(result_key)
164
- else:
165
- failed_engines.append(result_key)
166
-
167
- # 不去重,保留所有结果,让LLM能够看到不同搜索模式的差异
168
- unique_results = []
169
- for result in merged_results.values():
170
- unique_results.extend(result["results"])
171
-
172
- # 构建结果
173
- result_data = {
174
- "query": query,
175
- "merged_results": unique_results,
176
- "engine_results": merged_results,
177
- "search_type": "multi_engine",
178
- "stats": {
179
- "total_results": len(unique_results),
180
- "successful_engines_count": len(successful_engines),
181
- "failed_engines_count": len(failed_engines)
182
- }
183
- }
184
-
185
- logger.info(f"多引擎搜索完成: 成功引擎 {len(successful_engines)}/{len(search_engines)}, 总结果: {unique_results}")
186
- return json.dumps(result_data, ensure_ascii=False, indent=2)
187
-
188
- except Exception as e:
189
- error_result = {
190
- "query": query,
191
- "search_engines": {
192
- "successful": [],
193
- "failed": _global_search_engines,
194
- "total_requested": len(_global_search_engines)
195
- },
196
- "merged_results": [],
197
- "engine_results": {},
198
- "search_type": "multi_engine",
199
- "stats": {
200
- "total_results": 0,
201
- "successful_engines_count": 0,
202
- "failed_engines_count": len(_global_search_engines)
203
- },
204
- "error": str(e)
205
- }
206
- logger.error(f"多引擎搜索失败: {e}")
207
- return json.dumps(error_result, ensure_ascii=False, indent=2)
208
-
209
-
210
- @tool
211
- async def jina_fetch_webpage(url: str) -> str:
212
- """
213
- 输入网址, 获取网页内容
214
- """
215
- try:
216
- async with httpx.AsyncClient(timeout=30.0) as client:
217
- logger.info(f"Jina 获取页面: URL='{url}'")
218
- resp = await client.get(f"https://r.jina.ai/{url}", headers={"X-Engine": "direct"})
219
- if resp.status_code == 200:
220
- content = resp.text
221
- logger.info(f"网页获取成功,原始长度: {len(content)} 字符")
222
-
223
- # 如果压缩器已初始化,则使用压缩器压缩内容
224
- if _global_compressor is not None:
225
- try:
226
- content = await _global_compressor.compress_webpage(content, url)
227
- logger.info(f"网页内容压缩完成,最终长度: {len(content)} 字符")
228
- except Exception as e:
229
- logger.error(f"网页压缩失败: {e},返回原始内容")
230
-
231
- return content
232
- else:
233
- return f"获取网页失败,状态码: {resp.status_code}"
234
- except Exception as e:
235
- return f"获取网页失败: {str(e)}"
236
-
@@ -1,35 +0,0 @@
1
- import base64
2
- from typing import Optional
3
- from langchain_openai import ChatOpenAI
4
- from langchain_core.messages import HumanMessage, SystemMessage
5
- from loguru import logger
6
-
7
-
8
- async def vision_expert_analysis(vision_llm: ChatOpenAI, image_data: bytes, query: str = "") -> str:
9
- """视觉专家分析工具"""
10
- logger.info("调用视觉专家分析")
11
- try:
12
- img_data = base64.b64encode(image_data).decode()
13
- message_content = [
14
- {"type": "text", "text": f"请分析这张图片内容。用户问题:{query}" if query else "请详细分析这张图片的内容"},
15
- {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{img_data}"}}
16
- ]
17
-
18
- vision_prompt = """你是视觉分析专家,请分析图片内容:
19
-
20
- - 一大段话详尽的描述主要内容,
21
- - 如果出现文字, 请给出所有文字内容
22
-
23
- 输出格式:
24
- 第一张图描述了... 此外...
25
- ...
26
- """
27
-
28
- result = await vision_llm.ainvoke([
29
- SystemMessage(content=vision_prompt),
30
- HumanMessage(content=message_content)
31
- ])
32
- logger.info(f"视觉专家分析完成: {result}")
33
- return str(result.content) if hasattr(result, 'content') else str(result)
34
- except Exception as e:
35
- return f"视觉分析失败: {str(e)}"
@@ -1,112 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: entari_plugin_hyw
3
- Version: 0.3.5
4
- Summary: Use large language models to interpret chat messages
5
- Author-email: kumoSleeping <zjr2992@outlook.com>
6
- License: MIT
7
- Project-URL: Homepage, https://github.com/kumoSleeping/entari-plugin-hyw
8
- Project-URL: Repository, https://github.com/kumoSleeping/entari-plugin-hyw
9
- Project-URL: Issues, https://github.com/kumoSleeping/entari-plugin-hyw/issues
10
- Keywords: entari,llm,ai,bot,chat
11
- Classifier: Development Status :: 3 - Alpha
12
- Classifier: Intended Audience :: Developers
13
- Classifier: License :: OSI Approved :: MIT License
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.8
16
- Classifier: Programming Language :: Python :: 3.9
17
- Classifier: Programming Language :: Python :: 3.10
18
- Classifier: Programming Language :: Python :: 3.11
19
- Classifier: Programming Language :: Python :: 3.12
20
- Requires-Python: >=3.8
21
- Description-Content-Type: text/markdown
22
- Requires-Dist: arclet-entari[full]>=0.16.5
23
- Requires-Dist: langchain-openai
24
- Requires-Dist: httpx
25
- Requires-Dist: bs4>=0.0.2
26
- Requires-Dist: langchain>=1.0.1
27
- Requires-Dist: langgraph>=1.0.0
28
- Requires-Dist: entari-plugin-server>=0.5.0
29
- Requires-Dist: satori-python-adapter-onebot11>=0.2.5
30
- Requires-Dist: nekobox>=0.1.6
31
- Requires-Dist: ddgs>=9.6.1
32
-
33
- # entari-plugin-hyw
34
-
35
-
36
- ![License](https://img.shields.io/badge/License-MIT-green.svg) ![PyPI](https://img.shields.io/badge/PyPI-Available-brightgreen.svg)
37
-
38
- **使用大语言模型在聊天环境解释大家的hyw**
39
-
40
- ### 目前的局限
41
-
42
- > 目前仅支持 satori-python-adapter-onebot11 使用此插件, 更多适配请等一会...
43
-
44
- > 目前没有考虑 video , 小程序 等复杂消息类型的处理
45
-
46
-
47
- ## 🚀 快速开始
48
-
49
- ### 安装
50
-
51
- ```bash
52
- pip install entari-plugin-hyw
53
- ```
54
-
55
- ### 配置
56
-
57
- 在你的 `entari.yml` 配置文件中根据您的情况添加以下配置:
58
-
59
- ```yaml
60
- plugins:
61
- entari_plugin_hyw:
62
- hyw_command_name: ["/hyw", "hyw"]
63
-
64
- # 文本模型配置
65
- text_llm_model_name: "qwen3-max"
66
- text_llm_api_key: "your-api-key"
67
- text_llm_model_base_url: "https://xxx/v1"
68
- text_llm_enable_search: false
69
-
70
- # 视觉模型配置
71
- vision_llm_model_name: "qwen3-vl-plus"
72
- vision_llm_api_key: "your-api-key"
73
- vision_llm_model_base_url: "https://xxx/v1"
74
- vision_llm_enable_search: false
75
- ```
76
-
77
- ## 📖 使用方法
78
-
79
- ```
80
- hyw 什么是人工智能?
81
- hyw [图片]
82
- ```
83
-
84
-
85
- ```
86
- [引用消息[图片, 文字]] hyw
87
- [引用消息[图片, 文字]] [At] hyw 什么是人工智能? [图片]
88
- ```
89
-
90
- > 自动屏蔽 At 元素
91
-
92
- ## ⚙️ 配置参数
93
-
94
- | 参数 | 类型 | 默认值 | 说明 |
95
- |------|------|--------|------|
96
- | `hyw_command_name` | `str \| List[str]` | `"hyw"` | 触发命令名称 |
97
- | `text_llm_model_name` | `str` | - | 文本模型名称 |
98
- | `text_llm_api_key` | `str` | - | 文本模型 API 密钥 |
99
- | `text_llm_model_base_url` | `str` | - | 文本模型 API 地址 |
100
- | `text_llm_temperature` | `float` | `0.4` | 文本模型温度参数 |
101
- | `text_llm_enable_search` | `bool` | `false` | 是否启用搜索功能 |
102
- | `vision_llm_model_name` | `str` | - | 视觉模型名称 |
103
- | `vision_llm_api_key` | `str` | - | 视觉模型 API 密钥 |
104
- | `vision_llm_model_base_url` | `str` | - | 视觉模型 API 地址 |
105
- | `vision_llm_temperature` | `float` | `0.4` | 视觉模型温度参数 |
106
- | `vision_llm_enable_search` | `bool` | `false` | 是否启用视觉搜索 |
107
- | `hyw_prompt` | `str` | 默认提示词 | 自定义系统提示词 |
108
-
109
-
110
-
111
-
112
-
@@ -1,9 +0,0 @@
1
- entari_plugin_hyw/__init__.py,sha256=17FyK84OlwkJTD6mtfC_bQBAY2T-B3g_zhmCo2M7EfU,5040
2
- entari_plugin_hyw/agent.py,sha256=rSQHZmJdUKEHFciSh-JP3mg4hBn5zrRVQsnrcfAKWJU,20984
3
- entari_plugin_hyw/compressor.py,sha256=3TYXXYRFi0iktMDsZUnK2v1gaBCTLDCvX89aWU4RZnU,2252
4
- entari_plugin_hyw/tools.py,sha256=xuhlrhB8DaMjUzrGAEwouATFycbDPPKgugeSlLG17MY,10249
5
- entari_plugin_hyw/vision.py,sha256=oqPECLS4d6doUn9qSHe4d5075qpitDd9tR2IxgM3ISg,1322
6
- entari_plugin_hyw-0.3.5.dist-info/METADATA,sha256=9xy1UfLypvkpWKXwaEWwQK4eu4lYgMUetmf5BqoOhEM,3464
7
- entari_plugin_hyw-0.3.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- entari_plugin_hyw-0.3.5.dist-info/top_level.txt,sha256=TIDsn6XPs6KA5e3ezsE65JoXsy03ejDdrB41I4SPjmo,18
9
- entari_plugin_hyw-0.3.5.dist-info/RECORD,,