entari-plugin-hyw 4.0.0rc4__tar.gz → 4.0.0rc5__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 entari-plugin-hyw might be problematic. Click here for more details.
- {entari_plugin_hyw-4.0.0rc4/src/entari_plugin_hyw.egg-info → entari_plugin_hyw-4.0.0rc5}/PKG-INFO +4 -4
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/pyproject.toml +4 -4
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/__init__.py +174 -73
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/index.html +70 -79
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/browser/__init__.py +10 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/browser/engines/base.py +13 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/browser/engines/bing.py +95 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/browser/engines/searxng.py +137 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/browser/landing.html +172 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/browser/manager.py +153 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/browser/service.py +275 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/card-ui/src/App.vue +756 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/src/components/MarkdownContent.vue +7 -11
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/src/components/StageCard.vue +33 -30
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/src/types.ts +9 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/definitions.py +130 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/history.py +248 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/modular_pipeline.py +351 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/render_vue.py +401 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/search.py +116 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/stage_base.py +88 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/stage_instruct.py +328 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/stage_instruct_review.py +92 -0
- entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw/stage_summary.py +164 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5/src/entari_plugin_hyw.egg-info}/PKG-INFO +4 -4
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw.egg-info/SOURCES.txt +13 -2
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw.egg-info/requires.txt +3 -3
- entari_plugin_hyw-4.0.0rc4/src/entari_plugin_hyw/card-ui/src/App.vue +0 -412
- entari_plugin_hyw-4.0.0rc4/src/entari_plugin_hyw/history.py +0 -170
- entari_plugin_hyw-4.0.0rc4/src/entari_plugin_hyw/pipeline.py +0 -1219
- entari_plugin_hyw-4.0.0rc4/src/entari_plugin_hyw/prompts.py +0 -47
- entari_plugin_hyw-4.0.0rc4/src/entari_plugin_hyw/render_vue.py +0 -314
- entari_plugin_hyw-4.0.0rc4/src/entari_plugin_hyw/search.py +0 -735
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/MANIFEST.in +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/README.md +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/setup.cfg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/anthropic.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/cerebras.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/deepseek.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/gemini.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/google.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/grok.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/huggingface.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/microsoft.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/minimax.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/mistral.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/nvida.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/openai.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/openrouter.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/perplexity.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/qwen.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/xai.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/xiaomi.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/logos/zai.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/card-dist/vite.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/anthropic.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/cerebras.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/deepseek.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/gemini.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/google.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/grok.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/huggingface.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/microsoft.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/minimax.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/mistral.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/nvida.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/openai.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/openrouter.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/perplexity.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/qwen.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/xai.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/xiaomi.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/assets/icon/zai.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/.gitignore +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/README.md +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/index.html +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/package-lock.json +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/package.json +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/anthropic.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/cerebras.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/deepseek.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/gemini.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/google.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/grok.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/huggingface.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/microsoft.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/minimax.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/mistral.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/nvida.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/openai.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/openrouter.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/perplexity.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/qwen.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/xai.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/xiaomi.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/logos/zai.png +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/public/vite.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/src/assets/vue.svg +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/src/components/HelloWorld.vue +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/src/components/SectionCard.vue +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/src/main.ts +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/src/style.css +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/src/test_regex.js +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/tsconfig.app.json +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/tsconfig.json +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/tsconfig.node.json +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/card-ui/vite.config.ts +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/image_cache.py +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw/misc.py +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw.egg-info/dependency_links.txt +0 -0
- {entari_plugin_hyw-4.0.0rc4 → entari_plugin_hyw-4.0.0rc5}/src/entari_plugin_hyw.egg-info/top_level.txt +0 -0
{entari_plugin_hyw-4.0.0rc4/src/entari_plugin_hyw.egg-info → entari_plugin_hyw-4.0.0rc5}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: entari_plugin_hyw
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.0rc5
|
|
4
4
|
Summary: Use large language models to interpret chat messages
|
|
5
5
|
Author-email: kumoSleeping <zjr2992@outlook.com>
|
|
6
6
|
License: MIT
|
|
@@ -20,9 +20,9 @@ Requires-Dist: arclet-entari[full]>=0.16.5
|
|
|
20
20
|
Requires-Dist: openai
|
|
21
21
|
Requires-Dist: httpx
|
|
22
22
|
Requires-Dist: markdown>=3.10
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist:
|
|
23
|
+
Requires-Dist: DrissionPage>=4.1.1.2
|
|
24
|
+
Requires-Dist: trafilatura>=1.6.0
|
|
25
|
+
Requires-Dist: json-repair>=0.55.0
|
|
26
26
|
Provides-Extra: dev
|
|
27
27
|
Requires-Dist: entari-plugin-server>=0.5.0; extra == "dev"
|
|
28
28
|
Requires-Dist: satori-python-adapter-onebot11>=0.2.5; extra == "dev"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "entari_plugin_hyw"
|
|
7
|
-
version = "4.0.0-
|
|
7
|
+
version = "4.0.0-rc5"
|
|
8
8
|
description = "Use large language models to interpret chat messages"
|
|
9
9
|
authors = [{name = "kumoSleeping", email = "zjr2992@outlook.com"}]
|
|
10
10
|
dependencies = [
|
|
@@ -12,9 +12,9 @@ dependencies = [
|
|
|
12
12
|
"openai",
|
|
13
13
|
"httpx",
|
|
14
14
|
"markdown>=3.10",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
15
|
+
"DrissionPage>=4.1.1.2",
|
|
16
|
+
"trafilatura>=1.6.0",
|
|
17
|
+
"json-repair>=0.55.0",
|
|
18
18
|
]
|
|
19
19
|
requires-python = ">=3.10,<3.13"
|
|
20
20
|
readme = "README.md"
|
|
@@ -19,9 +19,9 @@ from loguru import logger
|
|
|
19
19
|
import arclet.letoderea as leto
|
|
20
20
|
from arclet.entari.event.command import CommandReceive
|
|
21
21
|
|
|
22
|
-
from .
|
|
22
|
+
from .modular_pipeline import ModularPipeline
|
|
23
23
|
from .history import HistoryManager
|
|
24
|
-
from .render_vue import ContentRenderer
|
|
24
|
+
from .render_vue import ContentRenderer, get_content_renderer
|
|
25
25
|
from .misc import process_onebot_json, process_images, resolve_model_name, render_refuse_answer, REFUSE_ANSWER_MARKDOWN
|
|
26
26
|
from arclet.entari.event.lifespan import Cleanup
|
|
27
27
|
|
|
@@ -83,86 +83,129 @@ class _RecentEventDeduper:
|
|
|
83
83
|
|
|
84
84
|
_event_deduper = _RecentEventDeduper()
|
|
85
85
|
|
|
86
|
+
@dataclass
|
|
87
|
+
class ModelConfig:
|
|
88
|
+
"""Model configuration for a specific stage."""
|
|
89
|
+
model_name: Optional[str] = None
|
|
90
|
+
api_key: Optional[str] = None
|
|
91
|
+
base_url: Optional[str] = None
|
|
92
|
+
extra_body: Optional[Dict[str, Any]] = None
|
|
93
|
+
model_provider: Optional[str] = None
|
|
94
|
+
input_price: Optional[float] = None
|
|
95
|
+
output_price: Optional[float] = None
|
|
96
|
+
|
|
97
|
+
|
|
86
98
|
@dataclass
|
|
87
99
|
class HywConfig(BasicConfModel):
|
|
100
|
+
# Core Settings
|
|
88
101
|
admins: List[str] = field(default_factory=list)
|
|
89
102
|
models: List[Dict[str, Any]] = field(default_factory=list)
|
|
90
103
|
question_command: str = "/q"
|
|
104
|
+
language: str = "Simplified Chinese"
|
|
105
|
+
temperature: float = 0.4
|
|
106
|
+
|
|
107
|
+
# Root-level defaults (backward compatible)
|
|
91
108
|
model_name: Optional[str] = None
|
|
92
109
|
api_key: Optional[str] = None
|
|
93
110
|
base_url: str = "https://openrouter.ai/api/v1"
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
111
|
+
extra_body: Optional[Dict[str, Any]] = None
|
|
112
|
+
model_provider: Optional[str] = None
|
|
113
|
+
input_price: Optional[float] = None
|
|
114
|
+
output_price: Optional[float] = None
|
|
115
|
+
|
|
116
|
+
# Nested Stage Configs
|
|
117
|
+
instruct: Optional[ModelConfig] = None
|
|
118
|
+
qa: Optional[ModelConfig] = None
|
|
119
|
+
main: Optional[ModelConfig] = None # Summary stage
|
|
120
|
+
|
|
121
|
+
# Search/Fetch Settings
|
|
122
|
+
search_engine: str = "bing"
|
|
123
|
+
enable_domain_blocking: bool = True
|
|
124
|
+
page_content_mode: str = "text"
|
|
125
|
+
|
|
126
|
+
# Rendering Settings
|
|
103
127
|
headless: bool = False
|
|
104
|
-
save_conversation: bool = False
|
|
105
|
-
icon: str = "openai"
|
|
106
128
|
render_timeout_ms: int = 6000
|
|
107
129
|
render_image_timeout_ms: int = 3000
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
enable_browser_fallback: bool = False
|
|
130
|
+
|
|
131
|
+
# Bot Behavior
|
|
132
|
+
save_conversation: bool = False
|
|
112
133
|
reaction: bool = False
|
|
113
134
|
quote: bool = True
|
|
114
|
-
temperature: float = 0.4
|
|
115
|
-
# Billing configuration (price per million tokens)
|
|
116
|
-
input_price: Optional[float] = None # $ per 1M input tokens
|
|
117
|
-
output_price: Optional[float] = None # $ per 1M output tokens
|
|
118
|
-
# Vision model pricing overrides (defaults to main model pricing if not set)
|
|
119
|
-
vision_input_price: Optional[float] = None
|
|
120
|
-
vision_output_price: Optional[float] = None
|
|
121
|
-
# Instruct model pricing overrides (defaults to main model pricing if not set)
|
|
122
|
-
instruct_input_price: Optional[float] = None
|
|
123
|
-
instruct_output_price: Optional[float] = None
|
|
124
|
-
# Provider Names
|
|
125
|
-
search_name: str = "DuckDuckGo"
|
|
126
|
-
search_provider: str = "crawl4ai" # crawl4ai | httpx | ddgs
|
|
127
|
-
fetch_provider: str = "crawl4ai" # crawl4ai | jinaai
|
|
128
|
-
jina_api_key: Optional[str] = None # Optional API key for Jina AI
|
|
129
|
-
model_provider: Optional[str] = None
|
|
130
|
-
vision_model_provider: Optional[str] = None
|
|
131
|
-
instruct_model_provider: Optional[str] = None
|
|
132
135
|
|
|
133
|
-
# Search/Fetch Settings
|
|
134
|
-
search_timeout: float = 10.0
|
|
135
|
-
search_retries: int = 2
|
|
136
|
-
fetch_timeout: float = 15.0
|
|
137
|
-
fetch_max_results: int = 5
|
|
138
|
-
fetch_blocked_domains: Optional[List[str]] = None
|
|
139
|
-
|
|
140
|
-
# Fetch Model Config
|
|
141
|
-
fetch_model_name: Optional[str] = None
|
|
142
|
-
fetch_api_key: Optional[str] = None
|
|
143
|
-
fetch_base_url: Optional[str] = None
|
|
144
|
-
fetch_extra_body: Optional[Dict[str, Any]] = None
|
|
145
|
-
fetch_input_price: Optional[float] = None
|
|
146
|
-
fetch_output_price: Optional[float] = None
|
|
147
|
-
# Summary Model Config
|
|
148
|
-
summary_model_name: Optional[str] = None
|
|
149
|
-
summary_api_key: Optional[str] = None
|
|
150
|
-
summary_base_url: Optional[str] = None
|
|
151
|
-
summary_extra_body: Optional[Dict[str, Any]] = None
|
|
152
|
-
summary_input_price: Optional[float] = None
|
|
153
|
-
summary_output_price: Optional[float] = None
|
|
154
136
|
# UI Theme
|
|
155
|
-
theme_color: str = "#ef4444"
|
|
137
|
+
theme_color: str = "#ef4444"
|
|
156
138
|
|
|
157
139
|
def __post_init__(self):
|
|
158
140
|
"""Parse and normalize theme color after initialization."""
|
|
159
141
|
self.theme_color = parse_color(self.theme_color)
|
|
160
|
-
|
|
142
|
+
# Convert dicts to ModelConfig if needed
|
|
143
|
+
if isinstance(self.instruct, dict):
|
|
144
|
+
self.instruct = ModelConfig(**self.instruct)
|
|
145
|
+
if isinstance(self.qa, dict):
|
|
146
|
+
self.qa = ModelConfig(**self.qa)
|
|
147
|
+
if isinstance(self.main, dict):
|
|
148
|
+
self.main = ModelConfig(**self.main)
|
|
149
|
+
|
|
150
|
+
def get_model_config(self, stage: str) -> Dict[str, Any]:
|
|
151
|
+
"""
|
|
152
|
+
Get resolved model config for a stage.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
stage: "instruct", "qa", or "main" (summary)
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
Dict with model_name, api_key, base_url, extra_body, etc.
|
|
159
|
+
"""
|
|
160
|
+
# Determine primary and secondary config sources
|
|
161
|
+
primary = None
|
|
162
|
+
secondary = None
|
|
163
|
+
|
|
164
|
+
if stage == "instruct":
|
|
165
|
+
primary = self.instruct
|
|
166
|
+
secondary = self.main # Fallback to main
|
|
167
|
+
elif stage == "qa":
|
|
168
|
+
# QA fallback to main as well if ever used
|
|
169
|
+
primary = self.qa
|
|
170
|
+
secondary = self.main
|
|
171
|
+
elif stage == "main":
|
|
172
|
+
primary = self.main
|
|
173
|
+
|
|
174
|
+
# Build result with fallback logic
|
|
175
|
+
def resolve(field_name: str, is_essential: bool = True):
|
|
176
|
+
"""Resolve a field with fallback: Primary -> Secondary -> Root."""
|
|
177
|
+
# 1. Try Primary
|
|
178
|
+
val = getattr(primary, field_name, None) if primary else None
|
|
179
|
+
|
|
180
|
+
# 2. Try Secondary (if value missing)
|
|
181
|
+
if val is None and secondary:
|
|
182
|
+
val = getattr(secondary, field_name, None)
|
|
183
|
+
|
|
184
|
+
# 3. Try Root (if value still missing)
|
|
185
|
+
if val is None:
|
|
186
|
+
val = getattr(self, field_name, None)
|
|
187
|
+
return val
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
"model_name": resolve("model_name"),
|
|
191
|
+
"api_key": resolve("api_key"),
|
|
192
|
+
"base_url": resolve("base_url"),
|
|
193
|
+
"extra_body": resolve("extra_body", is_essential=False),
|
|
194
|
+
"model_provider": resolve("model_provider", is_essential=False),
|
|
195
|
+
"input_price": resolve("input_price", is_essential=False),
|
|
196
|
+
"output_price": resolve("output_price", is_essential=False),
|
|
197
|
+
}
|
|
161
198
|
|
|
162
199
|
|
|
163
200
|
conf = plugin_config(HywConfig)
|
|
164
201
|
history_manager = HistoryManager()
|
|
165
|
-
renderer = ContentRenderer()
|
|
202
|
+
renderer = ContentRenderer(headless=conf.headless)
|
|
203
|
+
from .render_vue import set_global_renderer
|
|
204
|
+
set_global_renderer(renderer)
|
|
205
|
+
|
|
206
|
+
# Pre-start Crawl4AI browser for fast fetching/screenshots
|
|
207
|
+
from .browser.service import prestart_browser, close_screenshot_service
|
|
208
|
+
# prestart_browser(headless=conf.headless) # Removed to avoid RuntimeError: no running event loop
|
|
166
209
|
|
|
167
210
|
|
|
168
211
|
class GlobalCache:
|
|
@@ -170,6 +213,18 @@ class GlobalCache:
|
|
|
170
213
|
|
|
171
214
|
global_cache = GlobalCache()
|
|
172
215
|
|
|
216
|
+
|
|
217
|
+
@listen(Cleanup)
|
|
218
|
+
async def cleanup_screenshot_service():
|
|
219
|
+
"""Cleanup shared browser on shutdown."""
|
|
220
|
+
try:
|
|
221
|
+
await close_screenshot_service()
|
|
222
|
+
# Also close the shared browser manager
|
|
223
|
+
from .browser.manager import close_shared_browser
|
|
224
|
+
await close_shared_browser()
|
|
225
|
+
except Exception as e:
|
|
226
|
+
logger.warning(f"Failed to cleanup browser services: {e}")
|
|
227
|
+
|
|
173
228
|
async def react(session: Session, emoji: str):
|
|
174
229
|
if not conf.reaction: return
|
|
175
230
|
try:
|
|
@@ -185,9 +240,7 @@ async def process_request(
|
|
|
185
240
|
conversation_key_override: Optional[str] = None,
|
|
186
241
|
local_mode: bool = False,
|
|
187
242
|
) -> None:
|
|
188
|
-
logger.info(f"Processing request: {all_param}")
|
|
189
243
|
mc = MessageChain(all_param)
|
|
190
|
-
logger.info(f"reply: {session.reply}")
|
|
191
244
|
if session.reply:
|
|
192
245
|
try:
|
|
193
246
|
# Check if reply is from self (the bot)
|
|
@@ -197,12 +250,10 @@ async def process_request(
|
|
|
197
250
|
|
|
198
251
|
if reply_msg_id and history_manager.is_bot_message(reply_msg_id):
|
|
199
252
|
is_bot = True
|
|
200
|
-
logger.info(f"Reply target {reply_msg_id} identified as bot message via history")
|
|
201
253
|
|
|
202
254
|
if is_bot:
|
|
203
|
-
|
|
255
|
+
pass # Reply is from bot - ignoring
|
|
204
256
|
else:
|
|
205
|
-
logger.info(f"Reply is from user (or unknown) - including content")
|
|
206
257
|
mc.extend(MessageChain(" ") + session.reply.origin.message)
|
|
207
258
|
except Exception as e:
|
|
208
259
|
logger.warning(f"Failed to process reply origin: {e}")
|
|
@@ -211,7 +262,7 @@ async def process_request(
|
|
|
211
262
|
# Filter and reconstruct MessageChain
|
|
212
263
|
filtered_elements = mc.get(Text) + mc.get(Image) + mc.get(Custom)
|
|
213
264
|
mc = MessageChain(filtered_elements)
|
|
214
|
-
|
|
265
|
+
|
|
215
266
|
|
|
216
267
|
text_content = str(mc.get(Text)).strip()
|
|
217
268
|
# Remove HTML image tags from text content to prevent "unreasonable code behavior"
|
|
@@ -263,10 +314,15 @@ async def process_request(
|
|
|
263
314
|
logger.warning(f"Vision model resolution warning for {vision_model}: {err_v}")
|
|
264
315
|
|
|
265
316
|
images, err = await process_images(mc, vision_model)
|
|
317
|
+
|
|
318
|
+
# Start preparing render tab (async)
|
|
319
|
+
renderer = await get_content_renderer()
|
|
320
|
+
render_tab_task = asyncio.create_task(renderer.prepare_tab())
|
|
321
|
+
tab_id = None
|
|
266
322
|
|
|
267
323
|
# Call Pipeline directly
|
|
268
324
|
safe_input = msg_text
|
|
269
|
-
pipeline =
|
|
325
|
+
pipeline = ModularPipeline(conf)
|
|
270
326
|
try:
|
|
271
327
|
resp = await pipeline.execute(
|
|
272
328
|
safe_input,
|
|
@@ -294,6 +350,13 @@ async def process_request(
|
|
|
294
350
|
content = final_resp.get("llm_response", "")
|
|
295
351
|
structured = final_resp.get("structured_response", {})
|
|
296
352
|
|
|
353
|
+
# Wait for tab preparation if needed (should be ready by now)
|
|
354
|
+
try:
|
|
355
|
+
tab_id = await render_tab_task
|
|
356
|
+
except Exception as e:
|
|
357
|
+
logger.warning(f"Failed to prepare render tab: {e}")
|
|
358
|
+
tab_id = None
|
|
359
|
+
|
|
297
360
|
# Render
|
|
298
361
|
import tempfile
|
|
299
362
|
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tf:
|
|
@@ -319,23 +382,24 @@ async def process_request(
|
|
|
319
382
|
output_path=output_path,
|
|
320
383
|
reason=final_resp.get('refuse_reason', 'Instruct 专家分配此任务流程失败,请尝试提出其他问题~'),
|
|
321
384
|
theme_color=conf.theme_color,
|
|
385
|
+
tab_id=tab_id,
|
|
322
386
|
)
|
|
323
387
|
else:
|
|
324
388
|
render_ok = await renderer.render(
|
|
325
389
|
markdown_content=content,
|
|
326
390
|
output_path=output_path,
|
|
391
|
+
tab_id=tab_id,
|
|
327
392
|
stats=stats_to_render,
|
|
328
393
|
references=structured.get("references", []),
|
|
329
394
|
page_references=structured.get("page_references", []),
|
|
330
395
|
image_references=structured.get("image_references", []),
|
|
331
396
|
stages_used=final_resp.get("stages_used", []),
|
|
332
|
-
image_timeout=conf.render_image_timeout_ms,
|
|
333
397
|
theme_color=conf.theme_color,
|
|
334
398
|
)
|
|
335
399
|
|
|
336
400
|
# Send & Save
|
|
337
401
|
if not render_ok:
|
|
338
|
-
logger.error("Render failed; skipping reply.
|
|
402
|
+
logger.error("Render failed; skipping reply.")
|
|
339
403
|
if os.path.exists(output_path):
|
|
340
404
|
try:
|
|
341
405
|
os.remove(output_path)
|
|
@@ -375,6 +439,24 @@ async def process_request(
|
|
|
375
439
|
code=display_session_id,
|
|
376
440
|
)
|
|
377
441
|
|
|
442
|
+
if conf.save_conversation and sent_id:
|
|
443
|
+
try:
|
|
444
|
+
# Pass web_results to save fetched pages as markdown, and output image
|
|
445
|
+
history_manager.save_to_disk(
|
|
446
|
+
sent_id,
|
|
447
|
+
web_results=final_resp.get("web_results"),
|
|
448
|
+
image_path=output_path if 'output_path' in locals() else None
|
|
449
|
+
)
|
|
450
|
+
except Exception as e:
|
|
451
|
+
logger.warning(f"Failed to save conversation: {e}")
|
|
452
|
+
|
|
453
|
+
# Cleanup temp image
|
|
454
|
+
if 'output_path' in locals() and output_path and os.path.exists(output_path):
|
|
455
|
+
try:
|
|
456
|
+
os.remove(output_path)
|
|
457
|
+
except Exception:
|
|
458
|
+
pass
|
|
459
|
+
|
|
378
460
|
|
|
379
461
|
|
|
380
462
|
|
|
@@ -391,9 +473,29 @@ async def process_request(
|
|
|
391
473
|
try:
|
|
392
474
|
# Use a temporary ID for error cases
|
|
393
475
|
error_id = f"error_{int(time.time())}_{secrets.token_hex(4)}"
|
|
394
|
-
|
|
395
|
-
#
|
|
396
|
-
|
|
476
|
+
|
|
477
|
+
# Try to salvage history
|
|
478
|
+
partial_hist = []
|
|
479
|
+
if 'resp' in locals() and resp:
|
|
480
|
+
partial_hist = resp.get("conversation_history", [])
|
|
481
|
+
elif 'context' in locals() and context and hasattr(context, 'instruct_history'):
|
|
482
|
+
partial_hist = context.instruct_history
|
|
483
|
+
|
|
484
|
+
related_ids = []
|
|
485
|
+
if 'session' in locals():
|
|
486
|
+
msg_id = str(session.event.message.id) if hasattr(session.event, 'message') else str(session.event.id)
|
|
487
|
+
related_ids = [msg_id]
|
|
488
|
+
|
|
489
|
+
history_manager.remember(error_id, partial_hist, related_ids, {"model": "error", "error": str(e)}, context_id, code=display_session_id if 'display_session_id' in locals() else None)
|
|
490
|
+
|
|
491
|
+
# Save debug data on error
|
|
492
|
+
web_res = context.web_results if 'context' in locals() and context else []
|
|
493
|
+
|
|
494
|
+
history_manager.save_to_disk(
|
|
495
|
+
error_id,
|
|
496
|
+
web_results=web_res
|
|
497
|
+
)
|
|
498
|
+
|
|
397
499
|
except Exception as save_err:
|
|
398
500
|
logger.error(f"Failed to save error conversation: {save_err}")
|
|
399
501
|
|
|
@@ -419,9 +521,8 @@ async def handle_question_command(session: Session[MessageCreatedEvent], result:
|
|
|
419
521
|
logger.info(f"Question Command Triggered. Message: {session.event.message}")
|
|
420
522
|
|
|
421
523
|
args = result.all_matched_args
|
|
422
|
-
logger.info(f"Matched Args: {args}")
|
|
423
524
|
|
|
424
|
-
await process_request(session, args.get("all_param"), selected_model=None, selected_vision_model=None, conversation_key_override=None
|
|
525
|
+
await process_request(session, args.get("all_param"), selected_model=None, selected_vision_model=None, conversation_key_override=None)
|
|
425
526
|
|
|
426
527
|
metadata("hyw", author=[{"name": "kumoSleeping", "email": "zjr2992@outlook.com"}], version=__version__, config=HywConfig)
|
|
427
528
|
|