Spaces:
Running on Zero
Running on Zero
File size: 7,699 Bytes
ed4faae | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | import asyncio
from pathlib import Path
from typing import Any
import filetype
from arclet.alconna import (
Alconna,
Args,
CommandMeta,
MultiVar,
Option,
Subcommand,
TextFormatter,
)
from arclet.alconna.exceptions import SpecialOptionTriggered
from arclet.alconna.tools import RichConsoleFormatter
from meme_generator.app import run_server
from meme_generator.config import meme_config
from meme_generator.download import check_resources
from meme_generator.exception import MemeGeneratorException, NoSuchMeme
from meme_generator.log import setup_logger
from meme_generator.manager import get_meme, get_memes
def construct_parser() -> Alconna:
sub_commands: list[Subcommand] = []
for meme in get_memes():
options: list[Option] = []
if args_type := meme.params_type.args_type:
for option in args_type.parser_options:
options.append(option.option())
sub_command = Subcommand(
meme.key,
*options,
Option(
"--images",
Args["images", MultiVar(str, "+")],
help_text="输入图片路径",
),
Option("--texts", Args["texts", MultiVar(str, "+")], help_text="输入文字"),
help_text="/".join(meme.keywords),
)
sub_commands.append(sub_command)
parser = Alconna(
"meme",
Subcommand("list", alias=["ls"], help_text="查看表情列表"),
Subcommand(
"info", Args["key#表情名", str], alias=["show"], help_text="查看表情详情"
),
Subcommand("preview", Args["key#表情名", str], help_text="生成表情预览"),
Subcommand("generate", *sub_commands, alias=["make"], help_text="制作表情"),
Subcommand("run", alias=["start"], help_text="启动 web server"),
Subcommand(
"download",
Option("--url", Args["url", str], help_text="指定资源链接"),
help_text="下载内置表情图片",
),
meta=CommandMeta(
description="表情包生成器",
example="meme generate petpet --images /path/to/image/file",
),
formatter_type=RichConsoleFormatter,
)
return parser
def list_memes() -> str:
memes = sorted(get_memes(), key=lambda meme: meme.key)
return "\n".join(
f"{i}. {meme.key} ({'/'.join(meme.keywords)})"
for i, meme in enumerate(memes, start=1)
)
def meme_info(key: str) -> str:
try:
meme = get_meme(key)
except NoSuchMeme:
return f'表情 "{key}" 不存在!'
keywords = "、".join([f'"{keyword}"' for keyword in meme.keywords])
shortcuts = "、".join(
[f'"{shortcut.humanized or shortcut.key}"' for shortcut in meme.shortcuts]
)
tags = "、".join([f'"{tag}"' for tag in sorted(meme.tags)])
image_num = f"{meme.params_type.min_images}"
if meme.params_type.max_images > meme.params_type.min_images:
image_num += f" ~ {meme.params_type.max_images}"
text_num = f"{meme.params_type.min_texts}"
if meme.params_type.max_texts > meme.params_type.min_texts:
text_num += f" ~ {meme.params_type.max_texts}"
default_texts = ", ".join([f'"{text}"' for text in meme.params_type.default_texts])
args_info = ""
if args_type := meme.params_type.args_type:
formater = TextFormatter()
for option in args_type.parser_options:
opt = option.option()
alias_text = (
" ".join(opt.requires)
+ (" " if opt.requires else "")
+ "│".join(sorted(opt.aliases, key=len))
)
args_info += (
f"\n * {alias_text}{opt.separators[0]}"
f"{formater.parameters(opt.args)} {opt.help_text}"
)
return (
f"表情名:{meme.key}\n"
+ f"关键词:{keywords}\n"
+ (f"快捷指令:{shortcuts}\n" if shortcuts else "")
+ (f"标签:{tags}\n" if tags else "")
+ f"需要图片数目:{image_num}\n"
+ f"需要文字数目:{text_num}\n"
+ (f"默认文字:[{default_texts}]\n" if default_texts else "")
+ (f"其他参数:{args_info}" if args_info else "")
)
def generate_meme_preview(key: str) -> str:
try:
meme = get_meme(key)
except NoSuchMeme:
return f'表情 "{key}" 不存在!'
try:
result = meme.generate_preview()
content = result.getvalue()
ext = filetype.guess_extension(content)
filename = f"result.{ext}"
with open(filename, "wb") as f:
f.write(content)
return f'表情制作成功!生成的表情文件为 "{filename}"'
except MemeGeneratorException as e:
return str(e)
def generate_meme(
key: str, images: list[str], texts: list[str], args: dict[str, Any]
) -> str:
try:
meme = get_meme(key)
except NoSuchMeme:
return f'表情 "{key}" 不存在!'
for image in images:
if not Path(image).exists():
return f'图片路径 "{image}" 不存在!'
try:
result = meme(images=images, texts=texts, args=args)
content = result.getvalue()
ext = filetype.guess_extension(content)
filename = f"result.{ext}"
with open(filename, "wb") as f:
f.write(content)
return f'表情制作成功!生成的表情文件为 "{filename}"'
except MemeGeneratorException as e:
return str(e)
def main():
setup_logger()
parser = construct_parser()
result = parser()
if not result.matched:
if not isinstance(result.error_info, SpecialOptionTriggered):
print(result.error_info) # noqa: T201
return
if not result.subcommands:
print(parser.get_help()) # noqa: T201
for subcommand, sub_result in result.subcommands.items():
if subcommand == "list":
print(list_memes()) # noqa: T201
elif subcommand == "info":
key = str(sub_result.args["key"])
print(meme_info(key)) # noqa: T201
elif subcommand == "preview":
key = str(sub_result.args["key"])
print(generate_meme_preview(key)) # noqa: T201
elif subcommand == "generate":
for key, subsub_result in sub_result.subcommands.items():
images = (
list(subsub_result.options["images"].args["images"])
if "images" in subsub_result.options
else []
)
texts = (
list(subsub_result.options["texts"].args["texts"])
if "texts" in subsub_result.options
else []
)
options = subsub_result.options
options.pop("images", None)
options.pop("texts", None)
args = {}
for option, option_result in options.items():
if option_result.value is None:
args.update(option_result.args)
else:
args[option] = option_result.value
print(generate_meme(key, images, texts, args)) # noqa: T201
elif subcommand == "run":
run_server()
elif subcommand == "download":
if "url" in sub_result.options:
url = sub_result.options["url"].args["url"]
meme_config.resource.resource_url = url
loop = asyncio.new_event_loop()
loop.run_until_complete(check_resources())
if __name__ == "__main__":
main()
|