import asyncio from pathlib import Path from typing import Any, Dict import filetype from meme_generator import get_memes from meme_generator.meme import Meme memes = sorted(get_memes(), key=lambda meme: meme.key) image_path = Path("docs/images") async def generate_preview_images(): for meme in memes: async def generate_image(name: str, args: Dict[str, Any] = {}): for path in image_path.iterdir(): if name == path.stem: return result = await meme.generate_preview(args=args) content = result.getvalue() ext = filetype.guess_extension(content) filename = f"{name}.{ext}" with open(image_path / filename, "wb") as f: f.write(content) await generate_image(f"{meme.key}") if args := meme.params_type.args_type: if instances := args.instances: for i, instance in enumerate(instances): await generate_image(f"{meme.key}_instance{i}", instance.dict()) def meme_doc(meme: Meme) -> str: keywords = "、".join([f"`{keyword}`" for keyword in meme.keywords]) patterns = "、".join([f"`{pattern}`" for pattern in meme.patterns]) 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 = ( f"{', '.join([f'`{text}`' for text in meme.params_type.default_texts])}" ) def arg_info(name: str, info: Dict[str, Any]) -> str: text = ( f" - `{name}`\n" f" - 描述:{info.get('description', '')}\n" f" - 类型:`{info.get('type', '')}`\n" f" - 默认值:`{info.get('default', '')}`" ) if enum := info.get("enum", []): assert isinstance(enum, list) text += f"\n - 可选值:{'、'.join([f'`{e}`' for e in enum])}" return text if args := meme.params_type.args_type: model = args.model properties: Dict[str, Dict[str, Any]] = ( model.schema().get("properties", {}).copy() ) properties.pop("user_infos") args_info = "\n" + "\n".join( [arg_info(name, info) for name, info in properties.items()] ) else: args_info = "" if args := meme.params_type.args_type: parser = args.parser parser_info = parser.format_help() parser_info = parser_info.replace("update_doc.py", f"meme generate {meme.key}") else: parser_info = "" def image_doc(name: str) -> str: for path in image_path.iterdir(): if name == path.stem: img_path = path.relative_to(Path("docs")) return ( '
\n' f' \n' "
" ) return "" preview_image = "" if args := meme.params_type.args_type: if instances := args.instances: preview_image = "\n\n".join( [ f"> 参数:{instance.json(exclude={'user_infos'})}\n" + image_doc(meme.key + f"_instance{i}") for i, instance in enumerate(instances) ] ) if not preview_image: preview_image = image_doc(meme.key) return ( f"## {meme.key}\n\n" + f"- 关键词:{keywords}\n" + (f"- 正则表达式:{patterns}\n" if patterns else "") + f"- 需要图片数目:{image_num}\n" + f"- 需要文字数目:{text_num}\n" + (f"- 默认文字:[{default_texts}]\n" if default_texts else "") + (f"- 其他参数:{args_info}\n" if args_info else "") + (f"- 其他参数(命令行选项):\n```shell\n{parser_info}```\n\n" if parser_info else "") + "- 预览:\n" + f"{preview_image}" ) def generate_toc(): return "\n".join( f"{i}. [{meme.key} ({'/'.join(meme.keywords)})](#{meme.key})" for i, meme in enumerate(memes, start=1) ) def generate_doc(): doc = "# 表情列表\n\n以下为内置表情的关键词、所需参数等信息及表情预览\n\n按照表情的 `key` 排列\n\n\n" doc += generate_toc() + "\n\n\n" doc += "\n\n".join(meme_doc(meme) for meme in memes) + "\n" with open("docs/memes.md", "w") as f: f.write(doc) async def main(): await generate_preview_images() generate_doc() if __name__ == "__main__": loop = asyncio.new_event_loop() loop.run_until_complete(main())