From 53baa59736bb59540c832eef74066efe08bc3985 Mon Sep 17 00:00:00 2001 From: wj-Mcat <1435130236@qq.com> Date: Fri, 12 Nov 2021 15:30:13 +0800 Subject: [PATCH 1/2] add chatbot module --- projects/chatbot/README.md | 5 + projects/chatbot/bot.py | 237 ++++++++++++++++++++++++++++++ projects/chatbot/requirements.txt | 1 + projects/chatbot/simple-bot.py | 13 ++ 4 files changed, 256 insertions(+) create mode 100644 projects/chatbot/README.md create mode 100644 projects/chatbot/bot.py create mode 100644 projects/chatbot/requirements.txt create mode 100644 projects/chatbot/simple-bot.py diff --git a/projects/chatbot/README.md b/projects/chatbot/README.md new file mode 100644 index 000000000..e807c4b00 --- /dev/null +++ b/projects/chatbot/README.md @@ -0,0 +1,5 @@ +## Python Wechaty + +[python-wechaty](https://github.com/wechaty/python-wechaty) is an unified conversational RPA SDK for chatbot maker. Developer at least use six lines code to create chatbot base on multi-ims, eg: wechat, wechat official account, dingtalk, lark, whatsapp, giter, and so on ... + +There are [chinese documents](https://wechaty.readthedocs.io/) and [english documents](http://wechaty.js.org/) for developers to create their own chatbots. \ No newline at end of file diff --git a/projects/chatbot/bot.py b/projects/chatbot/bot.py new file mode 100644 index 000000000..aac02f76f --- /dev/null +++ b/projects/chatbot/bot.py @@ -0,0 +1,237 @@ +"""example code for ding-dong-bot with oop style""" +from typing import List, Optional, Union +import asyncio +from datetime import datetime +from wechaty_puppet import get_logger +from wechaty import ( + MessageType, + FileBox, + RoomMemberQueryFilter, + Wechaty, + Contact, + Room, + Message, + Image, + MiniProgram, + Friendship, + FriendshipType, + EventReadyPayload +) + +logger = get_logger(__name__) + + +class MyBot(Wechaty): + """ + listen wechaty event with inherited functions, which is more friendly for + oop developer + """ + + def __init__(self) -> None: + """initialization function + """ + self.login_user: Optional[Contact] = None + super().__init__() + + async def on_ready(self, payload: EventReadyPayload) -> None: + """listen for on-ready event""" + logger.info('ready event %s...', payload) + + # pylint: disable=R0912,R0914,R0915 + async def on_message(self, msg: Message) -> None: + """ + listen for message event + """ + from_contact: Contact = msg.talker() + text: str = msg.text() + room: Optional[Room] = msg.room() + msg_type: MessageType = msg.type() + file_box: Optional[FileBox] = None + if text == 'ding': + conversation: Union[ + Room, Contact] = from_contact if room is None else room + await conversation.ready() + await conversation.say('dong') + file_box = FileBox.from_url( + 'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/' + 'u=1116676390,2305043183&fm=26&gp=0.jpg', + name='ding-dong.jpg') + await conversation.say(file_box) + + elif msg_type == MessageType.MESSAGE_TYPE_IMAGE: + logger.info('receving image file') + # file_box: FileBox = await msg.to_file_box() + image: Image = msg.to_image() + + hd_file_box: FileBox = await image.hd() + await hd_file_box.to_file('./hd-image.jpg', overwrite=True) + + thumbnail_file_box: FileBox = await image.thumbnail() + await thumbnail_file_box.to_file('./thumbnail-image.jpg', overwrite=True) + artwork_file_box: FileBox = await image.artwork() + await artwork_file_box.to_file('./artwork-image.jpg', overwrite=True) + # reply the image + await msg.say(hd_file_box) + + # pylint: disable=C0301 + elif msg_type in [MessageType.MESSAGE_TYPE_AUDIO, MessageType.MESSAGE_TYPE_ATTACHMENT, MessageType.MESSAGE_TYPE_VIDEO]: + logger.info('receving file ...') + file_box = await msg.to_file_box() + if file_box: + await file_box.to_file(file_box.name) + + elif msg_type == MessageType.MESSAGE_TYPE_MINI_PROGRAM: + logger.info('receving mini-program ...') + mini_program: Optional[MiniProgram] = await msg.to_mini_program() + if mini_program: + await msg.say(mini_program) + + elif text == 'get room members' and room: + logger.info('get room members ...') + room_members: List[Contact] = await room.member_list() + names: List[str] = [ + room_member.name for room_member in room_members] + await msg.say('\n'.join(names)) + + elif text.startswith('remove room member:'): + logger.info('remove room member:') + if not room: + await msg.say('this is not room zone') + return + + room_member_name = text[len('remove room member:') + 1:] + + room_member: Optional[Contact] = await room.member( + query=RoomMemberQueryFilter(name=room_member_name) + ) + if room_member: + if self.login_user and self.login_user.contact_id in room.payload.admin_ids: + await room.delete(room_member) + else: + await msg.say('登录用户不是该群管理员...') + + else: + await msg.say(f'can not fine room member by name<{room_member_name}>') + elif text.startswith('get room topic'): + logger.info('get room topic') + if room: + topic: Optional[str] = await room.topic() + if topic: + await msg.say(topic) + + elif text.startswith('rename room topic:'): + logger.info('rename room topic ...') + if room: + new_topic = text[len('rename room topic:') + 1:] + await msg.say(new_topic) + elif text.startswith('add new friend:'): + logger.info('add new friendship ...') + identity_info = text[len('add new friend:'):] + weixin_contact: Optional[Contact] = await self.Friendship.search(weixin=identity_info) + phone_contact: Optional[Contact] = await self.Friendship.search(phone=identity_info) + contact: Optional[Contact] = weixin_contact or phone_contact + if contact: + await self.Friendship.add(contact, 'hello world ...') + + elif text.startswith('at me'): + if room: + talker = msg.talker() + await room.say('hello', mention_ids=[talker.contact_id]) + + elif text.startswith('my alias'): + talker = msg.talker() + alias = await talker.alias() + await msg.say('your alias is:' + (alias or '')) + + elif text.startswith('set alias:'): + talker = msg.talker() + new_alias = text[len('set alias:'):] + + # set your new alias + alias = await talker.alias(new_alias) + # get your new alias + alias = await talker.alias() + await msg.say('your new alias is:' + (alias or '')) + + elif text.startswith('find friends:'): + friend_name: str = text[len('find friends:'):] + friend = await self.Contact.find(friend_name) + if friend: + logger.info('find only one friend <%s>', friend) + + friends: List[Contact] = await self.Contact.find_all(friend_name) + + logger.info('find friend<%d>', len(friends)) + logger.info(friends) + + else: + pass + + if msg.type() == MessageType.MESSAGE_TYPE_UNSPECIFIED: + talker = msg.talker() + assert isinstance(talker, Contact) + + async def on_login(self, contact: Contact) -> None: + """login event + + Args: + contact (Contact): the account logined + """ + logger.info('Contact<%s> has logined ...', contact) + self.login_user = contact + + async def on_friendship(self, friendship: Friendship) -> None: + """when receive a new friendship application, or accept a new friendship + + Args: + friendship (Friendship): contains the status and friendship info, + eg: hello text, friend contact object + """ + MAX_ROOM_MEMBER_COUNT = 500 + # 1. receive a new friendship from someone + if friendship.type() == FriendshipType.FRIENDSHIP_TYPE_RECEIVE: + hello_text: str = friendship.hello() + + # accept friendship when there is a keyword in hello text + if 'wechaty' in hello_text.lower(): + await friendship.accept() + + # 2. you have a new friend to your contact list + elif friendship.type() == FriendshipType.FRIENDSHIP_TYPE_CONFIRM: + # 2.1 invite the user to wechaty group + # find the topic of room which contains Wechaty keyword + wechaty_rooms: List[Room] = await self.Room.find_all('Wechaty') + + # 2.2 find the suitable room + for wechaty_room in wechaty_rooms: + members: List[Contact] = await wechaty_room.member_list() + if len(members) < MAX_ROOM_MEMBER_COUNT: + contact: Contact = friendship.contact() + await wechaty_room.add(contact) + break + + async def on_room_join(self, room: Room, invitees: List[Contact], + inviter: Contact, date: datetime) -> None: + """on_room_join when there are new contacts to the room + + Args: + room (Room): the room instance + invitees (List[Contact]): the new contacts to the room + inviter (Contact): the inviter who share qrcode or manual invite someone + date (datetime): the datetime to join the room + """ + # 1. say something to welcome the new arrivals + names: List[str] = [] + for invitee in invitees: + await invitee.ready() + names.append(invitee.name) + + await room.say(f'welcome {",".join(names)} to the wechaty group !') + + +async def main() -> None: + """doc""" + bot = MyBot() + await bot.start() + +asyncio.run(main()) diff --git a/projects/chatbot/requirements.txt b/projects/chatbot/requirements.txt new file mode 100644 index 000000000..0facc4111 --- /dev/null +++ b/projects/chatbot/requirements.txt @@ -0,0 +1 @@ +wechaty \ No newline at end of file diff --git a/projects/chatbot/simple-bot.py b/projects/chatbot/simple-bot.py new file mode 100644 index 000000000..6b33b0a67 --- /dev/null +++ b/projects/chatbot/simple-bot.py @@ -0,0 +1,13 @@ +import asyncio +from wechaty import Wechaty, Message + +async def on_message(msg: Message): + if msg.text() == 'ding': + await msg.say('dong') + +async def main(): + bot = Wechaty() + bot.on('message', on_message) + await bot.start() + +asyncio.run(main()) From a9c302f80df113499cb8658a3cf95414b9d8d8df Mon Sep 17 00:00:00 2001 From: wj-Mcat <1435130236@qq.com> Date: Fri, 12 Nov 2021 16:39:23 +0800 Subject: [PATCH 2/2] update screen shot message --- projects/chatbot/README.md | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/projects/chatbot/README.md b/projects/chatbot/README.md index e807c4b00..9ba755975 100644 --- a/projects/chatbot/README.md +++ b/projects/chatbot/README.md @@ -1,5 +1,24 @@ -## Python Wechaty - +# Chatbot [python-wechaty](https://github.com/wechaty/python-wechaty) is an unified conversational RPA SDK for chatbot maker. Developer at least use six lines code to create chatbot base on multi-ims, eg: wechat, wechat official account, dingtalk, lark, whatsapp, giter, and so on ... -There are [chinese documents](https://wechaty.readthedocs.io/) and [english documents](http://wechaty.js.org/) for developers to create their own chatbots. \ No newline at end of file +There are [chinese documents](https://wechaty.readthedocs.io/) and [english documents](http://wechaty.js.org/) for developers to create their own chatbots. + +### Prerequisites + +```shell +pip install -r projects/chatbot/requirements.txt +``` + +### How to run the script + +```python +python projects/chatbot/bot.py +``` + +### Screenshot/GIF showing the sample use of the script + +The Run command script above is the best screenshot. + +## *Author Name* + +[wj-Mcat](https://github.com/wj-Mcat), 吴京京, NLP Researcher, Chatbot Lover