feat(wecom): add WeCom channel with SDK pinned to GitHub tag v0.1.2
This commit is contained in:
25
README.md
25
README.md
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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."""
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user