mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-21 16:05:19 +08:00
feat(dingtalk): support group subscriptions and card interaction events
This commit is contained in:
@@ -7,6 +7,8 @@ import typing
|
||||
import dingtalk_stream
|
||||
import pydantic
|
||||
|
||||
from .subscriptions import DingTalkSubscriptionHandler
|
||||
|
||||
from langbot.libs.dingtalk_api.api import DingTalkClient, is_stream_card_configured
|
||||
from langbot.libs.dingtalk_api.dingtalkevent import DingTalkEvent
|
||||
import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter
|
||||
@@ -40,6 +42,7 @@ class DingTalkCardCallbackHandler(dingtalk_stream.CallbackHandler):
|
||||
{
|
||||
'conversation_type': 'CardCallback',
|
||||
'Type': 'card_callback',
|
||||
'timestamp': float(message.headers.time or 0) / 1000,
|
||||
'CardCallback': {
|
||||
'extension': callback.extension,
|
||||
'corp_id': callback.corp_id,
|
||||
@@ -107,6 +110,10 @@ class DingTalkAdapter(DingTalkAPIMixin, abstract_platform_adapter.AbstractPlatfo
|
||||
return [
|
||||
'message.received',
|
||||
'feedback.received',
|
||||
'group.member_joined',
|
||||
'group.member_left',
|
||||
'group.info_updated',
|
||||
'dingtalk.card_action',
|
||||
'platform.specific',
|
||||
]
|
||||
|
||||
@@ -280,6 +287,7 @@ class DingTalkAdapter(DingTalkAPIMixin, abstract_platform_adapter.AbstractPlatfo
|
||||
async def on_message(event: DingTalkEvent):
|
||||
await self._handle_native_event(event)
|
||||
|
||||
self.bot.client.register_all_event_handler(DingTalkSubscriptionHandler(self))
|
||||
self.bot.on_message('FriendMessage')(on_message)
|
||||
self.bot.on_message('GroupMessage')(on_message)
|
||||
self.bot.client.register_callback_handler(
|
||||
@@ -298,7 +306,9 @@ class DingTalkAdapter(DingTalkAPIMixin, abstract_platform_adapter.AbstractPlatfo
|
||||
'DingTalk event received: '
|
||||
f'conversation={event.conversation}, message_id={getattr(event.incoming_message, "message_id", None)}'
|
||||
)
|
||||
if platform_events.FriendMessage in self.listeners or platform_events.GroupMessage in self.listeners:
|
||||
if event.conversation in {'FriendMessage', 'GroupMessage'} and (
|
||||
platform_events.FriendMessage in self.listeners or platform_events.GroupMessage in self.listeners
|
||||
):
|
||||
legacy_event = await self.event_converter.target2legacy(event, self.bot_account_id)
|
||||
if legacy_event:
|
||||
callback = self.listeners.get(type(legacy_event))
|
||||
|
||||
@@ -23,7 +23,18 @@ class DingTalkEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
||||
feedback = DingTalkEventConverter.card_callback_to_feedback(event)
|
||||
if feedback is not None:
|
||||
return feedback
|
||||
return DingTalkEventConverter.platform_specific(event, 'card.callback')
|
||||
callback = event.get('CardCallback') or {}
|
||||
content = callback.get('content') or {}
|
||||
return platform_events.DingTalkCardActionEvent(
|
||||
adapter_name=ADAPTER_NAME,
|
||||
user=platform_entities.User(id=str(callback.get('user_id') or '')),
|
||||
space_id=str(callback.get('space_id') or ''),
|
||||
card_instance_id=str(callback.get('card_instance_id') or ''),
|
||||
action=str(content.get('action') or content.get('actionKey') or ''),
|
||||
data=callback,
|
||||
timestamp=float(event.get('timestamp') or 0),
|
||||
source_platform_object=event,
|
||||
)
|
||||
return DingTalkEventConverter.platform_specific(event, f'message.{event.conversation or "unknown"}')
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -151,6 +151,10 @@ spec:
|
||||
supported_events:
|
||||
- message.received
|
||||
- feedback.received
|
||||
- group.member_joined
|
||||
- group.member_left
|
||||
- group.info_updated
|
||||
- dingtalk.card_action
|
||||
- platform.specific
|
||||
|
||||
supported_apis:
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
"""Translate DingTalk Stream EVENT envelopes, keeping unknown payloads intact."""
|
||||
|
||||
import asyncio
|
||||
from collections import OrderedDict
|
||||
|
||||
import dingtalk_stream
|
||||
from langbot_plugin.api.entities.builtin.platform import entities, events
|
||||
|
||||
from .types import ADAPTER_NAME
|
||||
|
||||
|
||||
def subscription_events(message):
|
||||
data = message.data
|
||||
headers = message.headers
|
||||
action = headers.event_type or data.get('EventType') or data.get('eventType') or ''
|
||||
raw = {'headers': vars(headers).copy(), 'data': data}
|
||||
stamp = headers.event_born_time or data.get('TimeStamp') or data.get('EventTime') or data.get('timestamp') or headers.time or 0
|
||||
stamp = float(stamp)
|
||||
common = dict(
|
||||
adapter_name=ADAPTER_NAME,
|
||||
timestamp=stamp / 1000 if stamp > 10_000_000_000 else stamp,
|
||||
source_platform_object=raw,
|
||||
)
|
||||
group_id = data.get('OpenConversationId') or data.get('openConversationId') or data.get('chatId') or data.get('ChatId')
|
||||
group = entities.UserGroup(id=str(group_id or ''), name=str(data.get('Title') or data.get('title') or ''))
|
||||
owner_id = data.get('Owner') or data.get('owner')
|
||||
if owner_id:
|
||||
group.owner_id = str(owner_id)
|
||||
operator_id = data.get('Operator') or data.get('operator')
|
||||
operator = entities.User(id=str(operator_id)) if operator_id else None
|
||||
members = data.get('UserId') or data.get('userId') or []
|
||||
if isinstance(members, str):
|
||||
members = [members]
|
||||
if group_id and members and action in {'chat_add_member', 'chat_remove_member', 'chat_quit'}:
|
||||
for member_id in dict.fromkeys(members):
|
||||
member = entities.User(id=str(member_id))
|
||||
if action == 'chat_add_member':
|
||||
yield events.MemberJoinedEvent(group=group, member=member, inviter=operator, **common)
|
||||
else:
|
||||
yield events.MemberLeftEvent(
|
||||
group=group, member=member, operator=operator,
|
||||
is_kicked=action == 'chat_remove_member', **common,
|
||||
)
|
||||
elif group_id and action in {'chat_update_title', 'chat_update_owner'}:
|
||||
yield events.GroupInfoUpdatedEvent(
|
||||
group=group, operator=operator,
|
||||
changed_fields=['name' if action == 'chat_update_title' else 'owner_id'], **common,
|
||||
)
|
||||
else:
|
||||
yield events.PlatformSpecificEvent(action=action or 'unknown', data=raw, **common)
|
||||
|
||||
|
||||
class DingTalkSubscriptionHandler(dingtalk_stream.EventHandler):
|
||||
def __init__(self, adapter):
|
||||
super().__init__()
|
||||
self.adapter = adapter
|
||||
self.completed = OrderedDict()
|
||||
self.lock = asyncio.Lock()
|
||||
|
||||
async def process(self, message):
|
||||
# Serialize retries; mark each fan-out event only after successful dispatch.
|
||||
async with self.lock:
|
||||
try:
|
||||
identity = message.headers.event_id or message.headers.message_id
|
||||
for index, event in enumerate(subscription_events(message)):
|
||||
key = (message.headers.event_corp_id, identity, index)
|
||||
if identity and key in self.completed:
|
||||
continue
|
||||
await self.adapter._dispatch_eba_event(event)
|
||||
if identity:
|
||||
self.completed[key] = None
|
||||
while len(self.completed) > 4096:
|
||||
self.completed.popitem(last=False)
|
||||
return dingtalk_stream.AckMessage.STATUS_OK, 'OK'
|
||||
except Exception:
|
||||
self.logger.exception('DingTalk subscription dispatch failed')
|
||||
return 500, 'Event dispatch failed'
|
||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
import json
|
||||
import pathlib
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock, patch
|
||||
from unittest.mock import AsyncMock, Mock, patch
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
@@ -38,7 +38,7 @@ class DummyLogger(AbstractEventLogger):
|
||||
class DummyDingTalkClient(DingTalkClient):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._message_handlers = {}
|
||||
self.client = SimpleNamespace(register_callback_handler=AsyncMock())
|
||||
self.client = SimpleNamespace(register_callback_handler=Mock(), register_all_event_handler=Mock())
|
||||
self.markdown_card = kwargs.get('markdown_card', True)
|
||||
self.access_token = ''
|
||||
self.send_message = AsyncMock()
|
||||
@@ -287,8 +287,8 @@ async def test_dingtalk_event_converter_maps_card_feedback():
|
||||
assert feedback.session_id == 'space-1'
|
||||
assert feedback.message_id == 'bot-msg-1'
|
||||
|
||||
assert isinstance(callback, platform_events.PlatformSpecificEvent)
|
||||
assert callback.action == 'card.callback'
|
||||
assert isinstance(callback, platform_events.DingTalkCardActionEvent)
|
||||
assert callback.action == 'open_details'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -522,3 +522,40 @@ async def test_dingtalk_adapter_dispatches_native_input_submission():
|
||||
assert calls[0].data['callback_token'] == 'callback-token'
|
||||
assert calls[0].data['values'] == {'score': 42.5}
|
||||
assert result['message_id'] not in adapter.interaction_callback_contexts
|
||||
|
||||
|
||||
def test_dingtalk_subscription_member_and_group_mapping():
|
||||
from dingtalk_stream.frames import EventMessage
|
||||
from langbot.pkg.platform.adapters.dingtalk.subscriptions import subscription_events
|
||||
|
||||
message = EventMessage()
|
||||
message.headers.event_type = 'chat_add_member'
|
||||
message.data = {'OpenConversationId': 'group', 'UserId': ['a', 'b']}
|
||||
converted = list(subscription_events(message))
|
||||
assert [event.member.id for event in converted] == ['a', 'b']
|
||||
assert all(event.type == 'group.member_joined' for event in converted)
|
||||
message.headers.event_type = 'chat_update_owner'
|
||||
message.data = {'OpenConversationId': 'group', 'Owner': 'new-owner'}
|
||||
event = list(subscription_events(message))[0]
|
||||
assert event.changed_fields == ['owner_id']
|
||||
assert event.group.owner_id == 'new-owner'
|
||||
message.headers.event_type = 'chat_add_member'
|
||||
message.data = {'chatId': 'group', 'unionId': ['union-id']}
|
||||
assert list(subscription_events(message))[0].type == 'platform.specific'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dingtalk_subscription_retry_does_not_repeat_successful_members():
|
||||
from dingtalk_stream.frames import EventMessage
|
||||
from langbot.pkg.platform.adapters.dingtalk.subscriptions import DingTalkSubscriptionHandler
|
||||
|
||||
message = EventMessage()
|
||||
message.headers.event_id = 'event-1'
|
||||
message.headers.event_type = 'chat_add_member'
|
||||
message.data = {'OpenConversationId': 'group', 'UserId': ['a', 'b']}
|
||||
adapter = SimpleNamespace(_dispatch_eba_event=AsyncMock(side_effect=[None, RuntimeError('retry'), None]))
|
||||
handler = DingTalkSubscriptionHandler(adapter)
|
||||
assert (await handler.process(message))[0] == 500
|
||||
assert (await handler.process(message))[0] == 200
|
||||
assert (await handler.process(message))[0] == 200
|
||||
assert [call.args[0].member.id for call in adapter._dispatch_eba_event.await_args_list] == ['a', 'b', 'b']
|
||||
|
||||
@@ -90,6 +90,10 @@ const DEBUG_EVENT_DEFINITIONS: Record<string, DebugEventDefinition> = {
|
||||
messageField: 'text',
|
||||
},
|
||||
'message.deleted': deletion,
|
||||
'dingtalk.card_action': {
|
||||
fields: [user],
|
||||
defaults: { space_id: 'dtv1.card//IM_GROUP.debug-group', card_instance_id: 'debug-card', action: 'confirm', data: {} },
|
||||
},
|
||||
'wecombot.enter_chat': {
|
||||
fields: [user],
|
||||
defaults: { chat_id: 'debug-user', chat_type: 'private', message_id: 'debug-entry', data: {} },
|
||||
|
||||
@@ -331,7 +331,14 @@ function eventLabel(event: string, t: TFunction) {
|
||||
|
||||
function eventDescription(event: string, t: TFunction) {
|
||||
if (event === '*') return t('bots.eventDescriptions.all');
|
||||
if (event.endsWith('.*')) return t('bots.eventDescriptions.namespace');
|
||||
if (event.endsWith('.*')) {
|
||||
const group = event.slice(0, -2);
|
||||
const key = `bots.eventDescriptions.namespace_${group}`;
|
||||
const description = t(key);
|
||||
return description === key
|
||||
? t('bots.eventDescriptions.namespace', { group })
|
||||
: description;
|
||||
}
|
||||
const key = `bots.eventDescriptions.${event.replace(/\./g, '_')}`;
|
||||
const description = t(key);
|
||||
return description === key ? t('bots.eventDescriptions.custom') : description;
|
||||
|
||||
@@ -1005,6 +1005,7 @@ const enUS = {
|
||||
eventNames: {
|
||||
wecombot_enter_chat: "User entered bot chat",
|
||||
wecombot_template_card_event: "Template card interaction",
|
||||
dingtalk_card_action: "DingTalk card interaction",
|
||||
wecomcs_enter_session: "Customer entered conversation",
|
||||
wecomcs_msg_send_fail: "Customer service message failed",
|
||||
wecomcs_servicer_status_change: "Representative availability changed",
|
||||
@@ -1019,6 +1020,7 @@ const enUS = {
|
||||
friend_added: 'Friend added',
|
||||
group_member_joined: 'Member joined group',
|
||||
group_member_left: 'Member left group',
|
||||
group_info_updated: "Group information updated",
|
||||
group_member_banned: 'Member banned',
|
||||
bot_invited_to_group: 'Bot invited to group',
|
||||
bot_removed_from_group: 'Bot removed from group',
|
||||
@@ -1029,6 +1031,7 @@ const enUS = {
|
||||
eventDescriptions: {
|
||||
wecombot_enter_chat: "A user opened the bot chat. Use this event for welcome workflows.",
|
||||
wecombot_template_card_event: "A user clicked or submitted a template card. Managed form callbacks are handled separately.",
|
||||
dingtalk_card_action: "Card clicks and submissions; feedback and managed forms are handled separately.",
|
||||
wecomcs_enter_session: "A customer opened a service link; includes entry source and welcome code.",
|
||||
wecomcs_msg_send_fail: "WeChat reported an outgoing message failure, with message ID and failure type.",
|
||||
wecomcs_servicer_status_change: "A representative started, stopped or suspended service.",
|
||||
@@ -1040,8 +1043,7 @@ const enUS = {
|
||||
'Matches bot invitations, removals, mutes, and other status events.',
|
||||
namespace_feedback: 'Matches feedback events from a platform or user.',
|
||||
namespace_friend: 'Matches friend requests and friendship changes.',
|
||||
namespace_group:
|
||||
'Matches member joins, leaves, removals, and other group events.',
|
||||
namespace_group: "Matches group events such as membership changes and group information updates.",
|
||||
namespace_message:
|
||||
'Matches received, edited, deleted, and reaction message events.',
|
||||
namespace_platform:
|
||||
@@ -1057,6 +1059,7 @@ const enUS = {
|
||||
friend_added: 'A friend relationship was created.',
|
||||
group_member_joined: 'A member joins a group where the bot is present.',
|
||||
group_member_left: 'A member leaves a group where the bot is present.',
|
||||
group_info_updated: "Group details such as its name or owner have changed.",
|
||||
group_member_banned: 'A group member is banned or removed.',
|
||||
bot_invited_to_group: 'The bot is invited to a group.',
|
||||
bot_removed_from_group: 'The bot is removed from a group.',
|
||||
|
||||
@@ -1024,6 +1024,7 @@ const esES = {
|
||||
eventNames: {
|
||||
wecombot_enter_chat: "Usuario entró al chat del bot",
|
||||
wecombot_template_card_event: "Interacción con tarjeta",
|
||||
dingtalk_card_action: "Interacción con tarjeta de DingTalk",
|
||||
wecomcs_enter_session: "Cliente entró en la conversación",
|
||||
wecomcs_msg_send_fail: "Fallo de envío de atención al cliente",
|
||||
wecomcs_servicer_status_change: "Disponibilidad del agente modificada",
|
||||
@@ -1038,6 +1039,7 @@ const esES = {
|
||||
friend_added: 'Amigo añadido',
|
||||
group_member_joined: 'Miembro unido al grupo',
|
||||
group_member_left: 'Miembro salió del grupo',
|
||||
group_info_updated: "Información del grupo actualizada",
|
||||
group_member_banned: 'Miembro bloqueado',
|
||||
bot_invited_to_group: 'Bot invitado al grupo',
|
||||
bot_removed_from_group: 'Bot eliminado del grupo',
|
||||
@@ -1048,6 +1050,7 @@ const esES = {
|
||||
eventDescriptions: {
|
||||
wecombot_enter_chat: "Un usuario abrió el chat del bot. Úsalo para flujos de bienvenida.",
|
||||
wecombot_template_card_event: "Un usuario pulsó o envió una tarjeta. Las respuestas de formularios gestionados se procesan por separado.",
|
||||
dingtalk_card_action: "Clics y envíos de tarjetas; las valoraciones y los formularios gestionados se procesan por separado.",
|
||||
wecomcs_enter_session: "Un cliente abrió el enlace de atención; incluye origen y código de bienvenida.",
|
||||
wecomcs_msg_send_fail: "WeChat notificó un fallo de envío con el ID y el tipo de error.",
|
||||
wecomcs_servicer_status_change: "Un agente inició, detuvo o suspendió la atención.",
|
||||
@@ -1060,8 +1063,7 @@ const esES = {
|
||||
namespace_feedback:
|
||||
'Coincide con comentarios recibidos de la plataforma o de usuarios.',
|
||||
namespace_friend: 'Coincide con solicitudes y cambios de amistad.',
|
||||
namespace_group:
|
||||
'Coincide con entradas, salidas, expulsiones y otros eventos de grupo.',
|
||||
namespace_group: "Coincide con cambios de miembros y actualizaciones de información del grupo.",
|
||||
namespace_message:
|
||||
'Coincide con mensajes recibidos, editados, eliminados y reacciones.',
|
||||
namespace_platform:
|
||||
@@ -1078,6 +1080,7 @@ const esES = {
|
||||
friend_added: 'Se ha creado una relación de amistad.',
|
||||
group_member_joined: 'Un miembro se une a un grupo donde está el bot.',
|
||||
group_member_left: 'Un miembro abandona un grupo donde está el bot.',
|
||||
group_info_updated: "Han cambiado datos del grupo, como su nombre o propietario.",
|
||||
group_member_banned: 'Un miembro del grupo es bloqueado o expulsado.',
|
||||
bot_invited_to_group: 'El bot es invitado a un grupo.',
|
||||
bot_removed_from_group: 'El bot es expulsado de un grupo.',
|
||||
|
||||
@@ -1010,6 +1010,7 @@ const jaJP = {
|
||||
eventNames: {
|
||||
wecombot_enter_chat: "ボットとのチャットに参加",
|
||||
wecombot_template_card_event: "テンプレートカード操作",
|
||||
dingtalk_card_action: "DingTalk カード操作",
|
||||
wecomcs_enter_session: "顧客が会話に参加",
|
||||
wecomcs_msg_send_fail: "カスタマーサービスの送信失敗",
|
||||
wecomcs_servicer_status_change: "担当者の受付状態変更",
|
||||
@@ -1024,6 +1025,7 @@ const jaJP = {
|
||||
friend_added: '友達追加',
|
||||
group_member_joined: 'メンバー参加',
|
||||
group_member_left: 'メンバー退出',
|
||||
group_info_updated: "グループ情報更新",
|
||||
group_member_banned: 'メンバーBAN',
|
||||
bot_invited_to_group: 'ボットがグループに招待された',
|
||||
bot_removed_from_group: 'ボットがグループから削除された',
|
||||
@@ -1034,6 +1036,7 @@ const jaJP = {
|
||||
eventDescriptions: {
|
||||
wecombot_enter_chat: "ユーザーがボットのチャットを開きました。歓迎や案内のフローに使用できます。",
|
||||
wecombot_template_card_event: "ユーザーがカードをクリックまたは送信しました。管理対象フォームの応答は別途処理します。",
|
||||
dingtalk_card_action: "カードのクリックや送信。フィードバックと管理対象フォームは別途処理します。",
|
||||
wecomcs_enter_session: "顧客がリンクから会話を開きました。流入元と歓迎メッセージ用コードを含みます。",
|
||||
wecomcs_msg_send_fail: "WeChat が送信失敗を通知しました。メッセージ ID と失敗種別を含みます。",
|
||||
wecomcs_servicer_status_change: "担当者が受付を開始、停止、または一時停止しました。",
|
||||
@@ -1046,8 +1049,7 @@ const jaJP = {
|
||||
namespace_feedback:
|
||||
'プラットフォームまたはユーザーからのフィードバックイベントに一致します。',
|
||||
namespace_friend: '友達リクエストや友達関係の変更イベントに一致します。',
|
||||
namespace_group:
|
||||
'メンバーの参加、退出、削除などのグループイベントに一致します。',
|
||||
namespace_group: "メンバーの変更やグループ情報の更新などに一致します。",
|
||||
namespace_message:
|
||||
'メッセージの受信、編集、削除、リアクションイベントに一致します。',
|
||||
namespace_platform:
|
||||
@@ -1067,6 +1069,7 @@ const jaJP = {
|
||||
friend_added: '友達関係が作成されました。',
|
||||
group_member_joined: 'ボットがいるグループにメンバーが参加しました。',
|
||||
group_member_left: 'ボットがいるグループからメンバーが退出しました。',
|
||||
group_info_updated: "グループ名や所有者などの情報が変更されました。",
|
||||
group_member_banned: 'グループメンバーがBANまたは削除されました。',
|
||||
bot_invited_to_group: 'ボットがグループに招待されました。',
|
||||
bot_removed_from_group: 'ボットがグループから削除されました。',
|
||||
|
||||
@@ -1020,6 +1020,7 @@ const ruRU = {
|
||||
eventNames: {
|
||||
wecombot_enter_chat: "Пользователь открыл чат бота",
|
||||
wecombot_template_card_event: "Взаимодействие с карточкой",
|
||||
dingtalk_card_action: "Взаимодействие с карточкой DingTalk",
|
||||
wecomcs_enter_session: "Клиент вошёл в диалог",
|
||||
wecomcs_msg_send_fail: "Ошибка отправки сообщения поддержки",
|
||||
wecomcs_servicer_status_change: "Статус оператора изменён",
|
||||
@@ -1034,6 +1035,7 @@ const ruRU = {
|
||||
friend_added: 'Друг добавлен',
|
||||
group_member_joined: 'Участник вступил в группу',
|
||||
group_member_left: 'Участник покинул группу',
|
||||
group_info_updated: "Информация о группе обновлена",
|
||||
group_member_banned: 'Участник заблокирован',
|
||||
bot_invited_to_group: 'Бот приглашён в группу',
|
||||
bot_removed_from_group: 'Бот удалён из группы',
|
||||
@@ -1044,6 +1046,7 @@ const ruRU = {
|
||||
eventDescriptions: {
|
||||
wecombot_enter_chat: "Пользователь открыл чат бота. Событие подходит для сценариев приветствия.",
|
||||
wecombot_template_card_event: "Пользователь нажал или отправил карточку. Ответы управляемых форм обрабатываются отдельно.",
|
||||
dingtalk_card_action: "Нажатия и отправка карточек; отзывы и управляемые формы обрабатываются отдельно.",
|
||||
wecomcs_enter_session: "Клиент открыл ссылку поддержки; событие содержит источник и код приветствия.",
|
||||
wecomcs_msg_send_fail: "WeChat сообщил об ошибке отправки с ID сообщения и типом ошибки.",
|
||||
wecomcs_servicer_status_change: "Оператор начал, остановил или приостановил приём обращений.",
|
||||
@@ -1057,8 +1060,7 @@ const ruRU = {
|
||||
'Соответствует обратной связи от платформы или пользователя.',
|
||||
namespace_friend:
|
||||
'Соответствует заявкам в друзья и изменениям дружеских связей.',
|
||||
namespace_group:
|
||||
'Соответствует вступлениям, выходам, удалениям участников и другим событиям группы.',
|
||||
namespace_group: "Соответствует изменениям состава и информации группы.",
|
||||
namespace_message:
|
||||
'Соответствует получению, редактированию, удалению сообщений и реакциям.',
|
||||
namespace_platform:
|
||||
@@ -1077,6 +1079,7 @@ const ruRU = {
|
||||
friend_added: 'Установлена дружеская связь.',
|
||||
group_member_joined: 'Участник вступает в группу, где есть бот.',
|
||||
group_member_left: 'Участник покидает группу, где есть бот.',
|
||||
group_info_updated: "Изменились сведения о группе, например название или владелец.",
|
||||
group_member_banned: 'Участник группы заблокирован или удалён.',
|
||||
bot_invited_to_group: 'Бот приглашён в группу.',
|
||||
bot_removed_from_group: 'Бот удалён из группы.',
|
||||
|
||||
@@ -988,6 +988,7 @@ const thTH = {
|
||||
eventNames: {
|
||||
wecombot_enter_chat: "ผู้ใช้เข้าสู่แชตบอต",
|
||||
wecombot_template_card_event: "การโต้ตอบกับการ์ด",
|
||||
dingtalk_card_action: "การโต้ตอบกับการ์ด DingTalk",
|
||||
wecomcs_enter_session: "ลูกค้าเข้าสู่การสนทนา",
|
||||
wecomcs_msg_send_fail: "ส่งข้อความบริการลูกค้าไม่สำเร็จ",
|
||||
wecomcs_servicer_status_change: "สถานะเจ้าหน้าที่เปลี่ยนแปลง",
|
||||
@@ -1002,6 +1003,7 @@ const thTH = {
|
||||
friend_added: 'เพิ่มเพื่อน',
|
||||
group_member_joined: 'สมาชิกเข้าร่วมกลุ่ม',
|
||||
group_member_left: 'สมาชิกออกจากกลุ่ม',
|
||||
group_info_updated: "อัปเดตข้อมูลกลุ่ม",
|
||||
group_member_banned: 'สมาชิกถูกแบน',
|
||||
bot_invited_to_group: 'บอตได้รับเชิญเข้ากลุ่ม',
|
||||
bot_removed_from_group: 'บอตถูกนำออกจากกลุ่ม',
|
||||
@@ -1012,6 +1014,7 @@ const thTH = {
|
||||
eventDescriptions: {
|
||||
wecombot_enter_chat: "ผู้ใช้เปิดแชตบอต ใช้สำหรับขั้นตอนต้อนรับและแนะนำ",
|
||||
wecombot_template_card_event: "ผู้ใช้คลิกหรือส่งการ์ด การตอบกลับแบบฟอร์มที่ระบบจัดการจะประมวลผลแยกกัน",
|
||||
dingtalk_card_action: "การคลิกและส่งการ์ด ความคิดเห็นและแบบฟอร์มที่ระบบจัดการจะประมวลผลแยกกัน",
|
||||
wecomcs_enter_session: "ลูกค้าเปิดลิงก์บริการ พร้อมข้อมูลแหล่งที่มาและรหัสต้อนรับ",
|
||||
wecomcs_msg_send_fail: "WeChat แจ้งการส่งล้มเหลว พร้อม ID ข้อความและประเภทข้อผิดพลาด",
|
||||
wecomcs_servicer_status_change: "เจ้าหน้าที่เริ่ม หยุด หรือพักการให้บริการ",
|
||||
@@ -1023,8 +1026,7 @@ const thTH = {
|
||||
'ตรงกับการเชิญ การนำบอทออก การปิดเสียง และเหตุการณ์สถานะอื่น',
|
||||
namespace_feedback: 'ตรงกับเหตุการณ์ข้อเสนอแนะจากแพลตฟอร์มหรือผู้ใช้',
|
||||
namespace_friend: 'ตรงกับคำขอเป็นเพื่อนและการเปลี่ยนแปลงความสัมพันธ์',
|
||||
namespace_group:
|
||||
'ตรงกับการเข้ากลุ่ม ออกจากกลุ่ม ถูกนำออก และเหตุการณ์กลุ่มอื่น',
|
||||
namespace_group: "ตรงกับการเปลี่ยนแปลงสมาชิกและการอัปเดตข้อมูลกลุ่ม",
|
||||
namespace_message: 'ตรงกับการรับ แก้ไข ลบข้อความ และแสดงปฏิกิริยา',
|
||||
namespace_platform: 'ตรงกับเหตุการณ์เฉพาะแพลตฟอร์มที่อะแดปเตอร์ให้มา',
|
||||
custom: 'เหตุการณ์กำหนดเองหรือยังไม่มีคำอธิบาย',
|
||||
@@ -1037,6 +1039,7 @@ const thTH = {
|
||||
friend_added: 'สร้างความสัมพันธ์เพื่อนแล้ว',
|
||||
group_member_joined: 'สมาชิกเข้าร่วมกลุ่มที่มีบอท',
|
||||
group_member_left: 'สมาชิกออกจากกลุ่มที่มีบอท',
|
||||
group_info_updated: "ข้อมูลกลุ่ม เช่น ชื่อหรือเจ้าของกลุ่ม มีการเปลี่ยนแปลง",
|
||||
group_member_banned: 'สมาชิกกลุ่มถูกแบนหรือนำออก',
|
||||
bot_invited_to_group: 'บอทได้รับเชิญเข้ากลุ่ม',
|
||||
bot_removed_from_group: 'บอทถูกนำออกจากกลุ่ม',
|
||||
|
||||
@@ -1005,6 +1005,7 @@ const viVN = {
|
||||
eventNames: {
|
||||
wecombot_enter_chat: "Người dùng vào cuộc trò chuyện với bot",
|
||||
wecombot_template_card_event: "Tương tác thẻ mẫu",
|
||||
dingtalk_card_action: "Tương tác thẻ DingTalk",
|
||||
wecomcs_enter_session: "Khách hàng vào hội thoại",
|
||||
wecomcs_msg_send_fail: "Gửi tin nhắn hỗ trợ thất bại",
|
||||
wecomcs_servicer_status_change: "Trạng thái nhân viên thay đổi",
|
||||
@@ -1019,6 +1020,7 @@ const viVN = {
|
||||
friend_added: 'Đã thêm bạn',
|
||||
group_member_joined: 'Thành viên tham gia nhóm',
|
||||
group_member_left: 'Thành viên rời nhóm',
|
||||
group_info_updated: "Thông tin nhóm được cập nhật",
|
||||
group_member_banned: 'Thành viên bị cấm tham gia nhóm',
|
||||
bot_invited_to_group: 'Bot được mời vào nhóm',
|
||||
bot_removed_from_group: 'Bot bị xóa khỏi nhóm',
|
||||
@@ -1029,6 +1031,7 @@ const viVN = {
|
||||
eventDescriptions: {
|
||||
wecombot_enter_chat: "Người dùng mở cuộc trò chuyện với bot. Dùng cho quy trình chào mừng.",
|
||||
wecombot_template_card_event: "Người dùng nhấp hoặc gửi thẻ. Phản hồi biểu mẫu do hệ thống quản lý được xử lý riêng.",
|
||||
dingtalk_card_action: "Nhấp và gửi thẻ; phản hồi và biểu mẫu được quản lý được xử lý riêng.",
|
||||
wecomcs_enter_session: "Khách hàng mở liên kết hỗ trợ; gồm nguồn truy cập và mã chào mừng.",
|
||||
wecomcs_msg_send_fail: "WeChat thông báo gửi thất bại, gồm ID tin nhắn và loại lỗi.",
|
||||
wecomcs_servicer_status_change: "Nhân viên bắt đầu, dừng hoặc tạm dừng tiếp nhận.",
|
||||
@@ -1040,8 +1043,7 @@ const viVN = {
|
||||
'Khớp sự kiện mời, xóa, tắt tiếng bot và các thay đổi trạng thái khác.',
|
||||
namespace_feedback: 'Khớp sự kiện phản hồi từ nền tảng hoặc người dùng.',
|
||||
namespace_friend: 'Khớp yêu cầu kết bạn và thay đổi quan hệ bạn bè.',
|
||||
namespace_group:
|
||||
'Khớp sự kiện tham gia, rời, bị xóa khỏi nhóm và sự kiện nhóm khác.',
|
||||
namespace_group: "Khớp các thay đổi thành viên và cập nhật thông tin nhóm.",
|
||||
namespace_message: 'Khớp sự kiện nhận, sửa, xóa và thả cảm xúc tin nhắn.',
|
||||
namespace_platform:
|
||||
'Khớp sự kiện riêng của nền tảng do bộ chuyển đổi cung cấp.',
|
||||
@@ -1055,6 +1057,7 @@ const viVN = {
|
||||
friend_added: 'Đã tạo quan hệ bạn bè.',
|
||||
group_member_joined: 'Thành viên tham gia nhóm có bot.',
|
||||
group_member_left: 'Thành viên rời nhóm có bot.',
|
||||
group_info_updated: "Thông tin nhóm như tên hoặc chủ sở hữu đã thay đổi.",
|
||||
group_member_banned: 'Thành viên nhóm bị cấm hoặc xóa.',
|
||||
bot_invited_to_group: 'Bot được mời vào nhóm.',
|
||||
bot_removed_from_group: 'Bot bị xóa khỏi nhóm.',
|
||||
|
||||
@@ -948,6 +948,7 @@ const zhHans = {
|
||||
eventNames: {
|
||||
wecombot_enter_chat: "用户进入机器人会话",
|
||||
wecombot_template_card_event: "模板卡片交互",
|
||||
dingtalk_card_action: "钉钉卡片交互",
|
||||
wecomcs_enter_session: "客户进入会话",
|
||||
wecomcs_msg_send_fail: "客服消息发送失败",
|
||||
wecomcs_servicer_status_change: "接待人员状态变更",
|
||||
@@ -962,6 +963,7 @@ const zhHans = {
|
||||
friend_added: '好友添加成功',
|
||||
group_member_joined: '成员加入群组',
|
||||
group_member_left: '成员离开群组',
|
||||
group_info_updated: "群信息更新",
|
||||
group_member_banned: '成员被封禁',
|
||||
bot_invited_to_group: '机器人被邀入群',
|
||||
bot_removed_from_group: '机器人被移出群',
|
||||
@@ -972,6 +974,7 @@ const zhHans = {
|
||||
eventDescriptions: {
|
||||
wecombot_enter_chat: "用户进入机器人会话,可用于欢迎和引导流程。",
|
||||
wecombot_template_card_event: "用户点击或提交模板卡片;已有交互表单的回调单独处理。",
|
||||
dingtalk_card_action: "用户点击或提交钉钉卡片;反馈和受管理的表单回调单独处理。",
|
||||
wecomcs_enter_session: "客户通过客服链接进入会话,可获取来源和欢迎语凭据。",
|
||||
wecomcs_msg_send_fail: "微信通知客服消息发送失败,包含消息 ID 和失败类型。",
|
||||
wecomcs_servicer_status_change: "接待人员开始、停止接待或暂时挂起。",
|
||||
@@ -982,7 +985,7 @@ const zhHans = {
|
||||
namespace_bot: '匹配机器人入群、退群、禁言和解除禁言等状态事件。',
|
||||
namespace_feedback: '匹配平台或用户反馈事件。',
|
||||
namespace_friend: '匹配好友请求、好友添加成功等好友关系事件。',
|
||||
namespace_group: '匹配成员加入、离开或被移出群组等群组成员事件。',
|
||||
namespace_group: "匹配群成员变动、群信息更新等群组事件。",
|
||||
namespace_message: '匹配消息接收、编辑、删除和表态事件。',
|
||||
namespace_platform: '匹配适配器提供的平台专属事件。',
|
||||
custom: '自定义或暂未提供说明的事件。',
|
||||
@@ -995,6 +998,7 @@ const zhHans = {
|
||||
friend_added: '好友关系建立成功。',
|
||||
group_member_joined: '有成员加入机器人所在群组。',
|
||||
group_member_left: '有成员离开机器人所在群组。',
|
||||
group_info_updated: "群名称、群主等群资料发生变更。",
|
||||
group_member_banned: '群成员被封禁或移出。',
|
||||
bot_invited_to_group: '机器人被邀请加入群组。',
|
||||
bot_removed_from_group: '机器人被移出群组。',
|
||||
|
||||
@@ -947,6 +947,7 @@ const zhHant = {
|
||||
eventNames: {
|
||||
wecombot_enter_chat: "使用者進入機器人會話",
|
||||
wecombot_template_card_event: "範本卡片互動",
|
||||
dingtalk_card_action: "釘釘卡片互動",
|
||||
wecomcs_enter_session: "客戶進入會話",
|
||||
wecomcs_msg_send_fail: "客服訊息傳送失敗",
|
||||
wecomcs_servicer_status_change: "接待人員狀態變更",
|
||||
@@ -961,6 +962,7 @@ const zhHant = {
|
||||
friend_added: '新增好友',
|
||||
group_member_joined: '成員加入群組',
|
||||
group_member_left: '成員離開群組',
|
||||
group_info_updated: "群組資訊更新",
|
||||
group_member_banned: '成員被封禁',
|
||||
bot_invited_to_group: '機器人被邀請加入群組',
|
||||
bot_removed_from_group: '機器人被移出群組',
|
||||
@@ -971,6 +973,7 @@ const zhHant = {
|
||||
eventDescriptions: {
|
||||
wecombot_enter_chat: "使用者進入機器人會話,可用於歡迎和引導流程。",
|
||||
wecombot_template_card_event: "使用者點擊或提交範本卡片;已有互動表單的回呼單獨處理。",
|
||||
dingtalk_card_action: "使用者點擊或提交釘釘卡片;回饋和受管理的表單回呼單獨處理。",
|
||||
wecomcs_enter_session: "客戶透過客服連結進入會話,可取得來源和歡迎語憑證。",
|
||||
wecomcs_msg_send_fail: "微信通知客服訊息傳送失敗,包含訊息 ID 和失敗類型。",
|
||||
wecomcs_servicer_status_change: "接待人員開始、停止接待或暫時掛起。",
|
||||
@@ -981,7 +984,7 @@ const zhHant = {
|
||||
namespace_bot: '匹配機器人入羣、退羣、禁言和解除禁言等狀態事件。',
|
||||
namespace_feedback: '匹配平臺或使用者反饋事件。',
|
||||
namespace_friend: '匹配好友請求、好友添加成功等好友關係事件。',
|
||||
namespace_group: '匹配成員加入、離開或被移出羣組等羣組成員事件。',
|
||||
namespace_group: "匹配群組成員變動、群組資訊更新等事件。",
|
||||
namespace_message: '匹配訊息接收、編輯、刪除和表態事件。',
|
||||
namespace_platform: '匹配適配器提供的平臺專屬事件。',
|
||||
custom: '自定義或暫未提供說明的事件。',
|
||||
@@ -994,6 +997,7 @@ const zhHant = {
|
||||
friend_added: '好友關係建立成功。',
|
||||
group_member_joined: '有成員加入機器人所在羣組。',
|
||||
group_member_left: '有成員離開機器人所在羣組。',
|
||||
group_info_updated: "群組名稱、群主等群組資料發生變更。",
|
||||
group_member_banned: '羣成員被封禁或移出。',
|
||||
bot_invited_to_group: '機器人被邀請加入羣組。',
|
||||
bot_removed_from_group: '機器人被移出羣組。',
|
||||
|
||||
Reference in New Issue
Block a user