Discord机器人实现涩图功能

Discord机器人实现涩图功能

Discord机器人实现涩图功能 上篇文章我们构建了一个最基础的机器人,接下来就得给他加点功能了 作为一个聊天机器人最重要的功能,那当然是涩图! 我们的需求是调用一个指令 /涩图 就可以获取一张涩图,而且还可以带点可选的参数 调用API 这里使用lolicon API(十分感谢API作者) API可

Discord机器人实现涩图功能

上篇文章我们构建了一个最基础的机器人,接下来就得给他加点功能了

作为一个聊天机器人最重要的功能,那当然是涩图!

我们的需求是调用一个指令 /涩图 就可以获取一张涩图,而且还可以带点可选的参数

调用API

这里使用lolicon API(十分感谢API作者)

API可以传入几个参数,我这里就给用户提供三个参数: r18 tags exclude_AI ,使用POST方式请求

先写一个最基础的请求类

def RequestLolicon(tags: list[str], r18: bool, excludeAI: bool) -> dict:
    params = { 
        'r18': r18.as_integer_ratio()[0],
        'excludeAI': excludeAI.as_integer_ratio()[0]
        }
    if len(tags) > 0:
        params['tag'] = tags
    result = requests.get("https://api.lolicon.app/setu/v2", params=params, timeout=5, proxies={ 'https': None } )
    return result.json() if result.json()['data'] else None

这段代码写了一个基础的请求图片数据的函数,传入三个参数,返回结果。

下载图片

我想让图片直接下载到本地,然后上传到discord的CDN上,所以需要一个图片下载功能

先写一个简单的下载图片函数

def Download(pid: str, url: str) -> str:
    ext = url.split('.')[-1]
    
    r = requests.get(url, timeout=30, proxies={ 'https': None })
    
    os.makedirs('./cache/setu/', exist_ok=True)
    with open(f'./cache/setu/{pid}.{ext}', 'wb') as img:
        img.write(r.content)
    
    return f'{pid}.{ext}'

这个函数传入两个参数 pid url

其中 url 是我们通过上一个调用API之后的结果获得的,因为这里只是个工具函数,所以不需要去关心API返回的数据。

pid 也是返回的数据,用于文件名

这个函数会把图片下载到 ./cache/setu/{pid}.{ext} 这个地方,其中 ext 根据下载 url 的后缀定

整合

接下来就是整合这两个函数,并且和Discord交互

async def HandleRequest(ctx: SlashContext, args, r18, excludeAI):
    tags = args.split(',')
    tags = args.split(',')
    data = RequestLolicon(tags, r18, excludeAI)
    if data is None:
        await ctx.send('未找到与tag所匹配的图片')
    else:
        pid = str(data['data'][0]['pid'])
        url = data['data'][0]['urls']['original']

        filename = Download(pid, url)
        file = File(
            file = f'./cache/setu/{filename}',
            file_name = filename,
            description = f'PID: {pid}'
        )

        await ctx.send(f'PID: {pid}', file=file)

        os.remove(f'./cache/setu/{filename}')

这段代码接受一个 SlashContext 参数,是python库 discord-py-interactions 提供给我们的,就是指令的上下文

这四个参数是我们在注册指令的地方传入的

这个函数的大意就是整合请求,下载图片,上传图片,发送消息,删除本地图片为一体

注册Discord Slash指令

现在开始注册Discord的Slash指令

scopes = [XXX]

@interactions.slash_command(
        name = '涩图',
        description = "来张涩图",
        scopes = scopes,
        nsfw = True
          )
@interactions.slash_option(
    name = 'tags',
    description = "指定图片的tag (可选, 用逗号分隔)",
    required = False,
    opt_type = interactions.OptionType.STRING
    )
@interactions.slash_option(
    name = 'r18',
    description = "图片是否为r18 (可选,默认为true)",
    required = False,
    opt_type = interactions.OptionType.BOOLEAN
)
@interactions.slash_option(
    name = 'exclude_ai',
    description = "是否排除AI生成的图片 (可选,默认为true)",
    required = False,
    opt_type = interactions.OptionType.BOOLEAN
)
async def setu(ctx: interactions.SlashContext, tags: str = "", r18 = True, exclude_ai = True):
    await ctx.defer()
    await Setu.HandleRequest(ctx, tags, r18, exclude_ai)

这里有一些东西需要说明:

  • scopes : 指令的作用域,一个数组,里面存的是你要启用指令的服务器ID。

    如果你不设置这个的话,discord默认你在所有服务器里启用,但是指令生效需要1个小时左右,如果你设置了瞬间就会注册好

    如果你设置正确的服务器ID,但是还是没有注册成功,那就有可能是你权限没开

    服务器ID的获取方式是 打开开发者模式 -> 右键服务器名 -> 复制服务器ID,具体方法如下:

    81514CF6-52E9-4835-9F7F-1B9968C4D84F.png20125CB0-CAD3-4334-8C45-42299F50319F.png

  • 指令注册Slash Command

    @interactions.slash_command(
            name = '指令名',
            description = "指令简介",
            scopes = scopes,
            nsfw = True
              )

    注册一个基本指令的注解

  • 指令参数Slash Option

    @interactions.slash_option(
        name = 'tags',
        description = "指定图片的tag (可选, 用逗号分隔)",
        required = False,
        opt_type = interactions.OptionType.STRING
        )

    name代表这个参数的名字,description就是简介

    required 是指定这个参数是不是必要的,如果不必要,那么在函数的参数声明里必须给它一个默认值,比如下面代码的 tags = ""

    opt_type 就是参数的类型,这个类型在 interactions.OptionType 这个枚举里面

  • 函数内部:

     await ctx.defer()
     await Setu.HandleRequest(ctx, tags, r18, exclude_ai)

    await ctx.defer() 这个代码是让机器人显示一个 正在响应 的文字,通常一些耗时操作需要用到这个指令,正好我们下载图片挺耗时的,就加上这个

测试

以上步骤没问题的话,这个功能应该就能正常实现了,成果图如下:

EBBC7FC4-B3C5-4FA7-B3C6-7926B24EA22D.png

LICENSED UNDER CC BY-NC-SA 4.0
Comment