Skip to content

Commit

Permalink
Merge pull request #202 from python-discord/jb3/features/face-generator
Browse files Browse the repository at this point in the history
  • Loading branch information
jb3 authored Jun 4, 2024
2 parents 9fa9f14 + 236be7e commit 0f980be
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 10 deletions.
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
FROM --platform=linux/amd64 ghcr.io/owl-corp/python-poetry-base:3.12-slim

# Install build dependencies
RUN apt-get update && apt-get install -y libmagickwand-dev && apt autoclean && rm -rf /var/lib/apt/lists/*

# Install project dependencies
WORKDIR /app
COPY pyproject.toml poetry.lock ./
Expand Down
66 changes: 64 additions & 2 deletions arthur/exts/systems/system_information.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
"""Return system information on our production 9front infrastructure."""

import asyncio
import io
import random
from datetime import UTC, datetime
from urllib import parse

import aiohttp
from discord import Member, Message
from discord.ext.commands import Cog, Context, command
from discord import File, Member, Message
from discord.ext.commands import Cog, Context, Converter, command
from loguru import logger
from wand.image import Image

from arthur.apis.systems import lib9front
from arthur.bot import KingArthur
Expand All @@ -27,6 +30,20 @@
)


class URLConverter(Converter):
"""Validate a passed argument is a URL, for use in optional converters that are looking for URLs."""

async def convert(self, _ctx: Context, argument: str) -> str | None:
"""Attempt to convert a string to a URL, return the argument if it is a URL, else return None."""
try:
parsed = parse.urlparse(argument)

if parsed.scheme in {"http", "https"}:
return argument
except ValueError:
return None


class SystemInformation(Cog):
"""Utilities for fetching system information from our 9front infrastructure."""

Expand Down Expand Up @@ -121,6 +138,51 @@ async def software(self, ctx: Context) -> None:
program = lib9front.generate_buzzwords(bullshit)
await ctx.reply(program)

@command(name="face")
async def face(
self, ctx: Context, resolution: int | None = 60, *, image_url: URLConverter | None = None
) -> None:
"""
Generate a system-compatible face for the given file.
If specified, resolution is the integer width and height to use for the generated image, defaulting to 60 (for a 60x60 image).
The image can be passed in as a URL or attached to the command invocation message.
"""
image_bytes = io.BytesIO()

if not image_url:
if len(ctx.message.attachments) == 0:
await ctx.reply(":x: Must upload an image or specify image URL")
return

await ctx.message.attachments[0].save(image_bytes)
else:
async with aiohttp.ClientSession() as session, session.get(image_url) as resp:
if resp.ok:
image_bytes.write(await resp.read())
image_bytes.seek(0)
else:
await ctx.reply(
f":x: Could not read remote resource, check it exists. (status `{resp.status}`)"
)
return

out_bytes = io.BytesIO()

with Image(file=image_bytes) as img:
img.resize(resolution, resolution)
img.type = "grayscale"
img.kmeans(number_colors=2)

img.format = "png"

img.save(file=out_bytes)

out_bytes.seek(0)

await ctx.reply(file=File(out_bytes, filename="face.png"))


async def setup(bot: KingArthur) -> None:
"""Add cog to bot."""
Expand Down
30 changes: 22 additions & 8 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ tabulate = { extras = ["widechars"], version = "0.9.0" }
jishaku = "2.5.2"
sentry-sdk = "2.3.1"
humanize = "4.9.0"
wand = "0.6.13"

[tool.poetry.dev-dependencies]
pre-commit = "3.7.1"
Expand Down

0 comments on commit 0f980be

Please sign in to comment.