feat(wecom): add WeCom channel with SDK pinned to GitHub tag v0.1.2

This commit is contained in:
Re-bin
2026-03-11 07:57:12 +00:00
parent eb6310c438
commit d0b4f0d70d
5 changed files with 22 additions and 18 deletions

View File

@@ -208,7 +208,7 @@ Connect nanobot to your favorite chat platform.
| **Slack** | Bot token + App-Level token | | **Slack** | Bot token + App-Level token |
| **Email** | IMAP/SMTP credentials | | **Email** | IMAP/SMTP credentials |
| **QQ** | App ID + App Secret | | **QQ** | App ID + App Secret |
| **Wecom** | Bot ID + App Secret | | **Wecom** | Bot ID + Bot Secret |
<details> <details>
<summary><b>Telegram</b> (Recommended)</summary> <summary><b>Telegram</b> (Recommended)</summary>
@@ -683,12 +683,17 @@ nanobot gateway
Uses **WebSocket** long connection — no public IP required. Uses **WebSocket** long connection — no public IP required.
**1. Create a wecom bot** **1. Install the optional dependency**
In the client's workspace, click on "Intelligent Robot" to create a robot and choose API mode for creation. ```bash
Select to create in "long connection" mode, and obtain Bot ID and Secret. pip install nanobot-ai[wecom]
```
**2. Configure** **2. Create a WeCom AI Bot**
Go to the WeCom admin console → Intelligent Robot → Create Robot → select **API mode** with **long connection**. Copy the Bot ID and Secret.
**3. Configure**
```json ```json
{ {
@@ -696,23 +701,21 @@ Select to create in "long connection" mode, and obtain Bot ID and Secret.
"wecom": { "wecom": {
"enabled": true, "enabled": true,
"botId": "your_bot_id", "botId": "your_bot_id",
"secret": "your_secret", "secret": "your_bot_secret",
"allowFrom": [ "allowFrom": ["your_id"]
"your_id"
]
} }
} }
} }
``` ```
**3. Run** **4. Run**
```bash ```bash
nanobot gateway nanobot gateway
``` ```
> [!TIP] > [!TIP]
> wecom uses WebSocket to receive messages — no webhook or public IP needed! > WeCom uses WebSocket to receive messages — no webhook or public IP needed!
</details> </details>

View File

@@ -156,7 +156,6 @@ class ChannelManager:
self.channels["wecom"] = WecomChannel( self.channels["wecom"] = WecomChannel(
self.config.channels.wecom, self.config.channels.wecom,
self.bus, self.bus,
groq_api_key=self.config.providers.groq.api_key,
) )
logger.info("WeCom channel enabled") logger.info("WeCom channel enabled")
except ImportError as e: except ImportError as e:

View File

@@ -2,6 +2,7 @@
import asyncio import asyncio
import importlib.util import importlib.util
import os
from collections import OrderedDict from collections import OrderedDict
from typing import Any from typing import Any
@@ -36,10 +37,9 @@ class WecomChannel(BaseChannel):
name = "wecom" name = "wecom"
def __init__(self, config: WecomConfig, bus: MessageBus, groq_api_key: str = ""): def __init__(self, config: WecomConfig, bus: MessageBus):
super().__init__(config, bus) super().__init__(config, bus)
self.config: WecomConfig = config self.config: WecomConfig = config
self.groq_api_key = groq_api_key
self._client: Any = None self._client: Any = None
self._processed_message_ids: OrderedDict[str, None] = OrderedDict() self._processed_message_ids: OrderedDict[str, None] = OrderedDict()
self._loop: asyncio.AbstractEventLoop | None = None self._loop: asyncio.AbstractEventLoop | None = None
@@ -50,7 +50,7 @@ class WecomChannel(BaseChannel):
async def start(self) -> None: async def start(self) -> None:
"""Start the WeCom bot with WebSocket long connection.""" """Start the WeCom bot with WebSocket long connection."""
if not WECOM_AVAILABLE: if not WECOM_AVAILABLE:
logger.error("WeCom SDK not installed. Run: pip install wecom-aibot-sdk-python") logger.error("WeCom SDK not installed. Run: pip install nanobot-ai[wecom]")
return return
if not self.config.bot_id or not self.config.secret: if not self.config.bot_id or not self.config.secret:
@@ -213,7 +213,6 @@ class WecomChannel(BaseChannel):
if file_url and aes_key: if file_url and aes_key:
file_path = await self._download_and_save_media(file_url, aes_key, "image") file_path = await self._download_and_save_media(file_url, aes_key, "image")
if file_path: if file_path:
import os
filename = os.path.basename(file_path) filename = os.path.basename(file_path)
content_parts.append(f"[image: {filename}]\n[Image: source: {file_path}]") content_parts.append(f"[image: {filename}]\n[Image: source: {file_path}]")
else: else:
@@ -308,6 +307,7 @@ class WecomChannel(BaseChannel):
media_dir = get_media_dir("wecom") media_dir = get_media_dir("wecom")
if not filename: if not filename:
filename = fname or f"{media_type}_{hash(file_url) % 100000}" filename = fname or f"{media_type}_{hash(file_url) % 100000}"
filename = os.path.basename(filename)
file_path = media_dir / filename file_path = media_dir / filename
file_path.write_bytes(data) file_path.write_bytes(data)

View File

@@ -208,7 +208,7 @@ class WecomConfig(Base):
secret: str = "" # Bot Secret from WeCom AI Bot platform secret: str = "" # Bot Secret from WeCom AI Bot platform
allow_from: list[str] = Field(default_factory=list) # Allowed user IDs allow_from: list[str] = Field(default_factory=list) # Allowed user IDs
welcome_message: str = "" # Welcome message for enter_chat event welcome_message: str = "" # Welcome message for enter_chat event
react_emoji: str = "eyes" # Emoji for message reactions
class ChannelsConfig(Base): class ChannelsConfig(Base):
"""Configuration for chat channels.""" """Configuration for chat channels."""

View File

@@ -44,11 +44,13 @@ dependencies = [
"json-repair>=0.57.0,<1.0.0", "json-repair>=0.57.0,<1.0.0",
"chardet>=3.0.2,<6.0.0", "chardet>=3.0.2,<6.0.0",
"openai>=2.8.0", "openai>=2.8.0",
"wecom-aibot-sdk-python>=0.1.2",
"tiktoken>=0.12.0,<1.0.0", "tiktoken>=0.12.0,<1.0.0",
] ]
[project.optional-dependencies] [project.optional-dependencies]
wecom = [
"wecom-aibot-sdk-python @ git+https://github.com/chengyongru/wecom_aibot_sdk.git@v0.1.2",
]
matrix = [ matrix = [
"matrix-nio[e2e]>=0.25.2", "matrix-nio[e2e]>=0.25.2",
"mistune>=3.0.0,<4.0.0", "mistune>=3.0.0,<4.0.0",