# meta pic: https://static.whypodg.me/mods!stablediffusion.png
# meta banner: https://mods.whypodg.me/badges/stablediffusion.jpg
# meta developer: @idiotcoders
# scope: hikka_only
# scope: hikka_min 1.6.2
import json
import re
import requests
import datetime
from hikkatl.types import Message
from .. import loader, utils
@loader.tds
class StableDiffusionMod(loader.Module):
"""Some mod for work with StableDiffusion. API KEY required!"""
strings = {
"name": "StableDiffusion",
"_cfg_api_key": "Insert the StableDiffusionApi.com API Key",
"_cfg_model": "Pass the AI model",
"_cfg_bad_prompt": "Pass the bad prompt — is that what you don't want to see in the pic",
"_cfg_debug": "Debug mode",
"_cfg_samples": "Default quantity of images to generate",
"_cfg_steps": "Steps — The higher the number, the more the image will be detailed",
"_cfg_upscale": "Using upscale",
"error": "⚠ Some error occured!\n\n{}",
"key_required": "API Key required! Insert it in .cfg StableDiffusion",
"done": "✅ Image is generated!\n\n",
"debug": "Model: {model}\nPrompt: {prompt}\n" \
"Bad prompt: {negative}\nSteps: {steps}, {upsc}" \
"upscaled using external AI{time}",
"not": "not ",
"drawing": "🎨 Image is drawing...",
"help": "🥹 Help for StableDiffusion module\n\n\n" \
"1️⃣ Configuration:\nAll configuration in the config" \
" - .cfg StableDiffusion\n\n\n2️⃣ " \
"Parameters and their description:\n api_key is your personal access key to StableDiffusionAPI.com, " \
" you can get it here\n\n model is the model to be generated (in config specifies which " \
"models are available)\n\n bad_prompt - negative input. It is needed in order to remove from your " \
"images what you don't wanna see\n\n debug - if value is True, the response will contain" \
" information about the generated image(s) (model, prompt, bad_prompt, steps, etc.)\n samples — " \
"number of images generated\n\n steps are «steps» . the higher the number, the more detailed" \
" the image will be\n\n upscale - improved generation using AI\n\n\n3️⃣ Usage:\nLet's suppose that you have finished the setup. Let's move on to use.\n" \
"You need to use it like this: .sd <prompt>\nWhere <prompt> is whatever you wanna see on " \
"the image"
}
strings_ru = {
"_cls_doc": "Какой-то модуль для работы с StableDiffusion. Нужен API KEY!",
"_cfg_api_key": "Укажи свой API Key от StableDiffusionAPI.com",
"_cfg_model": "Укажи модель",
"_cfg_bad_prompt": "Укажи негативный ввод — то, что ты не хочешь видеть на изображении",
"_cfg_debug": "Debug мод",
"_cfg_samples": "Количество изображений по умолчанию для генерации",
"_cfg_steps": "Шаги - чем выше число, тем больше детальнее будет изображение.",
"_cfg_upscale": "Использование улучшения",
"error": "⚠ Произошла ошибка!\n\n{}",
"key_required": "⚠ Нужен API Key! Укажи его в .cfg StableDiffusion",
"done": "✅ Изображение сгенерировано!\n\n",
"debug": "Модель: {model}\nВвод: {prompt}\n" \
"Негативный ввод: {negative}\nШаги: {steps}, {upsc}" \
"улучшено с использованием ИИ{time}",
"not": "не было ",
"drawing": "🎨 Рисую…",
"help": "🥹 Помощь по модулю StableDiffusion\n\n\n" \
"1️⃣ Настройка.\nВся настройка проводится в конфиге — " \
".cfg StableDiffusion\n\n\n2️⃣ Параметры и их описание" \
":\n api_key — это ваш персональный ключ доступа к StableDiffusionAPI.com, его можно получить на" \
" этом же сайте\n\n model — это модель для генерации (в конфиге указано, какие модели есть)\n\n" \
" bad_prompt — негативный ввод. он нужен для того, чтобы убрать с ваших изображений то, " \
"что вы не хотите видеть\n\n debug — если установлено True, в ответе будет информация" \
" о генерируемом(-ых) изображении(-ях) (модель, prompt, bad_prompt, steps и т.д.)" \
"\n\n samples — кол-во генерации изображений" \
"\n\n steps — это «шаги». чем выше число, тем детальнее будет изображение" \
"\n\n upscale — улучшение генерации с помощью ИИ" \
"\n\n\n3️⃣ Использование \nПредположим, что Вы закончили настройку. " \
"Перейдём к использованию.\n\nИспользовать нужно так: .sd <prompt>\nГде <prompt> — что угодно" \
", что вы хотите видеть на изображении"
}
def __init__(self): # debug: bool, bad_prompt
self.config = loader.ModuleConfig(
loader.ConfigValue(
"api_key",
None,
lambda: self.strings("_cfg_api_key"),
validator=loader.validators.Hidden()
),
loader.ConfigValue(
"model",
"anything-v5",
lambda: self.strings("_cfg_model"),
validator=loader.validators.Choice([
'abyssorangemix2nsfw', 'anything-v4', 'anything-v5',
'anythingelse-v4', 'bro623jbfe32', 'cetusmix', 'cnwi74tjsdfw',
'counterfeit-v20', 'counterfeit-v30', 'dark-sushi-25d',
'disillusionmix', 'grapefruit-nsfw-anim', 'hanfu',
'hc-a-mecha-musume-a', 'hc-kokkoro', 'hc-kyoka', 'hc-sailor-mercury',
'majicmixfantasy', 'meinamix', 'meinapastel', 'night-sky-yozora-sty',
'tmnd-mix', 'troi4bwiyt4', 'ttksuperspirit'
])
),
loader.ConfigValue(
"bad_prompt",
(
"(bad_prompt:0.8), multiple persons, multiple views, extra hands,"
" ugly, lowres, bad quality, blurry, disfigured, extra limbs,"
" missing limbs, deep fried, cheap art, missing fingers, out of"
" frame, cropped, bad art, face hidden, text, speech bubble,"
" stretched, bad hands, error, extra digit, fewer digits, worst"
" quality, low quality, normal quality, mutated, mutation,"
" deformed, severed, dismembered, corpse, pubic, poorly drawn,"
" (((deformed hands))), (((more than two hands))), (((deformed"
" body))), ((((mutant)))), painting, extra fingers, mutated hands,"
" poorly drawn hands, poorly drawn face, bad anatomy, bad"
" proportions, cloned face, skinny, glitchy, double torso,"
" extra arms, mangled fingers, missing lips, distorted face,"
" extra legs"
),
lambda: self.strings("_cfg_bad_prompt"),
),
loader.ConfigValue(
"debug",
False,
lambda: self.strings("_cfg_debug"),
validator=loader.validators.Boolean()
),
loader.ConfigValue(
"samples",
1,
lambda: self.strings("_cfg_samples"),
validator=loader.validators.Integer(minimum=1, maximum=4),
),
loader.ConfigValue(
"steps",
30,
lambda: self.strings("_cfg_steps"),
validator=loader.validators.Integer(minimum=1, maximum=50),
),
loader.ConfigValue(
"upscale",
False,
lambda: self.strings("_cfg_upscale"),
validator=loader.validators.Boolean()
)
)
async def getFetch(self, url):
payload = json.dumps({"key": self.config['api_key']})
headers = {"Content-Type": "application/json"}
r = (await utils.run_sync(
requests.post,
url,
headers=headers,
data=payload
)).json()
if r.get('status') == "success":
return r['output']
else:
return (await self.getFetch(url))
@loader.command(
ru_doc="— помощь по использованию и настройке модуля",
alias="sdh"
)
async def sdhelpcmd(self, message: Message):
"""— help on using and configure the module"""
await utils.answer(
message,
response=self.strings['help']
)
@loader.command(
ru_doc=" — генерация изобраения с использованием StableDiffusion API."
)
async def sdcmd(self, message: Message):
""" — generate an image using StableDiffusion API"""
if not self.config['api_key']:
await utils.answer(
message,
self.strings['key_required']
)
return
await utils.answer(
message,
response=self.strings['drawing']
)
prompt = utils.get_args_raw(message)
url = "https://stablediffusionapi.com/api/v3/dreambooth"
payload = json.dumps({
"key": self.config['api_key'],
"model_id": self.config['model'],
"prompt": prompt,
"negative_prompt": self.config['bad_prompt'],
"width": "512",
"height": "512",
"samples": self.config['samples'],
"num_inference_steps": self.config['steps'],
"safety_checker": "no",
"enhance_prompt": "yes",
"seed": None,
"guidance_scale": 7.5,
"multi_lingual": "no",
"panorama": "no",
"self_attention": "no",
"upscale": "yes" if self.config['upscale'] else "no",
"embeddings": "embeddings_model_id",
"lora": "lora_model_id",
"webhook": None,
"track_id": None
})
headers = {
"Content-Type": "application/json"
}
r = (await utils.run_sync(requests.post, url, headers=headers, data=payload)).json()
if r.get('status') == "error":
await utils.answer(
message,
response=self.strings['error'].format(r)
)
return
if r.get('output'):
out = self.strings['done']
if self.config['debug']:
out += self.strings['debug'].format(
model=r['meta']['model_id'],
prompt=r['meta']['prompt'],
negative=r['meta']['negative_prompt'],
steps=r['meta']['steps'],
upsc=self.strings['not'] if not self.config['upscale'] else "",
time=f", {round(r['generationTime'], 2)}s"
)
imgs = []
for i in r['output']:
img = (await utils.run_sync(
requests.get,
i
)).content
imgs.append(img)
await utils.answer_file(
message,
file=imgs,
caption=out
)
elif r.get('status') == "processing":
out = self.strings['done']
if self.config['debug']:
out += self.strings['debug'].format(
model=r['meta']['model_id'],
prompt=r['meta']['prompt'],
negative=r['meta']['negative_prompt'],
steps=r['meta']['steps'],
upsc=self.strings['not'] if not self.config['upscale'] else "",
time=""
)
rr = await self.getFetch(r)
imgs = []
for i in rr['output']:
img = (await utils.run_sync(
requests.get,
i
)).content
imgs.append(img)
await utils.answer_file(
message,
file=imgs,
caption=out
)
else:
await utils.answer(
message,
response=self.strings['error'].format(r)
)