alicebot(一)

这是alicebot文件夹下大致的文件所在位置

.
├── plugins
│   ├── a.py (单个 Python 文件)
│   └── b (Python 包)
│      └── __init__.py
├── config.toml
└── main.py

首先聊一下插件类;

插件的python代码 主要放在plugins文件夹下(建议写单独的python文件)

每个plugin代码都必须实现rule()和handle()功能

rule()方法用于定义插件的触发规则,handle()方法当符合插件规则时会被调用,同时每个插件类都必须是plugin的子类。

from alicebot import Plugin


class HalloAlice(Plugin):
    priority: int = 0
    block: bool = False

    async def handle(self) -> None:
        pass

    async def rule(self) -> bool:
        return True

priority:表示插件运行的优先级 数字越小优先级越高

block: 表示当前插件执行结束后是否阻止事件的传播,如果设置为 True,则当前插件执行完毕后会停止当前事件传播,比当前插件优先级低的插件将不会被执行

它会先运行rule()方法 根据返回值判断是否要运行handle()方法

以下是一些内置方法和属性

from alicebot import Plugin
from alicebot.exceptions import GetEventTimeout


class HalloAlice(Plugin):
    async def handle(self) -> None:
        try:
            name_event = await self.event.ask("What is you name?", timeout=10)

            # await self.event.reply("What is you name?")
            # name_event = await self.event.get(timeout=10)

            # await self.event.reply("What is you name?")
            # name_event = await self.bot.get(
            #     lambda event: (
            #         event.adapter.name == "cqhttp"
            #         and event.type == "message"
            #         and event.sender.user_id == self.event.sender.user_id
            #     ),
            #     timeout=10,
            # )
        except GetEventTimeout:
            return
        else:
            await self.event.reply(f"Hello, {name_event.message}!")

    async def rule(self) -> bool:
        if self.event.adapter.name != "cqhttp":
            return False
        if self.event.type != "message":
            return False
        return str(self.event.message).lower() == "hello"

ask()和get()方法 都可以指定超时时间,因为都是异步方法 所以需要使用await

上述代码中 else用于try语句成功执行,触发条件是你发送hello,它会发送信息问你的姓名,然后返回"hello+姓名"

输出日志一般使用logger.info("Hello"),不建议使用print

例子:(一个完整的可以查询天气的插件)

import aiohttp
from alicebot import Plugin
from alicebot.exceptions import GetEventTimeout

class Weather(Plugin):
    async def handle(self) -> None:
        args = self.event.get_plain_text().split(" ")

        if len(args) >= 2:
            await self.event.reply(await self.get_weather(args[1]))
            return

        try:
            city_event = await self.event.ask("请输入想要查询天气的城市:", timeout=10)
        except GetEventTimeout:
            return
        else:
            await self.event.reply(await self.get_weather(city_event.get_plain_text()))

    async def rule(self) -> bool:
        if self.event.adapter.name != "cqhttp":
            return False
        if self.event.type != "message":
            return False
        return self.event.message.startswith("天气") or self.event.message.startswith("weather")

    @staticmethod
    async def get_weather(city):

        # 使用和风天气API获取城市ID
        api_key = "c7572bff778844748f0b2c955aa83e31"  # 请替换为你的实际API Key
        location_api_url = f"https://geoapi.qweather.com/v2/city/lookup?location={city}&key={api_key}"

        async with aiohttp.ClientSession() as session:
            async with session.get(location_api_url) as response:
                if response.status != 200:
                    return "无法获取城市信息,请稍后再试。"
                location_data = await response.json()
                if location_data.get("code") != "200":
                    return "获取城市信息失败,请稍后再试。"

                location_id = location_data["location"][0]["id"]

                weather_api_url = f"https://devapi.qweather.com/v7/weather/now?location={location_id}&key={api_key}"

                async with session.get(weather_api_url) as response:
                    if response.status != 200:
                        return "无法获取天气信息,请稍后再试。"
                    weather_data = await response.json()
                    if weather_data.get("code") != "200":
                        return "获取天气信息失败,请稍后再试。"

                    # 提取天气信息
                    now = weather_data.get("now", {})
                    weather_text = now.get("text", "未知")
                    temperature = now.get("temp", "未知")
                    feels_like = now.get("feelsLike", "未知")
                    wind_dir = now.get("windDir", "未知")

                    return (
                        f"{city}的天气是:{weather_text},"
                        f"温度:{temperature}°C,"
                        f"体感温度:{feels_like}°C,"
                        f"风向:{wind_dir}。"
                    )

简单的报时功能的案例

import asyncio
import logging
import json
import urllib3
from datetime import datetime, timedelta
from alicebot import Plugin

# 配置日志
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

class Time(Plugin):
    # 配置群组ID列表
    CONFIG_GROUPS = [591910269]
    # 指定报时的时间点,格式为 (小时, 分钟)
    REPORT_TIMES = [(8, 0), (12, 0), (18, 0), (23, 0)]

    async def handle(self) -> None:
        """
        插件的处理方法,AliceBot 会在插件触发时调用此方法。
        """
        logger.debug("Time plugin handle method called.")
        # 初始化并启动周期任务
        asyncio.create_task(self.scheduled_task())

    async def scheduled_task(self):
        """
        定时任务,每到指定时间点发送报时消息。
        """
        while True:
            now = datetime.now()
            # 计算下一个报时点
            next_report_time = self.get_next_report_time(now)
            wait_seconds = (next_report_time - now).total_seconds()
            logger.debug(f"Next report time at {next_report_time}, waiting for {wait_seconds} seconds.")
            await asyncio.sleep(wait_seconds)

            # 获取当前时间并格式化为字符串
            now = datetime.now()
            time_str = now.strftime("%H:%M")
            message_content = f"报时:现在是{time_str}。"
            logger.debug(f"Sending message: {message_content}")

            # 发送报时消息到配置的群组
            for group_id in self.CONFIG_GROUPS:
                try:
                    # 使用 urllib3 发送 POST 请求
                    http = urllib3.PoolManager()
                    headers = {
                        'Authorization': 'Bearer your_actual_access_token',  # 替换为你的 API Token
                        'Content-Type': 'application/json'
                    }
                    data = {
                        'group_id': group_id,
                        'message': message_content
                    }
                    response = http.request(
                        'POST',
                        'http://127.0.0.1:5700/send_group_msg',
                        body=json.dumps(data),
                        headers=headers
                    )
                    if response.status == 200:
                        logger.info(f"Message sent to group {group_id}")
                    else:
                        logger.error(f"Failed to send message to group {group_id}: {response.data.decode('utf-8')}")
                except Exception as e:
                    logger.error(f"Failed to send message to group {group_id}: {e}")

    def get_next_report_time(self, now):
        """
        获取下一个报时点。

        参数:
            now (datetime): 当前时间。

        返回:
            datetime: 下一个报时点。
        """
        # 生成今天的所有报时点
        today_times = [datetime(now.year, now.month, now.day, hour, minute) for hour, minute in self.REPORT_TIMES]
        # 找出还未到的报时点
        future_times = [t for t in today_times if t > now]
        if future_times:
            return future_times[0]
        # 如果今天的报时点已经过去,则返回明天的第一个报时点
        return today_times[0] + timedelta(days=1)

    async def rule(self) -> bool:
        """
        规则方法,用于判断是否触发插件。

        返回:
            bool: 总是返回 True,表示总是触发。
        """
        return True

skip():用于跳过当前插件继续事件传播

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值