Example #1
0
 def __init__(self, bot: NoneBot, ctx: Dict[str, Any], msg: str):
     super().__init__(bot, ctx)
     self.msg = msg
     tmp_msg = Message(msg)
     self.msg_text = tmp_msg.extract_plain_text()
     self.msg_images = [s.data['url'] for s in tmp_msg
                        if s.type == 'image' and 'url' in s.data]
Example #2
0
def extract_text(arg: Message_T) -> str:
    """
    提取消息中的纯文本部分(使用空格合并纯文本消息段)。

    参数:
        arg (nonebot.typing.Message_T):
    """
    arg_as_msg = Message(arg)
    return arg_as_msg.extract_plain_text()
Example #3
0
 def __init__(self, bot: NoneBot, event: CQEvent, msg: str):
     super().__init__(bot, event)
     self.msg: str = msg
     """以字符串形式表示的消息内容,已去除开头的 @ 和机器人称呼,可能存在 CQ 码。"""
     tmp_msg = Message(msg)
     self.msg_text: str = tmp_msg.extract_plain_text()
     """消息内容的纯文本部分,已去除所有 CQ 码/非 `text` 类型的消息段。各纯文本消息段之间使用空格连接。"""
     self.msg_images: List[str] = [
         s.data['url'] for s in tmp_msg
         if s.type == 'image' and 'url' in s.data
     ]
     """消息内容中所有图片的 URL 的列表,如果消息中没有图片,则为 `[]`。"""
Example #4
0
    def refresh(self, ctx: Dict[str, Any], *, current_arg: str = '') -> None:
        """
        Refill the session with a new message context.

        :param ctx: new message context
        :param current_arg: new command argument as a string
        """
        self.ctx = ctx
        self.current_arg = current_arg
        current_arg_as_msg = Message(current_arg)
        self.current_arg_text = current_arg_as_msg.extract_plain_text()
        self.current_arg_images = [s.data['url'] for s in current_arg_as_msg
                                   if s.type == 'image' and 'url' in s.data]
Example #5
0
def _extract_image_urls(arg: Message_T) -> List[str]:
    """Extract all image urls from a message-like object."""
    arg_as_msg = Message(arg)
    return [
        s.data['url'] for s in arg_as_msg
        if s.type == 'image' and 'url' in s.data
    ]
Example #6
0
 def match(self, event: Event, message: str) -> bool:
     # at 了机器人
     if not self.has_at_bot(event, message):
         return False
     # 但是是回复消息
     return not (True in map(lambda seg: seg['type'] == 'reply',
                             Message(message)))
Example #7
0
 def current_arg_text(self) -> str:
     """
     Plain text part in the current argument, without any CQ codes.
     """
     if self._current_arg_text is None:
         self._current_arg_text = Message(
             self.current_arg).extract_plain_text()
     return self._current_arg_text
Example #8
0
 def current_arg_images(self) -> List[str]:
     """`current_arg` 属性中所有图片的 URL 的列表,如果参数中没有图片,则为 `[]`。"""
     if self._current_arg_images is None:
         self._current_arg_images = [
             s.data['url'] for s in Message(self.current_arg)
             if s.type == 'image' and 'url' in s.data
         ]
     return self._current_arg_images
Example #9
0
 def current_arg_images(self) -> List[str]:
     """
     Images (as list of urls) in the current argument.
     """
     if self._current_arg_images is None:
         self._current_arg_images = [
             s.data['url'] for s in Message(self.current_arg)
             if s.type == 'image' and 'url' in s.data
         ]
     return self._current_arg_images
Example #10
0
async def tuling(session: CommandSession):
    message = session.get('message', prompt=__(e.I_AM_READY))

    ctx_id = context_id(session.ctx)
    if ctx_id in tuling_sessions:
        del tuling_sessions[ctx_id]

    tmp_msg = Message(message)
    text = tmp_msg.extract_plain_text()
    images = [
        s.data['url'] for s in tmp_msg if s.type == 'image' and 'url' in s.data
    ]

    # call tuling api
    replies = await call_tuling_api(session, text, images)
    logger.debug(f'Got tuling\'s replies: {replies}')

    if replies:
        for reply in replies:
            await session.send(escape(reply))
            await asyncio.sleep(0.8)
    else:
        await session.send(__(e.I_DONT_UNDERSTAND))

    one_time = session.get_optional('one_time', False)
    if one_time:
        # tuling123 may opened a session, we should recognize the
        # situation that tuling123 want more information from the user.
        # for simplification, we only recognize named entities,
        # and since we will also check the user's input later,
        # here we can allow some ambiguity.
        ne_type = tuling_ne_type(replies, {
            'LOC': ('哪里', '哪儿', re.compile(r'哪\S城市'), '位置'),
            'TIME': ('什么时候', ),
        })
        if ne_type:
            logger.debug(f'One time call, '
                         f'and there is a tuling session for {ne_type}')
            tuling_sessions[ctx_id] = ne_type
    else:
        session.pause()
Example #11
0
def extract_image_urls(arg: Message_T) -> List[str]:
    """
    提取消息中的图片 URL 列表。

    参数:
        arg (nonebot.typing.Message_T):
    """
    arg_as_msg = Message(arg)
    return [
        s.data['url'] for s in arg_as_msg
        if s.type == 'image' and 'url' in s.data
    ]
Example #12
0
    def switch(self, new_message: Message_T) -> NoReturn:
        """
        Finish the session and switch to a new (fake) message event.

        The user may send another command (or another intention as natural
        language) when interacting with the current session. In this case,
        the session may not understand what the user is saying, so it
        should call this method and pass in that message, then NoneBot will
        handle the situation properly.
        """
        if self.is_first_run:
            # if calling this method during first run,
            # we think the command is not handled
            raise _FinishException(result=False)

        if not isinstance(new_message, Message):
            new_message = Message(new_message)
        raise SwitchException(new_message)
Example #13
0
    async def prior_intercept(cls, bot, context, msg, input_vars, update_vars, extras, **kwargs):
        if context['post_type'] == 'message':
            if context.get('sender'):
                for msg_data in context['message']:
                    if msg_data['type'] == 'rich':
                        detail_1 = json.loads(msg_data.get('data', {}).get('content', "{}").replace("[", "[").replace("]", "]").replace(",", ",")).get("detail_1", {})
                        pic_url = detail_1.get("preview", "")

                        if detail_1.get("title") is not None and detail_1.get("desc") is not None:
                            output_msg = Message(detail_1.get("title", "无标题") + ":" + detail_1.get("desc", "无简介"))
                            if not pic_url is None and not pic_url.strip() == "":
                                if not pic_url.startswith("http"):
                                    pic_url = "http://" + pic_url

                                async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=5)) as session:
                                    async with session.get(pic_url) as resp:
                                        pic = await resp.read()

                                output_msg = output_msg + MessageSegment(type_='image', data={'file': "base64://" + base64.b64encode(pic).decode("ascii")})
                            
                            await bot.send(context, output_msg)

        return False
Example #14
0
    def switch(self, new_message: Message_T) -> NoReturn:
        """
        结束当前会话,改变当前消息事件中的消息内容,然后重新处理消息事件。

        此函数可用于从一个命令中跳出,将用户输入的剩余部分作为新的消息来处理,例如可实现以下对话:

        ```
        用户: 帮我查下天气
        Bot: 你要查询哪里的天气呢?
        用户: 算了,帮我查下今天下午南京到上海的火车票吧
        Bot: 今天下午南京到上海的火车票有如下班次: blahblahblah
        ```

        这里进行到第三行时,命令期待的是一个地点,但实际发现消息的开头是「算了」,于是调用 `switch('帮我查下今天下午南京到上海的火车票吧')`,结束天气命令,将剩下来的内容作为新的消息来处理(触发火车票插件的自然语言处理器,进而调用火车票查询命令)。

        参数:
            new_message (nonebot.typing.Message_T): 要覆盖消息事件的新消息内容

        用法:
            ```python
            @my_cmd.args_parser
            async def _(session: CommandSession)
                if not session.is_first_run and session.current_arg.startswith('算了,'):
                    session.switch(session.current_arg[len('算了,'):])
            ```

            使用「算了」来取消当前命令,转而进入新的消息处理流程。这个例子比较简单,实际应用中可以使用更复杂的 NLP 技术来判断。
        """
        if self.is_first_run:
            # if calling this method during first run,
            # we think the command is not handled
            raise _FinishException(result=False)

        if not isinstance(new_message, Message):
            new_message = Message(new_message)
        self._raise(SwitchException(new_message))
Example #15
0
    async def all_state_intercept(cls, bot, context, msg, input_vars,
                                  update_vars, extras, **kwargs):
        if u'疫情' in msg and u'提醒' in msg:
            if u'立即' in msg:
                await cls.check_alert_update_tg(
                    "pneunomia_alert_tg/%s" %
                    (util.get_identity(context, const.GROUP)), util.global_bot,
                    context, False)
                return True

            if u'取消' in msg:
                if u'telegram' in msg.lower():
                    any = False
                    result = "取消了疫情动态(Telegram)。"
                    j: Job
                    for j in util.get_jobs():
                        real_id = j.id.split(":")[-1]
                        args = real_id.split("/")
                        if args[0] == "pneunomia_alert_tg" and args[
                                1] == util.get_identity(context, const.GROUP):
                            j.remove()
                            any = True

                    if any:
                        await bot.send(context, result)
                    return True
                else:
                    any = False
                    result = "取消了疫情动态。"
                    j: Job
                    for j in util.get_jobs():
                        real_id = j.id.split(":")[-1]
                        args = real_id.split("/")
                        if args[0] == "pneunomia_alert" and args[
                                1] == util.get_identity(context, const.GROUP):
                            j.remove()
                            any = True

                    if any:
                        await bot.send(context, result)
                    return True

            else:
                if u'telegram' in msg.lower():
                    digest = u'摘要' in msg
                    jobcall = util.make_jobcall(cls.check_alert_update_tg,
                                                context, digest)
                    job_id = "pneunomia_alert_tg/%s" % (util.get_identity(
                        context, const.GROUP))

                    try:
                        util.add_job(jobcall,
                                     trigger=IntervalTrigger(minutes=9),
                                     id=job_id)
                    except ConflictingIdError:
                        await bot.send(context, "设置开启疫情动态(Telegram):失败:已有这个任务")
                        return True

                    await bot.send(
                        context,
                        "设置开启疫情动态(Telegram):成功" + ("(摘要)" if digest else ""))
                    return True
                else:
                    jobcall = util.make_jobcall(cls.check_alert_update,
                                                context)
                    job_id = "pneunomia_alert/%s" % (util.get_identity(
                        context, const.GROUP))

                    try:
                        util.add_job(jobcall,
                                     trigger=IntervalTrigger(minutes=10),
                                     id=job_id)
                    except ConflictingIdError:
                        await bot.send(context, "设置开启疫情动态:失败:已有这个任务")
                        return True

                    await bot.send(context, "设置开启疫情动态:成功")
                    return True

        elif u'疫情' == msg.strip():
            data = await util.http_get("https://3g.dxy.cn/newh5/view/pneumonia"
                                       )
            byregion_data = REGEX_BYREGION_EXTRACT_JSON.search(data).group(
                "json")
            byregion_data = json.loads(byregion_data)

            news_data = REGEX_NEWS_EXTRACT_JSON.search(data).group("json")
            news_data = json.loads(news_data)

            result = ""

            for region in byregion_data:
                result += ("%s:" % (region["provinceShortName"]))
                result += ("确诊 %s 例" % (region["confirmedCount"]))
                if region["suspectedCount"]:
                    result += (",疑似 %s 例" % (region["suspectedCount"]))
                if region["curedCount"]:
                    result += (",治愈 %s 例" % (region["curedCount"]))
                if region["deadCount"]:
                    result += (",死亡 %s 例" % (region["deadCount"]))
                result += "\n"

            result += "\n"

            total_data = REGEX_TOTAL_EXTRACT_JSON.search(data).group("json")
            total_data = json.loads(total_data)

            remarks = []
            notes = []
            for i in range(5):
                remark = total_data.get("remark" + str(i + 1), "").strip()
                if remark != "":
                    remarks.append(remark)

            for i in range(5):
                note = total_data.get("note" + str(i + 1), "").strip()
                if note != "":
                    notes.append(note)

            remarks = "\n".join(remarks)
            notes = "\n".join(notes)
            total_data["remarks"] = remarks
            total_data["notes"] = notes
            total_data["confirmedIncr"] = total_data.get(
                "confirmedIncr", "???")
            total_data["suspectedIncr"] = total_data.get(
                "suspectedIncr", "???")
            total_data["seriousIncr"] = total_data.get("seriousIncr", "???")
            total_data["curedIncr"] = total_data.get("curedIncr", "???")
            total_data["deadIncr"] = total_data.get("deadIncr", "???")

            result += "总计全国确诊 %(confirmedCount)s 例(较昨日+%(confirmedIncr)s),疑似 %(suspectedCount)s 例(较昨日+%(suspectedIncr)s),重症 %(seriousCount)s 例(较昨日+%(seriousIncr)s),治愈 %(curedCount)s 例(较昨日+%(curedIncr)s),死亡 %(deadCount)s 例(较昨日+%(deadIncr)s)\n\n%(notes)s\n%(remarks)s" % total_data

            result += "\n"

            for i, news_obj in enumerate(news_data[0:5]):
                result += "\n" + (
                    "%d. " % (i + 1)) + datetime.datetime.fromtimestamp(
                        news_obj["modifyTime"] / 1000,
                        tz=datetime.timezone(datetime.timedelta(hours=8))
                    ).strftime("%Y-%m-%d %H:%M:%S") + " - " + news_obj["title"]

            await bot.send(context, Message(result))

            # data = await util.http_get("https://news.sina.cn/zt_d/yiqing0121")

            # sina_data = REGEX_SINA_EXTRACT_JSON.search(data).group("json")
            # sina_data = json.loads(sina_data)

            # pic_data_url = sina_data["data"]["apiRes"]["data"]["components"][0]["data"][0]["pic"]

            # await bot.send(context, MessageSegment(MessageSegment(type_='image', data={'file': pic_data_url})))

            # pic_data_url = total_data["imgUrl"]

            # await bot.send(context, MessageSegment(MessageSegment(type_='image', data={'file': pic_data_url})))

            pic_data = total_data["quanguoTrendChart"]

            for pic_data_obj in pic_data:
                await bot.send(
                    context,
                    Message(pic_data_obj["title"]) + MessageSegment(
                        type_='image', data={'file': pic_data_obj["imgUrl"]}))

            return True

        return False
Example #16
0
 def current_arg_text(self) -> str:
     """`current_arg` 属性的纯文本部分(不包含 CQ 码),各部分使用空格连接。"""
     if self._current_arg_text is None:
         self._current_arg_text = Message(
             self.current_arg).extract_plain_text()
     return self._current_arg_text
Example #17
0
def _extract_text(arg: Message_T) -> str:
    """Extract all plain text segments from a message-like object."""
    arg_as_msg = Message(arg)
    return arg_as_msg.extract_plain_text()