diff --git a/.gitignore b/.gitignore index 6ede31e..b7d9569 100644 --- a/.gitignore +++ b/.gitignore @@ -112,3 +112,5 @@ node_modules/ settings.py *.session *.session-journal +tmp.png +secrets.py diff --git a/dreamer.py b/dreamer.py new file mode 100644 index 0000000..3fdc81e --- /dev/null +++ b/dreamer.py @@ -0,0 +1,241 @@ +import os, logging +DEBUG = os.environ.get('DEBUG') +logging.basicConfig( + #filename='protovax.log', encoding='utf-8', + format='[%(asctime)s] %(levelname)s %(module)s/%(funcName)s - %(message)s', + level=logging.DEBUG if DEBUG else logging.INFO) + +import requests +import random +import json +import base64 +import time +import re +from io import BytesIO +from telethon import TelegramClient, events + +import secrets + +PROTOSPACE = -1001298858490 +JASON = 172033414 + +client = TelegramClient('data/dreamer.session', secrets.TG_API_ID, secrets.TG_API_HASH) + +def snap_size(size): + VALID_SIZES = [512, 576, 640, 704, 768, 832, 896, 960, 1024] + for s in VALID_SIZES: + if s >= size: + return s + +def dreamer(prompt, steps=30, seed=1234, height=512, width=512): + url = secrets.DREAM_API + + #sd_settings_json = '{"fn_index":12,"data":["","","None","None",30,"Euler a",false,false,1,1,7,-1,-1,0,0,0,false,512,512,false,false,0.7,"None",false,"Seed","","Steps","",true,false,false,null,"",null,"",""],"session_hash":"qpydye2zzsh"}' + sd_settings_json = '{"fn_index":12,"data":["","","None","None",30,"Euler a",false,false,1,1,7,-1,-1,0,0,0,false,512,512,false,false,0.7,"None",false,false,null,"","Seed","","Nothing","",true,false,null,"",""],"session_hash":"qpydye2zzsh"}' + + sd_settings = json.loads(sd_settings_json) + sd_settings['data'][0] = prompt + sd_settings['data'][4] = steps + sd_settings['data'][11] = seed + sd_settings['data'][17] = snap_size(height) + sd_settings['data'][18] = snap_size(width) + + if width > 512 or height > 512: + # highres fix + sd_settings['data'][19] = True + + logging.info('Dreaming of: %s', prompt) + + try: + res = requests.post(url, json=sd_settings, timeout=40) + res.raise_for_status() + res = res.json() + return res + except BaseException as e: + logging.error('Problem dreaming {}: {} - {}'.format(url, e.__class__.__name__, str(e))) + return None + +async def message_handler(event): + text = event.raw_text + chat = event.chat_id + + sender = await event.get_sender() + if not event.sender: + return + + if event.message.fwd_from: + return + + name = getattr(sender, 'first_name', None) + if not name: + return + + command = '' + data = '' + reply = '' + reply_file = None + + if text.startswith('! '): + text = text[2:] + elif text.startswith('!'): + text = text[1:] + else: + return + + if ' ' in text: + command = text.split(' ', 1)[0] + data = text.split(' ', 1)[1] + else: + command = text + + command = command.lower() + + + #!dream + if command == 'dream': + logging.info('Chat: {:<14} | ID: {:<6} | User: {} {} | Command: {} | Data: {}'.format(chat, event.id, name, sender.id, command, data or 'None')) + + if not reply and chat == PROTOSPACE: + reply = '> please join {} to dream'.format(secrets.PROTODREAM_URL) + + #if not reply and sender.id == JASON: + # reply = '> no.' + + to_send = '' + if not reply and data: + to_send = data + + if not reply and not to_send and event.message.is_reply: + reply_msg = await event.get_reply_message() + to_send = reply_msg.raw_text + + if not reply and '> ' in to_send: + reply = '> sounds like a bad !dream' + + if not reply and len(to_send) > 500: + reply = '> impressive. very nice. let\'s see Paul Allen\'s prompt.' + + if not reply and not to_send: + reply = '> usage: !dream [prompt] [options]' + reply += '\n> or reply to a someone with !dream' + reply += '\n> default options:' + reply += '\n> steps:30 (20-40)' + reply += '\n> height:512 (512-1024)' + reply += '\n> width:512 (512-1024)' + reply += '\n> seed:number' + reply += '\n> favourites: https://t.me/+UyMF3ArBe4pmYzQ5' + + if not reply: + settings = { + 'steps': 30, + 'height': 512, + 'width': 512, + 'seed': random.randint(11111, 19999), + } + + maximums = { + 'steps': 40, + 'height': 1024, + 'width': 1024, + } + + minimums = { + 'steps': 20, + 'height': 512, + 'width': 512, + } + + for match in re.findall('((\w+)[:=](\d+))', to_send): + whole = match[0] + setting = match[1] + value = int(match[2]) + + to_send = to_send.replace(whole, '').replace(' ', ' ') + + if setting in maximums and value > maximums[setting]: + reply = '> {} should be <= {}'.format(setting, maximums[setting]) + break + + if setting in minimums and value < minimums[setting]: + reply = '> {} should be >= {}'.format(setting, minimums[setting]) + break + + if setting in settings: + settings[setting] = value + + + if not reply: + try: + to_send = to_send.replace('@', '') + to_send = to_send.replace('!', '') + to_send = to_send.strip() + prompt = to_send + + if len(str(settings['seed'])) == 4: + enhancements1 = [ + ', fantasy, intricate, elegant, digital painting, concept art, sharp focus, illustration by greg rutkowski, 4k', + ', synthwave style, artstation, detailed, award winning, dramatic lighting, miami vice, oil on canvas', + ', highly detailed painting by dustin nguyen, akihiko yoshida, greg tocchini, 4 k, trending on artstation, 8 k', + ', cinematic lighting, insanely detailed, intricate, artstation, cgsociety, painted by simon stalenhag, concept art, illustration, sharp focus', + ', photorealistic, highly detailed, illustration, lifelike, highly detailed, intricate, octane render, sharp focus, cyberpunk', + ', by ghibli, makoto shinkai, bright and transparent animation style, anime art wallpaper 4 k, trending on artstation', + ', painterly, sharp focus, illustration, art by lois royo', + ', in the style of gta cover art, by stephen bliss, trending on artstation, pixiv, 8 k', + ', d & d, fantasy concept art, octane render, 8 k', + ', peter mohrbacher, charlie bowater, artstation, craig mullins, cinematic, digital painting, deviantart, cinematic lighting, 4 k', + ', tristan eaton, victo ngai, maxfield parrish, artgerm, koons, ryden, intricated details', + ', by soul bass, kawase hasui, moebius and edward hopper, colorful flat surreal design, xray hd, 8 k', + ', manga cover art, detailed color portrait, artstation trending, 8 k', + ', a hacker hologram by penny patricia poppycock, pixabay contest winner, holography, irridescent, photoillustration, maximalist vaporwave - n 9', + ', breathtaking, epic, stunning, gorgeous, much detail, much wow, cgsociety, wlop, pixiv, behance, deviantart, masterpiece', + ', sharp focus, dynamic lighting, elegant, harmony, beauty, masterpiece, by roberto ferry, illustration, blue background', + ', ultradetailed environment, sharp focus, cinematic lighting, by alphonse maria mucha and kim jung gi', + ', concept art by jama jurabaev, cinematic shot, trending on artstation, high quality, brush stroke, hyperspace, vibrant colors', + ', hyper detailed, sharp focus, bokeh, unreal engine, ray tracing, cute, fantasy, sci fi, purple lights, tiny, small', + ', fancy, ultra detailed, brush strokes, digital painting, cinematic, yoshitaka amano, andy warhol, ultra realistic', + ', by tsuyoshi nagano, illustration, cinematic lighting, hyperdetailed, 8 k, symmetrical, frostbite 3 engine, cryengine, dof, trending on artstation, digital art, crepuscular ray', + ', retrowave, tonal separation, black background, neon, black, glitch, strong contrast, pinterest, trending on artstation', + ', basic background, krenz cushart, mucha, ghibli, by joaquin sorolla rhads leyendecker, by ohara koson', + ] + + if ',' not in prompt: + prompt += enhancements1[settings['seed'] % len(enhancements1)] + elif str(settings['seed'])[0] == '1': + pass + + start = time.time() + dream_res = dreamer(prompt, **settings) + finish = time.time() + + url_enc = dream_res['data'][0][0] + b64_str = url_enc[22:] + + reply_file = base64.decodebytes(bytes(b64_str, 'utf-8')) + + latency = finish - start + reply = '> generated "{}" for {} in {} s with seed:{} steps:{}'.format( + to_send, + name, + str(latency)[:3], + settings['seed'], + settings['steps'] + ) + + except BaseException as e: + logging.exception(e) + reply = '> error' + + await event.reply(reply, file=reply_file, link_preview=False) + + +@client.on(events.MessageEdited) +async def message_edited(event): + await message_handler(event) + +@client.on(events.NewMessage) +async def new_message(event): + await message_handler(event) + + +client.start() +client.run_until_disconnected() diff --git a/secrets.py.example b/secrets.py.example new file mode 100644 index 0000000..7244ce1 --- /dev/null +++ b/secrets.py.example @@ -0,0 +1,6 @@ +TG_API_ID = '' +TG_API_HASH = '' + +DREAM_API = '' + +PROTODREAM_URL = ''