ForcePilot/backend/package/yuxi/channels/adapters/wechat/heartbeat_adapter.py
Kris a1d9ba9683 refactor(wechat): 整理代码风格与导入顺序,新增多项微信适配功能
本次提交包含多项优化与新增功能:
1. 清理多个文件中多余的空行与导入顺序
2. 修复voice.py中的多行字符串格式化问题
3. 新增微信公众号被动回复构建函数与配置项
4. 新增企业微信markdown消息发送支持
5. 新增消息去重TTL与最大条目配置
6. 新增markdown文本截断工具函数
7. 新增微信授权与OAuth相关工具方法
8. 重构消息去重逻辑,使用DedupPolicy替代本地字典实现
9. 新增子账号多租户支持功能
10. 新增消息动作处理适配器,支持send/reply等操作
11. 修复token持久化逻辑,新增状态存储支持
2026-05-13 16:16:52 +08:00

68 lines
2.1 KiB
Python

from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from yuxi.channels.models import DeliveryResult
from .adapter import WeChatAdapter
class WeChatHeartbeatAdapter:
def __init__(self, config: dict[str, Any]):
self._typing_enabled = config.get("typing_indicator", False)
self._heartbeat_interval = config.get("heartbeat_interval", 300.0)
@property
def typing_enabled(self) -> bool:
return self._typing_enabled
async def send_typing_indicator(self, send_fn, chat_id: str, active: bool = True) -> None:
if not self._typing_enabled or not active:
return
try:
await send_fn(chat_id, "...")
except Exception:
pass
async def send_typing_via_response(
self,
send_fn,
chat_id: str,
active: bool = True,
) -> DeliveryResult | None:
if not self._typing_enabled or not active:
return None
try:
from yuxi.channels.models import (
ChannelIdentity,
ChannelResponse,
ChannelType,
)
identity = ChannelIdentity(
channel_id="wechat",
channel_type=ChannelType.WECHAT,
channel_user_id="",
channel_chat_id=chat_id,
)
response = ChannelResponse(identity=identity, content="...")
return await send_fn(response)
except Exception:
return None
async def heartbeat_check(self, adapter: WeChatAdapter) -> dict[str, Any]:
import time
start = time.monotonic()
try:
health = await adapter.health_check()
latency = (time.monotonic() - start) * 1000
return {"alive": health.status == "healthy", "latencyMs": latency}
except Exception as e:
return {"alive": False, "lastError": str(e)}
@staticmethod
def should_preserve_thread_id_for_group_heartbeat(config: dict[str, Any]) -> bool:
return config.get("preserve_heartbeat_thread_id_for_group", False)