From 47921d50ee817445280920b5f0a6b2fa31f178f5 Mon Sep 17 00:00:00 2001 From: Richard Chien Date: Wed, 15 Feb 2017 18:07:36 +0800 Subject: [PATCH] Add mojo_weixin adapter --- app.py | 2 - commands/ai.py | 31 +++++---- filters/allow_only_message_10000.py | 10 +++ filters/intercept_massive_platform_100.py | 10 +++ msg_src_adapter.py | 8 ++- msg_src_adapters/mojo_weixin.py | 84 +++++++++++++++++++++++ nl_processor.py | 2 +- 7 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 filters/allow_only_message_10000.py create mode 100644 filters/intercept_massive_platform_100.py create mode 100644 msg_src_adapters/mojo_weixin.py diff --git a/app.py b/app.py index cd24c74a..b4e2f0bb 100644 --- a/app.py +++ b/app.py @@ -23,8 +23,6 @@ def _main(ctx_msg: dict): if not adapter: raise SkipException ctx_msg = adapter.unitize_context(ctx_msg) - if ctx_msg.get('post_type') != 'message': - raise SkipException if not apply_filters(ctx_msg): raise SkipException except SkipException: diff --git a/commands/ai.py b/commands/ai.py index 1f1f7235..b8a6565d 100644 --- a/commands/ai.py +++ b/commands/ai.py @@ -3,7 +3,8 @@ import requests from command import CommandRegistry from commands import core -from little_shit import get_source +from little_shit import get_source, get_message_sources +from msg_src_adapter import get_adapter __registry__ = cr = CommandRegistry() @@ -32,15 +33,19 @@ def tuling123(args_text, ctx_msg, internal=False): reply = '腊鸡图灵机器人出问题了,先不管他,过会儿再玩他' core.echo(reply, ctx_msg) -# TODO: 加入微信消息源之后修改 -# @cr.register('xiaoice', '小冰') -# def xiaoice(args_text, ctx_msg, internal=False): -# resp = api.wx_consult(account='xiaoice-ms', content=args_text) -# if resp: -# json = resp.json() -# if json and json.get('reply'): -# reply = json['reply'] -# core.echo(reply, ctx_msg, internal) -# return reply -# core.echo('小冰没有回复,请稍后再试', ctx_msg, internal) -# return None + +@cr.register('xiaoice', '小冰') +def xiaoice(args_text, ctx_msg, internal=False): + msg_sources = get_message_sources() + for src in msg_sources: + if src['via'] == 'mojo_weixin': + # Only MojoWeixin support this function + adapter = get_adapter('mojo_weixin', src['login_id']) + if adapter: + json = adapter.consult(account='xiaoice-ms', content=args_text) + if json and json.get('reply'): + reply = json['reply'] + core.echo(reply, ctx_msg, internal) + return reply + core.echo('小冰现在无法回复,请稍后再试', ctx_msg, internal) + return None diff --git a/filters/allow_only_message_10000.py b/filters/allow_only_message_10000.py new file mode 100644 index 00000000..0f13473e --- /dev/null +++ b/filters/allow_only_message_10000.py @@ -0,0 +1,10 @@ +""" +This filter intercepts all post data except ones of which 'post_type' is 'message'. +""" + +from filter import as_filter + + +@as_filter(priority=10000) +def _filter(ctx_msg): + return ctx_msg.get('post_type') == 'message' diff --git a/filters/intercept_massive_platform_100.py b/filters/intercept_massive_platform_100.py new file mode 100644 index 00000000..8abc74da --- /dev/null +++ b/filters/intercept_massive_platform_100.py @@ -0,0 +1,10 @@ +""" +This filter intercepts messages that are from massive platforms. +""" + +from filter import as_filter + + +@as_filter(priority=100) +def _filter(ctx_msg): + return not ctx_msg.get('is_massive_platform', False) diff --git a/msg_src_adapter.py b/msg_src_adapter.py index c1cf24bc..9575dc47 100644 --- a/msg_src_adapter.py +++ b/msg_src_adapter.py @@ -36,18 +36,18 @@ class Adapter(object): elif msg_type == 'private' and hasattr(self, 'send_private_message'): if 'user_id' not in target and 'sender_id' in target: target['user_id'] = target['sender_id'] # compatible with ctx_msg - elif 'user_tid' not in target and 'sender_tid' in target: + if 'user_tid' not in target and 'sender_tid' in target: target['user_tid'] = target.get('sender_tid') # compatible with ctx_msg self.send_private_message(target, content) if 'user_id' in target and 'sender_id' in target: del target['user_id'] - elif 'user_tid' in target and 'sender_tid' in target: + if 'user_tid' in target and 'sender_tid' in target: del target['user_tid'] def get_login_info(self, ctx_msg: dict): - return {'user_id': ctx_msg.get('login_id')} + return {} def is_sender_superuser(self, ctx_msg: dict): return ctx_msg.get('sender_id') == self.superuser_id @@ -125,6 +125,8 @@ def get_adapter(via: str, login_id: str): get_message_sources() )) if len(msg_src_list): + if via not in _adapter_classes: + return None _adapter_instances[key] = _adapter_classes[via](msg_src_list[0]) return _adapter_instances[key] else: diff --git a/msg_src_adapters/mojo_weixin.py b/msg_src_adapters/mojo_weixin.py new file mode 100644 index 00000000..b849dbdd --- /dev/null +++ b/msg_src_adapters/mojo_weixin.py @@ -0,0 +1,84 @@ +import requests + +from msg_src_adapter import Adapter, as_adapter, ConfigurationError + + +@as_adapter(via='mojo_weixin') +class MojoWeixinAdapter(Adapter): + def __init__(self, config: dict): + super().__init__(config) + if not config.get('api_url'): + raise ConfigurationError + self.api_url = config['api_url'] + + def unitize_context(self, ctx_msg: dict): + new_ctx = {'raw_ctx': ctx_msg, 'post_type': ctx_msg['post_type'], 'via': ctx_msg['via'], + 'login_id': ctx_msg['login_id']} + + if ctx_msg['type'].endswith('group_notice'): + new_ctx['post_type'] = 'notice' # Make 'group_notice' a notice but not a message, and ignore it later + + if new_ctx['post_type'] != 'receive_message': + return new_ctx + + new_ctx['post_type'] = 'message' # Just handle 'receive_message', and make 'post_type' 'message' + new_ctx['time'] = ctx_msg['time'] + new_ctx['msg_id'] = str(ctx_msg['id']) + new_ctx['msg_type'] = ctx_msg['type'].split('_')[0] + new_ctx['msg_type'] = 'private' if new_ctx['msg_type'] == 'friend' else new_ctx['msg_type'] + new_ctx['format'] = ctx_msg.get('format', 'text') + new_ctx['content'] = ctx_msg['content'] + + new_ctx['receiver'] = ctx_msg.get('receiver', '') + new_ctx['receiver_name'] = ctx_msg.get('receiver_name', '') + new_ctx['receiver_id'] = ctx_msg.get('receiver_account', '') + new_ctx['receiver_tid'] = ctx_msg.get('receiver_id', '') + + new_ctx['sender'] = ctx_msg.get('sender', '') + new_ctx['sender_name'] = ctx_msg.get('sender_name', '') + new_ctx['sender_id'] = ctx_msg.get('sender_account', '') + new_ctx['sender_tid'] = ctx_msg.get('sender_id', '') + + if new_ctx['msg_type'] == 'group': + new_ctx['group'] = ctx_msg.get('group', '') + new_ctx['group_id'] = '' # WeChat does not has a unique group id that won't change after re-login + new_ctx['group_tid'] = ctx_msg.get('group_id', '') + + # Check if the sender is a massive platform + friend_list = requests.get(self.api_url + '/search_friend', params={'id': ctx_msg.get('sender_id')}).json() + if friend_list and len(friend_list) > 0: + if friend_list[0].get('category') == '公众号': + new_ctx['is_massive_platform'] = True + + return new_ctx + + def get_login_info(self, ctx_msg: dict): + json = requests.get(self.api_url + '/get_user_info').json() + if json: + json['user_tid'] = json.get('id') + json['user_id'] = json.get('account') + json['nickname'] = json.get('name') + return json + + def send_private_message(self, target: dict, content: str): + params = None + if target.get('user_id'): + params = {'account': target.get('user_id')} + elif target.get('user_tid'): + params = {'id': target.get('user_tid')} + + if params: + params['content'] = content + requests.get(self.api_url + '/send_friend_message', params=params) + + def send_group_message(self, target: dict, content: str): + params = None + if target.get('group_tid'): + params = {'id': target.get('group_tid')} + + if params: + params['content'] = content + requests.get(self.api_url + '/send_group_message', params=params) + + def consult(self, account: str, content: str): + return requests.get(self.api_url + '/consult', params={'account': account, 'content': content}).json() diff --git a/nl_processor.py b/nl_processor.py index 4c358528..b3797482 100644 --- a/nl_processor.py +++ b/nl_processor.py @@ -19,7 +19,7 @@ def as_processor(keywords=None): def parse_potential_commands(sentence): segmentation = list(jieba.posseg.cut(sentence=sentence)) - print('分词结果:', ['[' + s.flag + ']' + s.word for s in segmentation]) + print('分词结果:', ' '.join(['[' + s.flag + ']' + s.word for s in segmentation])) potential_commands = [] for processor in _processors: processed = False