entari-plugin-hyw 3.4.2__tar.gz → 3.5.0rc2__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-3.4.2/src/entari_plugin_hyw.egg-info → entari_plugin_hyw-3.5.0rc2}/PKG-INFO +5 -2
- {entari_plugin_hyw-3.4.2 → entari_plugin_hyw-3.5.0rc2}/README.md +4 -1
- {entari_plugin_hyw-3.4.2 → entari_plugin_hyw-3.5.0rc2}/pyproject.toml +1 -1
- {entari_plugin_hyw-3.4.2 → entari_plugin_hyw-3.5.0rc2}/src/entari_plugin_hyw/__init__.py +78 -158
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/index.html +396 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/vite.svg +1 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/anthropic.svg +1 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/cerebras.svg +9 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/deepseek.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/gemini.svg +1 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/google.svg +1 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/grok.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/huggingface.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/microsoft.svg +15 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/minimax.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/mistral.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/nvida.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/openai.svg +1 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/openrouter.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/perplexity.svg +24 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/qwen.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/xai.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/xiaomi.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/icon/zai.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/.gitignore +24 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/README.md +5 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/index.html +16 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/package-lock.json +2342 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/package.json +31 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/anthropic.svg +1 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/cerebras.svg +9 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/deepseek.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/gemini.svg +1 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/google.svg +1 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/grok.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/huggingface.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/microsoft.svg +15 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/minimax.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/mistral.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/nvida.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/openai.svg +1 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/openrouter.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/perplexity.svg +24 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/qwen.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/xai.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/xiaomi.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/logos/zai.png +0 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/public/vite.svg +1 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/src/App.vue +410 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/src/assets/vue.svg +1 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/src/components/HelloWorld.vue +41 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/src/components/MarkdownContent.vue +385 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/src/components/SectionCard.vue +41 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/src/components/StageCard.vue +183 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/src/main.ts +5 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/src/style.css +8 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/src/test_regex.js +103 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/src/types.ts +52 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/tsconfig.app.json +16 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/tsconfig.json +7 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/tsconfig.node.json +26 -0
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/card-ui/vite.config.ts +16 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/core → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw}/history.py +25 -1
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/image_cache.py +283 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/utils → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw}/misc.py +0 -3
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/core → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw}/pipeline.py +236 -86
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/utils/prompts_cn.py → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/prompts.py +10 -25
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/render_vue.py +314 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/utils → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw}/search.py +227 -10
- {entari_plugin_hyw-3.4.2 → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw.egg-info}/PKG-INFO +5 -2
- entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw.egg-info/SOURCES.txt +92 -0
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/libs/highlight.css +0 -10
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/libs/highlight.js +0 -1213
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/libs/katex-auto-render.js +0 -1
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/libs/katex.css +0 -1
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/libs/katex.js +0 -1
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/libs/tailwind.css +0 -1
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/package-lock.json +0 -953
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/package.json +0 -16
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/tailwind.config.js +0 -12
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/tailwind.input.css +0 -235
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/template.html +0 -157
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/template.html.bak +0 -157
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/template.j2 +0 -400
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/core/__init__.py +0 -0
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/core/config.py +0 -38
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/core/hyw.py +0 -48
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/core/render.py +0 -630
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/utils/__init__.py +0 -2
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/utils/browser.py +0 -40
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/utils/playwright_tool.py +0 -36
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/utils/prompts.py +0 -119
- entari_plugin_hyw-3.4.2/src/entari_plugin_hyw.egg-info/SOURCES.txt +0 -53
- {entari_plugin_hyw-3.4.2 → entari_plugin_hyw-3.5.0rc2}/MANIFEST.in +0 -0
- {entari_plugin_hyw-3.4.2 → entari_plugin_hyw-3.5.0rc2}/setup.cfg +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/anthropic.svg +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/cerebras.svg +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/deepseek.png +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/gemini.svg +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/google.svg +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/grok.png +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/huggingface.png +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/microsoft.svg +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/minimax.png +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/mistral.png +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/nvida.png +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/openai.svg +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/openrouter.png +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/perplexity.svg +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/qwen.png +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/xai.png +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/xiaomi.png +0 -0
- {entari_plugin_hyw-3.4.2/src/entari_plugin_hyw/assets/icon → entari_plugin_hyw-3.5.0rc2/src/entari_plugin_hyw/assets/card-dist/logos}/zai.png +0 -0
- {entari_plugin_hyw-3.4.2 → entari_plugin_hyw-3.5.0rc2}/src/entari_plugin_hyw.egg-info/dependency_links.txt +0 -0
- {entari_plugin_hyw-3.4.2 → entari_plugin_hyw-3.5.0rc2}/src/entari_plugin_hyw.egg-info/requires.txt +0 -0
- {entari_plugin_hyw-3.4.2 → entari_plugin_hyw-3.5.0rc2}/src/entari_plugin_hyw.egg-info/top_level.txt +0 -0
{entari_plugin_hyw-3.4.2/src/entari_plugin_hyw.egg-info → entari_plugin_hyw-3.5.0rc2}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: entari_plugin_hyw
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.5.0rc2
|
|
4
4
|
Summary: Use large language models to interpret chat messages
|
|
5
5
|
Author-email: kumoSleeping <zjr2992@outlook.com>
|
|
6
6
|
License: MIT
|
|
@@ -75,8 +75,11 @@ Configure the plugin in your `entari.yml`.
|
|
|
75
75
|
```yaml
|
|
76
76
|
plugins:
|
|
77
77
|
entari_plugin_hyw:
|
|
78
|
-
model_name: google/gemini-
|
|
78
|
+
model_name: google/gemini-2.0-flash-exp
|
|
79
79
|
api_key: "your-or-api-key-here"
|
|
80
|
+
# Rendering Configuration
|
|
81
|
+
render_timeout_ms: 6000 # Browser wait timeout
|
|
82
|
+
render_image_timeout_ms: 3000 # Image load wait timeout
|
|
80
83
|
```
|
|
81
84
|
|
|
82
85
|
## Usage
|
|
@@ -46,8 +46,11 @@ Configure the plugin in your `entari.yml`.
|
|
|
46
46
|
```yaml
|
|
47
47
|
plugins:
|
|
48
48
|
entari_plugin_hyw:
|
|
49
|
-
model_name: google/gemini-
|
|
49
|
+
model_name: google/gemini-2.0-flash-exp
|
|
50
50
|
api_key: "your-or-api-key-here"
|
|
51
|
+
# Rendering Configuration
|
|
52
|
+
render_timeout_ms: 6000 # Browser wait timeout
|
|
53
|
+
render_image_timeout_ms: 3000 # Image load wait timeout
|
|
51
54
|
```
|
|
52
55
|
|
|
53
56
|
## Usage
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "entari_plugin_hyw"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.5.0-rc2"
|
|
8
8
|
description = "Use large language models to interpret chat messages"
|
|
9
9
|
authors = [{name = "kumoSleeping", email = "zjr2992@outlook.com"}]
|
|
10
10
|
dependencies = [
|
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
|
+
from importlib.metadata import version as get_version
|
|
2
3
|
from typing import List, Dict, Any, Optional, Union
|
|
3
4
|
import time
|
|
5
|
+
import asyncio
|
|
6
|
+
|
|
7
|
+
# 从 pyproject.toml 读取版本号,避免重复维护
|
|
8
|
+
try:
|
|
9
|
+
__version__ = get_version("entari_plugin_hyw")
|
|
10
|
+
except Exception:
|
|
11
|
+
__version__ = "0.0.0"
|
|
4
12
|
|
|
5
13
|
from arclet.alconna import Alconna, Args, AllParam, CommandMeta, Option, Arparma, MultiVar, store_true
|
|
6
14
|
from arclet.entari import metadata, listen, Session, plugin_config, BasicConfModel, plugin, command
|
|
15
|
+
from arclet.letoderea import on
|
|
7
16
|
from arclet.entari import MessageChain, Text, Image, MessageCreatedEvent, Quote, At
|
|
8
17
|
from satori.element import Custom
|
|
9
18
|
from loguru import logger
|
|
10
19
|
import arclet.letoderea as leto
|
|
11
20
|
from arclet.entari.event.command import CommandReceive
|
|
12
21
|
|
|
13
|
-
from .
|
|
14
|
-
from .
|
|
15
|
-
from .
|
|
16
|
-
from .
|
|
22
|
+
from .pipeline import ProcessingPipeline
|
|
23
|
+
from .history import HistoryManager
|
|
24
|
+
from .render_vue import ContentRenderer
|
|
25
|
+
from .misc import process_onebot_json, process_images, resolve_model_name
|
|
17
26
|
from arclet.entari.event.lifespan import Cleanup
|
|
18
27
|
|
|
19
28
|
import os
|
|
@@ -22,6 +31,32 @@ import base64
|
|
|
22
31
|
|
|
23
32
|
import re
|
|
24
33
|
|
|
34
|
+
|
|
35
|
+
def parse_color(color: str) -> str:
|
|
36
|
+
"""
|
|
37
|
+
Parse color from hex or RGB tuple to hex format.
|
|
38
|
+
Supports: #ff0000, ff0000, (255, 0, 0), 255,0,0
|
|
39
|
+
"""
|
|
40
|
+
if not color:
|
|
41
|
+
return "#ef4444"
|
|
42
|
+
|
|
43
|
+
color = str(color).strip()
|
|
44
|
+
|
|
45
|
+
# Hex format: #fff or #ffffff or ffffff
|
|
46
|
+
if color.startswith('#') and len(color) in [4, 7]:
|
|
47
|
+
return color
|
|
48
|
+
if re.match(r'^[0-9a-fA-F]{6}$', color):
|
|
49
|
+
return f'#{color}'
|
|
50
|
+
|
|
51
|
+
# RGB tuple: (r, g, b) or r,g,b
|
|
52
|
+
rgb_match = re.match(r'^\(?(\d+)[,\s]+(\d+)[,\s]+(\d+)\)?$', color)
|
|
53
|
+
if rgb_match:
|
|
54
|
+
r, g, b = (max(0, min(255, int(x))) for x in rgb_match.groups())
|
|
55
|
+
return f'#{r:02x}{g:02x}{b:02x}'
|
|
56
|
+
|
|
57
|
+
logger.warning(f"Invalid color '{color}', using default #ef4444")
|
|
58
|
+
return "#ef4444"
|
|
59
|
+
|
|
25
60
|
class _RecentEventDeduper:
|
|
26
61
|
def __init__(self, ttl_seconds: float = 30.0, max_size: int = 2048):
|
|
27
62
|
self.ttl_seconds = ttl_seconds
|
|
@@ -69,6 +104,7 @@ class HywConfig(BasicConfModel):
|
|
|
69
104
|
save_conversation: bool = False
|
|
70
105
|
icon: str = "openai"
|
|
71
106
|
render_timeout_ms: int = 6000
|
|
107
|
+
render_image_timeout_ms: int = 3000
|
|
72
108
|
extra_body: Optional[Dict[str, Any]] = None
|
|
73
109
|
vision_extra_body: Optional[Dict[str, Any]] = None
|
|
74
110
|
instruct_extra_body: Optional[Dict[str, Any]] = None
|
|
@@ -88,81 +124,45 @@ class HywConfig(BasicConfModel):
|
|
|
88
124
|
# Provider Names
|
|
89
125
|
search_name: str = "DuckDuckGo"
|
|
90
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
|
|
91
129
|
model_provider: Optional[str] = None
|
|
92
130
|
vision_model_provider: Optional[str] = None
|
|
93
131
|
instruct_model_provider: Optional[str] = None
|
|
132
|
+
# UI Theme
|
|
133
|
+
theme_color: str = "#ef4444" # Tailwind red-500, supports hex/RGB/color names
|
|
134
|
+
|
|
135
|
+
def __post_init__(self):
|
|
136
|
+
"""Parse and normalize theme color after initialization."""
|
|
137
|
+
self.theme_color = parse_color(self.theme_color)
|
|
94
138
|
|
|
95
139
|
|
|
96
140
|
|
|
97
141
|
conf = plugin_config(HywConfig)
|
|
98
142
|
history_manager = HistoryManager()
|
|
99
143
|
renderer = ContentRenderer()
|
|
100
|
-
hyw = HYW(config=conf)
|
|
101
|
-
|
|
102
|
-
|
|
103
144
|
|
|
104
145
|
|
|
105
|
-
@listen(Cleanup, once=True)
|
|
106
|
-
async def _hyw_cleanup():
|
|
107
|
-
try:
|
|
108
|
-
await hyw.close()
|
|
109
|
-
except Exception as e:
|
|
110
|
-
logger.warning(f"HYW cleanup error: {e}")
|
|
111
|
-
|
|
112
146
|
class GlobalCache:
|
|
113
147
|
models_image_path: Optional[str] = None
|
|
114
148
|
|
|
115
149
|
global_cache = GlobalCache()
|
|
116
150
|
|
|
117
|
-
from satori.exception import ActionFailed
|
|
118
|
-
from satori.adapters.onebot11.reverse import _Connection
|
|
119
|
-
|
|
120
|
-
# Monkeypatch to suppress ActionFailed for get_msg
|
|
121
|
-
original_call_api = _Connection.call_api
|
|
122
|
-
|
|
123
|
-
async def patched_call_api(self, action: str, params: dict = None):
|
|
124
|
-
try:
|
|
125
|
-
return await original_call_api(self, action, params)
|
|
126
|
-
except ActionFailed as e:
|
|
127
|
-
if action == "get_msg":
|
|
128
|
-
logger.warning(f"Suppressed ActionFailed for get_msg: {e}")
|
|
129
|
-
return None
|
|
130
|
-
raise e
|
|
131
|
-
|
|
132
|
-
_Connection.call_api = patched_call_api
|
|
133
|
-
|
|
134
|
-
EMOJI_TO_CODE = {
|
|
135
|
-
"✨": "10024",
|
|
136
|
-
"✅": "10004",
|
|
137
|
-
"❌": "10060"
|
|
138
|
-
}
|
|
139
|
-
|
|
140
151
|
async def react(session: Session, emoji: str):
|
|
141
152
|
if not conf.reaction: return
|
|
142
153
|
try:
|
|
143
|
-
|
|
144
|
-
code = EMOJI_TO_CODE.get(emoji, "10024")
|
|
145
|
-
# OneBot specific reaction
|
|
146
|
-
await session.account.protocol.call_api(
|
|
147
|
-
"internal/set_group_reaction",
|
|
148
|
-
{
|
|
149
|
-
"group_id": str(session.guild.id),
|
|
150
|
-
"message_id": str(session.event.message.id),
|
|
151
|
-
"code": code,
|
|
152
|
-
"is_add": True
|
|
153
|
-
}
|
|
154
|
-
)
|
|
155
|
-
else:
|
|
156
|
-
# Standard Satori reaction
|
|
157
|
-
await session.reaction_create(emoji=emoji)
|
|
158
|
-
except ActionFailed:
|
|
159
|
-
pass
|
|
154
|
+
await session.reaction_create(emoji=emoji)
|
|
160
155
|
except Exception as e:
|
|
161
156
|
logger.warning(f"Reaction failed: {e}")
|
|
162
157
|
|
|
163
|
-
async def process_request(
|
|
164
|
-
|
|
165
|
-
|
|
158
|
+
async def process_request(
|
|
159
|
+
session: Session[MessageCreatedEvent],
|
|
160
|
+
all_param: Optional[MessageChain] = None,
|
|
161
|
+
selected_model: Optional[str] = None,
|
|
162
|
+
selected_vision_model: Optional[str] = None,
|
|
163
|
+
conversation_key_override: Optional[str] = None,
|
|
164
|
+
local_mode: bool = False,
|
|
165
|
+
) -> None:
|
|
166
166
|
logger.info(f"Processing request: {all_param}")
|
|
167
167
|
mc = MessageChain(all_param)
|
|
168
168
|
logger.info(f"reply: {session.reply}")
|
|
@@ -242,12 +242,19 @@ async def process_request(session: Session[MessageCreatedEvent], all_param: Opti
|
|
|
242
242
|
|
|
243
243
|
images, err = await process_images(mc, vision_model)
|
|
244
244
|
|
|
245
|
-
# Call
|
|
246
|
-
# Sanitize user_input: use extracted text only
|
|
245
|
+
# Call Pipeline directly
|
|
247
246
|
safe_input = msg_text
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
247
|
+
pipeline = ProcessingPipeline(conf)
|
|
248
|
+
try:
|
|
249
|
+
resp = await pipeline.execute(
|
|
250
|
+
safe_input,
|
|
251
|
+
hist_payload,
|
|
252
|
+
model_name=model,
|
|
253
|
+
images=images,
|
|
254
|
+
selected_vision_model=vision_model,
|
|
255
|
+
)
|
|
256
|
+
finally:
|
|
257
|
+
await pipeline.close()
|
|
251
258
|
|
|
252
259
|
# Step 1 Results
|
|
253
260
|
step1_vision_model = resp.get("vision_model_used")
|
|
@@ -270,111 +277,28 @@ async def process_request(session: Session[MessageCreatedEvent], all_param: Opti
|
|
|
270
277
|
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tf:
|
|
271
278
|
output_path = tf.name
|
|
272
279
|
model_used = final_resp.get("model_used")
|
|
273
|
-
vision_model_used = final_resp.get("vision_model_used")
|
|
274
|
-
|
|
275
|
-
# Helper to infer icon from model name
|
|
276
|
-
def infer_icon_from_model(model_name: str) -> str:
|
|
277
|
-
"""Infer icon name from model name (e.g. 'google/gemini-3-flash' -> 'google' or 'gemini')"""
|
|
278
|
-
if not model_name:
|
|
279
|
-
return conf.icon
|
|
280
|
-
name_lower = model_name.lower()
|
|
281
|
-
# Check for known providers/models in the name
|
|
282
|
-
known_icons = ["google", "gemini", "openai", "anthropic", "deepseek", "mistral",
|
|
283
|
-
"qwen", "grok", "xai", "perplexity", "microsoft", "minimax", "nvidia"]
|
|
284
|
-
for icon_name in known_icons:
|
|
285
|
-
if icon_name in name_lower:
|
|
286
|
-
return icon_name
|
|
287
|
-
return conf.icon
|
|
288
|
-
|
|
289
|
-
icon = conf.icon
|
|
290
|
-
m_conf = None
|
|
291
|
-
if model_used:
|
|
292
|
-
m_conf = next((m for m in conf.models if m.get("name") == model_used), None)
|
|
293
|
-
if m_conf:
|
|
294
|
-
icon = m_conf.get("icon", infer_icon_from_model(model_used))
|
|
295
|
-
else:
|
|
296
|
-
# Model not in config list, infer from name
|
|
297
|
-
icon = infer_icon_from_model(model_used)
|
|
298
280
|
|
|
299
281
|
# Determine session short code
|
|
300
282
|
if hist_key:
|
|
301
283
|
display_session_id = history_manager.get_code_by_key(hist_key)
|
|
302
284
|
if not display_session_id:
|
|
303
|
-
# Should not happen if key exists, but fallback
|
|
304
285
|
display_session_id = history_manager.generate_short_code()
|
|
305
286
|
else:
|
|
306
|
-
# New conversation, pre-generate code
|
|
307
287
|
display_session_id = history_manager.generate_short_code()
|
|
308
288
|
|
|
309
|
-
# Determine vision base url and icon
|
|
310
|
-
vision_base_url = None
|
|
311
|
-
vision_icon = None
|
|
312
|
-
|
|
313
|
-
if vision_model_used:
|
|
314
|
-
v_conf = next((m for m in conf.models if m.get("name") == vision_model_used), None)
|
|
315
|
-
if v_conf:
|
|
316
|
-
vision_base_url = v_conf.get("base_url")
|
|
317
|
-
vision_icon = v_conf.get("icon", infer_icon_from_model(vision_model_used))
|
|
318
|
-
else:
|
|
319
|
-
vision_icon = infer_icon_from_model(vision_model_used)
|
|
320
|
-
|
|
321
|
-
# Handle Vision Only Mode (suppress text model display)
|
|
322
|
-
render_model_name = model_used or conf.model_name or "unknown"
|
|
323
|
-
render_icon = icon
|
|
324
|
-
render_base_url = m_conf.get("base_url", conf.base_url) if m_conf else conf.base_url
|
|
325
|
-
|
|
326
|
-
if not model_used and vision_model_used:
|
|
327
|
-
render_model_name = ""
|
|
328
|
-
render_icon = ""
|
|
329
|
-
|
|
330
289
|
# Use stats_list if available, otherwise standard stats
|
|
331
290
|
stats_to_render = final_resp.get("stats_list", final_resp.get("stats", {}))
|
|
332
|
-
|
|
333
|
-
# Determine Behavior Summary & Provider Name
|
|
334
|
-
|
|
335
|
-
# 1. Behavior Summary
|
|
336
|
-
behavior_summary = "Text Generation"
|
|
337
|
-
if vision_model_used:
|
|
338
|
-
behavior_summary = "Visual Analysis"
|
|
339
|
-
elif any(s.get("name") == "Search" for s in final_resp.get("stages_used", []) or []):
|
|
340
|
-
behavior_summary = "Search-Augmented"
|
|
341
|
-
|
|
342
|
-
# 2. Provider Name
|
|
343
|
-
# Try to get from m_conf (resolved above)
|
|
344
|
-
provider_name = "Unknown Provider"
|
|
345
|
-
if model_used and m_conf:
|
|
346
|
-
provider_name = m_conf.get("provider", "Unknown Provider")
|
|
347
|
-
elif not model_used and vision_model_used:
|
|
348
|
-
# If only vision model used (unlikely but possible in code logic)
|
|
349
|
-
if 'v_conf' in locals() and v_conf:
|
|
350
|
-
provider_name = v_conf.get("provider", "Unknown Provider")
|
|
351
|
-
|
|
352
|
-
# If still unknown and we have base_url, maybe use domain as last resort fallback?
|
|
353
|
-
# User said: "provider does not automatically get from url if not filled"
|
|
354
|
-
# So if it's "Unknown Provider", we leave it or maybe empty string?
|
|
355
|
-
# Let's stick to "Unknown Provider" or just empty if we want to be clean.
|
|
356
|
-
# But for UI validation it's better to show something if missing config.
|
|
357
291
|
|
|
358
292
|
render_ok = await renderer.render(
|
|
359
293
|
markdown_content=content,
|
|
360
294
|
output_path=output_path,
|
|
361
|
-
suggestions=[],
|
|
362
295
|
stats=stats_to_render,
|
|
363
296
|
references=structured.get("references", []),
|
|
364
297
|
page_references=structured.get("page_references", []),
|
|
365
298
|
image_references=structured.get("image_references", []),
|
|
366
|
-
flow_steps=structured.get("flow_steps", []),
|
|
367
299
|
stages_used=final_resp.get("stages_used", []),
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
behavior_summary=behavior_summary,
|
|
371
|
-
icon_config=render_icon,
|
|
372
|
-
vision_model_name=vision_model_used,
|
|
373
|
-
vision_base_url=vision_base_url,
|
|
374
|
-
vision_icon_config=vision_icon,
|
|
375
|
-
base_url=render_base_url,
|
|
376
|
-
billing_info=final_resp.get("billing_info"),
|
|
377
|
-
render_timeout_ms=conf.render_timeout_ms
|
|
300
|
+
image_timeout=conf.render_image_timeout_ms,
|
|
301
|
+
theme_color=conf.theme_color,
|
|
378
302
|
)
|
|
379
303
|
|
|
380
304
|
# Send & Save
|
|
@@ -443,18 +367,16 @@ async def process_request(session: Session[MessageCreatedEvent], all_param: Opti
|
|
|
443
367
|
logger.error(f"Failed to save error conversation: {save_err}")
|
|
444
368
|
|
|
445
369
|
|
|
446
|
-
|
|
447
|
-
# Main Command (Question)
|
|
448
370
|
alc = Alconna(
|
|
449
371
|
conf.question_command,
|
|
450
372
|
Args["all_param;?", AllParam],
|
|
451
373
|
)
|
|
452
374
|
|
|
453
|
-
@command.on(alc)
|
|
375
|
+
@command.on(alc)
|
|
454
376
|
async def handle_question_command(session: Session[MessageCreatedEvent], result: Arparma):
|
|
455
377
|
"""Handle main Question command"""
|
|
456
378
|
try:
|
|
457
|
-
|
|
379
|
+
logger.info(f"Question Command Triggered. Message: {result}")
|
|
458
380
|
mid = str(session.event.message.id) if getattr(session.event, "message", None) else str(session.event.id)
|
|
459
381
|
dedupe_key = f"{getattr(session.account, 'id', 'account')}:{mid}"
|
|
460
382
|
if _event_deduper.seen_recently(dedupe_key):
|
|
@@ -468,14 +390,12 @@ async def handle_question_command(session: Session[MessageCreatedEvent], result:
|
|
|
468
390
|
args = result.all_matched_args
|
|
469
391
|
logger.info(f"Matched Args: {args}")
|
|
470
392
|
|
|
471
|
-
# Only all_param is supported now
|
|
472
|
-
# Context ID for history lookup is automatically handled in process_request
|
|
473
|
-
|
|
474
393
|
await process_request(session, args.get("all_param"), selected_model=None, selected_vision_model=None, conversation_key_override=None, local_mode=False)
|
|
475
394
|
|
|
476
|
-
metadata("hyw", author=[{"name": "kumoSleeping", "email": "zjr2992@outlook.com"}], version=
|
|
395
|
+
metadata("hyw", author=[{"name": "kumoSleeping", "email": "zjr2992@outlook.com"}], version=__version__, config=HywConfig)
|
|
396
|
+
|
|
477
397
|
|
|
478
|
-
@
|
|
398
|
+
@listen(CommandReceive)
|
|
479
399
|
async def remove_at(content: MessageChain):
|
|
480
|
-
|
|
481
|
-
return content
|
|
400
|
+
logger.info(f"remove_at: {content}")
|
|
401
|
+
return content.lstrip(At)
|