# `7MMM. ,MMF'`7MMM. ,MMF' `7MMM. ,MMF' `7MM # MMMb dPMM MMMb dPMM MMMb dPMM MM # M YM ,M MM M YM ,M MM M YM ,M MM ,pW"Wq. ,M""bMM ,pP"Ybd # M Mb M' MM M Mb M' MM M Mb M' MM 6W' `Wb ,AP MM 8I `" # M YM.P' MM M YM.P' MM mmmmm M YM.P' MM 8M M8 8MI MM `YMMMa. # M `YM' MM M `YM' MM M `YM' MM YA. ,A9 `Mb MM L. I8 # .JML. `' .JMML..JML. `' .JMML. .JML. `' .JMML.`Ybmd9' `Wbmd"MML.M9mmmP' # # (c) 2023 — licensed under Apache 2.0 — https://www.apache.org/licenses/LICENSE-2.0 # meta pic: https://img.icons8.com/?size=512&id=17387&format=png # meta developer: @mm_mods __version__ = "1.0" import asyncio import aiohttp from hikka import loader, utils from telethon.tl.patched import Message import logging import random logger = logging.getLogger(__name__) name_models = { "Analog Diffusion V1": "analog-diffusion-1.0.ckpt [9ca13f02]", "Anything V3": "anythingv3_0-pruned.ckpt [2700c435]", "Anything V4": "anything-v4.5-pruned.ckpt [65745d25]", "Anything V5": "anythingV5_PrtRE.safetensors [893e49b9]", "Orangemix": "AOM3A3_orangemixs.safetensors [9600da17]", "Deliberate V2": "deliberate_v2.safetensors [10ec4b29]", "Dreamlike Diffusion V1": "dreamlike-diffusion-1.0.safetensors [5c9fd6e0]", "Dreamlike Diffusion V2": "dreamlike-diffusion-2.0.safetensors [fdcf65e7]", "Dreamshaper V5": "dreamshaper_5BakedVae.safetensors [a3fbf318]", "Dreamshaper V6": "dreamshaper_6BakedVae.safetensors [114c8abb]", "Elldreth's Vivid Mix": "elldreths-vivid-mix.safetensors [342d9d26]", "Lyriel V1.5": "lyriel_v15.safetensors [65d547c5]", "Meina V9": "meinamix_meinaV9.safetensors [2ec66ab0]", "OpenJourney V4": "openjourney_V4.ckpt [ca2f377f]", "Portrait V1": "portrait+1.0.safetensors [1400e684]", "Realistic Vision V2": "Realistic_Vision_V2.0.safetensors [79587710]", "Rev Animated V1.22": "revAnimated_v122.safetensors [3f4fefd9]", "Riffusion V1": "riffusion-model-v1.ckpt [3aafa6fe]", "StableDiffusion V1.4": "sdv1_4.ckpt [7460a6fa]", "StableDiffusion V1.5": "v1-5-pruned-emaonly.ckpt [81761151]", "Shonin's Beautiful People V1": "shoninsBeautiful_v10.safetensors [25d8c546]", "The Ally's Mix II": "theallys-mix-ii-churned.safetensors [5d9225a4]", "Timeless V1": "timeless-1.0.ckpt [7c4971d4]", } samplers = ["Euler", "Euler a", "Heun", "DPM++ 2M Karras", "DDIM"] # noinspection PyCallingNonCallable @loader.tds class ProdiaMod(loader.Module): """Image generator based on Prodia API. No API key required.""" def __init__(self): self.config = loader.ModuleConfig( loader.ConfigValue( "model", "StableDiffusion V1.5", lambda: self.strings("model-h"), validator=loader.validators.Choice(list(name_models.keys())), ), loader.ConfigValue( "cfg", 8, lambda: self.strings("cfg-h"), validator=loader.validators.Integer(minimum=0, maximum=20), ), loader.ConfigValue( "sampler", "Euler", lambda: self.strings("sampler-h"), validator=loader.validators.Choice(samplers), ), loader.ConfigValue( "steps", 30, lambda: self.strings("steps-h"), validator=loader.validators.Integer(minimum=1, maximum=30), ), loader.ConfigValue( "neg_def", "", lambda: self.strings("ndef-h"), validator=loader.validators.String(), ), ) strings = { "name": "Prodia IG", "model-h": "An initial image set on which the model is based.", "cfg-h": "The higher the value, the closer to prompt the image will be.", "sampler-h": "The algorithm by which the image will be generated.", "steps-h": "The number of steps to generate the image, the higher the value, " "the more detailed the image will be.", "ndef-h": "Default negative prompt. Negative prompt makes AI to NOT generate described in it thing.", "args?": "🟡 You provided no args…", "working": "🎨 Working on your image…\n" "Prompt: {}{}\n\n" "Provided parameters:\n" "Model: {} — ID {}\n" "CFG: {}\n" "Sampler: {}\n" "Steps: {}", "done": "🎉 Your image is done!\n" "Prompt: {}{}\n\n" "Model: {} — ID {}\n" "CFG: {}\n" "Sampler: {}\n" "Steps: {}\n", "neg_prompt": "\nNegative prompt: {}", } strings_ru = { "name": "Prodia IG", "model-h": "Начальный набор изображений, на основе которого построена модель.", "cfg-h": "Чем выше значение, тем более близким к запросу будет изображение.", "sampler-h": "Алгоритм, по которому будет сгенерировано изображение.", "steps-h": "Количество шагов для генерации изображения, чем выше значение, " "тем более детализированным будет изображение.", "ndef-h": "Стандартный негативный запрос. Негативный промпт заставляет ИИ НЕ генерировать " "описанную в нём вещь.", "args?": "🟡 Вы не указали аргументы…", "working": "🎨 Работаю над изображением…\n" "Запрос: {}{}\n\n" "Указанные параметры:\n" "Модель: {} — ID {}\n" "CFG: {}\n" "Сэмплер: {}\n" "Шаги: {}", "done": "🎉 Ваше изображение готово!\n" "Запрос: {}{}\n\n" "Модель: {} — ID {}\n" "CFG: {}\n" "Сэмплер: {}\n" "Шаги: {}\n", "neg_prompt": "\nОтрицательный запрос: {}", "_cls_doc": "Генератор изображений на основе Prodia API. Не требует API ключа.", "_cmd_doc_prodia": "Сгенерировать изображение с помощью Prodia API.", } strings_de = { "name": "Prodia IG", "model-h": "Ein Initialbildsatz, auf dem das Modell basiert.", "cfg-h": "Je höher der Wert, desto näher am Prompt wird das Bild sein.", "sampler-h": "Der Algorithmus, nach dem das Bild generiert wird.", "steps-h": "Die Anzahl der Schritte zur Generierung des Bildes, je höher der Wert, " "desto detaillierter wird das Bild sein.", "ndef-h": "Standardmäßiger negativer Prompt. Negativer Prompt bewirkt, dass die KI NICHT das in ihm " "beschriebene Ding generiert.", "args?": "🟡 Du hast keine Argumente angegeben…", "working": "🎨 Arbeite an deinem Bild…\n" "Prompt: {}{}\n\n" "Angegebene Parameter:\n" "Modell: {} — ID {}\n" "CFG: {}\n" "Sampler: {}\n" "Schritte: {}", "done": "🎉 Dein Bild ist fertig!\n" "Prompt: {}{}\n\n" "Modell: {} — ID {}\n" "CFG: {}\n" "Sampler: {}\n" "Schritte: {}\n", "neg_prompt": "\nNegativer Prompt: {}", "_cls_doc": "Ein Bildgenerator auf Basis der Prodia-API. Benötigt keinen API-Schlüssel.", "_cmd_doc_prodia": "Generieren Sie ein Bild mit der Prodia-API.", } @loader.command("prodia") async def prodiacmd(self, m: Message): """Generate an image using Prodia API.""" prompt = utils.get_args_raw(m) neg_prompt = "" if not prompt: return await utils.answer(m, self.strings("args?")) if "\n" in prompt: prompt, neg_prompt = prompt.split("\n", 1) if neg_prompt == "[]": neg_prompt = self.config["neg_def"] mid = name_models[self.config["model"]] model = self.config["model"] cfg = self.config["cfg"] sampler = self.config["sampler"] steps = self.config["steps"] if neg_prompt: nm = await utils.answer( m, self.strings("working").format( prompt, self.strings("neg_prompt").format(neg_prompt), model, mid, cfg, sampler, steps, ), ) else: nm = await utils.answer( m, self.strings("working").format( prompt, "", model, mid, cfg, sampler, steps ), ) url = "https://api.prodia.com" pars = { "new": "true", "prompt": prompt, "model": mid, "negative_prompt": neg_prompt, "steps": steps, "cfg": cfg, "seed": random.randint(0, 1000000000), "sampler": sampler, "aspect_ratio": "square", } async with aiohttp.ClientSession() as s: async with s.get(f"{url}/generate", params=pars) as r: resp = await r.json() job_id = resp["job"] while True: async with s.get(f"{url}/job/{job_id}") as r: resp = await r.json() if resp["status"] == "succeeded": break await asyncio.sleep(0.15) if neg_prompt: await utils.answer_file( nm, f"https://images.prodia.xyz/{job_id}.png", caption=self.strings("done").format( prompt, self.strings("neg_prompt").format(neg_prompt), model, mid, cfg, sampler, steps, ), ) else: await utils.answer_file( nm, f"https://images.prodia.xyz/{job_id}.png", caption=self.strings("done").format( prompt, "", model, mid, cfg, sampler, steps ), )