lunarflu HF Staff commited on
Commit
54389af
·
1 Parent(s): cd3f2d7

[dfif stable revert] run_in_executor added for jojo

Browse files
Files changed (1) hide show
  1. app.py +473 -0
app.py CHANGED
@@ -160,3 +160,476 @@ async def main():
160
  print('default thread pool', exeresult)
161
 
162
  '''
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  print('default thread pool', exeresult)
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
+ import discord
189
+ import os
190
+ import threading
191
+ import gradio as gr
192
+ import requests
193
+ import json
194
+ import random
195
+ import time
196
+ import re
197
+ from discord import Embed, Color
198
+ from discord.ext import commands
199
+ # test # fix? # unstick # fix
200
+ from gradio_client import Client
201
+ from PIL import Image
202
+ #from ratelimiter import RateLimiter
203
+
204
+ import asyncio
205
+ import concurrent.futures
206
+ import multiprocessing
207
+
208
+ import shutil # for doing image movement magic
209
+
210
+ #todo
211
+ # 4 -> combined image
212
+ # loading emoji? animated emojis?
213
+ # make success / fail emojis more consistent across both painter + dfif
214
+ # tasks for concurrent coroutines
215
+ # ratelimits
216
+
217
+ # enlarge each of 4 images?
218
+ # Error: [Errno 104] Connection reset by peer?
219
+
220
+ # clean up old threads
221
+ # safety for on_reaction_add?
222
+ # could use one channel, use threads to organize it. Otherwise may be too split and harder to keep track of
223
+ # lock generation after ~120s, can change
224
+ # restructure using slash commands? generate -> deepfloydif -> prompt -> thread -> combined -> upscale -> thread
225
+
226
+ DFIF_TOKEN = os.getenv('HF_TOKEN')
227
+ DISCORD_TOKEN = os.environ.get("GRADIOTEST_TOKEN", None)
228
+
229
+ df = Client("huggingface-projects/IF", DFIF_TOKEN)
230
+ jojogan = Client("akhaliq/JoJoGAN", DFIF_TOKEN)
231
+
232
+
233
+ intents = discord.Intents.default()
234
+ intents.message_content = True
235
+
236
+ bot = commands.Bot(command_prefix='!', intents=intents)
237
+
238
+
239
+ #---------------------------------------------------------------------------------------------------------------------------------------------
240
+ @bot.event
241
+ async def on_ready():
242
+ print('Logged on as', bot.user)
243
+ bot.log_channel = bot.get_channel(1100458786826747945) # 1100458786826747945 = bot-test, 1107006391547342910 = lunarbot server
244
+ #---------------------------------------------------------------------------------------------------------------------------------------------
245
+ async def safetychecks(ctx):
246
+ try:
247
+ if ctx.author.bot:
248
+ print(f"Error: The bot is not allowed to use its own commands.")
249
+ return False
250
+
251
+ #✅✅ check if the bot is offline
252
+ offline_bot_role_id = 1103676632667017266
253
+ bot_member = ctx.guild.get_member(bot.user.id)
254
+ if any(role.id == offline_bot_role_id for role in bot_member.roles):
255
+ print(f"Error: The bot is offline or under maintenance. (Remove the offline-bot role to bring it online)")
256
+ return False
257
+
258
+ #✅✅ check if the command is in the allowed channel(s)
259
+ channel_id = 1100458786826747945
260
+ if ctx.channel.id != 1100458786826747945:
261
+ print(f"Error: This is not a permitted channel for that command. (bot-test is the correct channel)")
262
+ return False
263
+
264
+ #✅✅ check if the user has the required role(s)
265
+ guild_id = 879548962464493619
266
+ required_role_id = 900063512829755413 # @verified for now
267
+ guild = bot.get_guild(guild_id)
268
+ required_role = guild.get_role(required_role_id)
269
+ if required_role not in ctx.author.roles:
270
+ print(f"Error: The user does not have the required role to use that command. ({required_role} is the correct role)")
271
+ return False
272
+
273
+ return True
274
+
275
+ except Exception as e:
276
+ print(f"Error: safetychecks failed somewhere, command will not continue.")
277
+ await ctx.message.reply(f"<@811235357663297546> SC failed somewhere") # this will always ping, as long as the bot has access to the channel
278
+ #----------------------------------------------------------------------------------------------------------------------------------------------
279
+ # jojo
280
+ @bot.command()
281
+ async def jojo(ctx):
282
+ # img + face ✅
283
+ # img + no face ✅
284
+ # no image ✅
285
+ # no generation ✅
286
+ # responsive? ✅
287
+ # ratelimits? ❌
288
+ # safety checks?✅
289
+ # bot no crash ✅
290
+ try:
291
+ if await safetychecks(ctx): #✅
292
+ await ctx.message.add_reaction('🤖')
293
+ thread = await ctx.message.create_thread(name=f'{ctx.author} Jojo Thread')
294
+ if ctx.message.attachments:
295
+ await thread.send(f'{ctx.author.mention}Generating images in thread, can take ~1 minute...yare yare, daze ...')
296
+ attachment = ctx.message.attachments[0]
297
+ style = 'JoJo'
298
+ #im = jojogan.predict(attachment.url, style)
299
+ im = await asyncio.get_running_loop().run_in_executor(None, jojogan.predict, attachment.url, style)
300
+ #await ctx.message.reply(f'Here is the {style} version of it', file=discord.File(im))
301
+ await thread.send(f'{ctx.author.mention}Here is the {style} version of it', file=discord.File(im))
302
+ await ctx.message.add_reaction('✅') # img + face
303
+ else: # no image
304
+ await thread.send(f"{ctx.author.mention}No attachments to be found...Can't animify dat! Try sending me an image 😉")
305
+ await ctx.message.add_reaction('❌')
306
+ except Exception as e: # no generation / img + no face
307
+ print(f"Error: {e}")
308
+ await thread.send(f"{ctx.author.mention}Error: {e}")
309
+ await ctx.message.add_reaction('❌')
310
+
311
+ #----------------------------------------------------------------------------------------------------------------------------------------------
312
+ # Disney
313
+ @bot.command()
314
+ async def disney(ctx):
315
+ try:
316
+ if await safetychecks(ctx): #✅
317
+ await ctx.message.add_reaction('🤖')
318
+ thread = await ctx.message.create_thread(name=f'{ctx.author} disney Thread')
319
+ if ctx.message.attachments:
320
+ await thread.send(f'{ctx.author.mention}Generating images in thread, can take ~1 minute...')
321
+ attachment = ctx.message.attachments[0]
322
+ style = 'disney'
323
+ im = await asyncio.get_running_loop().run_in_executor(None, jojogan.predict, attachment.url, style)
324
+ await thread.send(f'{ctx.author.mention}Here is the {style} version of it', file=discord.File(im))
325
+ await ctx.message.add_reaction('✅') # img + face
326
+ else: # no image
327
+ await thread.send(f"{ctx.author.mention}No attachments to be found...Can't animify dat! Try sending me an image 😉")
328
+ await ctx.message.add_reaction('❌')
329
+ except Exception as e: # no generation / img + no face
330
+ print(f"Error: {e}")
331
+ await thread.send(f"{ctx.author.mention}Error: {e}")
332
+ await ctx.message.add_reaction('❌')
333
+
334
+ #----------------------------------------------------------------------------------------------------------------------------------------------
335
+ # Spider-Verse
336
+ @bot.command()
337
+ async def spiderverse(ctx):
338
+ try:
339
+ if await safetychecks(ctx): #✅
340
+ await ctx.message.add_reaction('🤖')
341
+ thread = await ctx.message.create_thread(name=f'{ctx.author} spider-verse Thread')
342
+ if ctx.message.attachments:
343
+ await thread.send(f'{ctx.author.mention}Generating images in thread, can take ~1 minute...')
344
+ attachment = ctx.message.attachments[0]
345
+ style = 'Spider-Verse'
346
+ im = await asyncio.get_running_loop().run_in_executor(None, jojogan.predict, attachment.url, style)
347
+ await thread.send(f'{ctx.author.mention}Here is the {style} version of it', file=discord.File(im))
348
+ await ctx.message.add_reaction('✅') # img + face
349
+ else: # no image
350
+ await thread.send(f"{ctx.author.mention}No attachments to be found...Can't animify dat! Try sending me an image 😉")
351
+ await ctx.message.add_reaction('❌')
352
+ except Exception as e: # no generation / img + no face
353
+ print(f"Error: {e}")
354
+ await thread.send(f"{ctx.author.mention}Error: {e}")
355
+ await ctx.message.add_reaction('❌')
356
+
357
+ #----------------------------------------------------------------------------------------------------------------------------------------------
358
+ # sketch
359
+ @bot.command()
360
+ async def sketch(ctx):
361
+ try:
362
+ if await safetychecks(ctx): #✅
363
+ await ctx.message.add_reaction('🤖')
364
+ thread = await ctx.message.create_thread(name=f'{ctx.author} sketch Thread')
365
+ if ctx.message.attachments:
366
+ await thread.send(f'{ctx.author.mention}Generating images in thread, can take ~1 minute...')
367
+ attachment = ctx.message.attachments[0]
368
+ style = 'sketch'
369
+ im = await asyncio.get_running_loop().run_in_executor(None, jojogan.predict, attachment.url, style)
370
+ await thread.send(f'{ctx.author.mention}Here is the {style} version of it', file=discord.File(im))
371
+ await ctx.message.add_reaction('✅') # img + face
372
+ else: # no image
373
+ await thread.send(f"{ctx.author.mention}No attachments to be found...Can't animify dat! Try sending me an image 😉")
374
+ await ctx.message.add_reaction('❌')
375
+ except Exception as e: # no generation / img + no face
376
+ print(f"Error: {e}")
377
+ await thread.send(f"{ctx.author.mention}Error: {e}")
378
+ await ctx.message.add_reaction('❌')
379
+ #----------------------------------------------------------------------------------------------------------------------------------------------
380
+ # Stage 1
381
+ @bot.command()
382
+ async def deepfloydif(ctx, *, prompt: str):
383
+ try:
384
+ try:
385
+ if await safetychecks(ctx): #✅
386
+ await ctx.message.add_reaction('🤖') # loading emoji?
387
+ dfif_command_message_id = ctx.message.id # we will use this in some magic later on
388
+ thread = await ctx.message.create_thread(name=f'{ctx.author} DeepfloydIF Image Upscaling Thread ')
389
+ # create thread -> send new message inside thread + combined_image -> add reactions -> dfif2
390
+
391
+ #current_time = int(time.time())
392
+ #random.seed(current_time)
393
+
394
+ negative_prompt = ''
395
+ seed = random.randint(0, 1000)
396
+ #seed = 1
397
+ number_of_images = 4
398
+ guidance_scale = 7
399
+ custom_timesteps_1 = 'smart50'
400
+ number_of_inference_steps = 50
401
+
402
+ await thread.send(f'{ctx.author.mention}Generating images in thread, can take ~1 minute...')
403
+
404
+ except Exception as e:
405
+ print(f"Error: {e}")
406
+ await ctx.reply('stage 1 error -> pre generation')
407
+ await ctx.message.add_reaction('❌')
408
+
409
+ try:
410
+ stage_1_results, stage_1_param_path, stage_1_result_path = df.predict(
411
+ prompt, negative_prompt, seed, number_of_images, guidance_scale, custom_timesteps_1, number_of_inference_steps, api_name='/generate64')
412
+
413
+ partialpath = stage_1_result_path[5:] #magic for later
414
+ except Exception as e:
415
+ print(f"Error: {e}")
416
+ await ctx.reply('stage 1 error -> during generation')
417
+ await ctx.message.add_reaction('❌')
418
+
419
+ try:
420
+ png_files = [f for f in os.listdir(stage_1_results) if f.endswith('.png')]
421
+
422
+ if png_files:
423
+ first_png = png_files[0]
424
+ second_png = png_files[1]
425
+ third_png = png_files[2]
426
+ fourth_png = png_files[3]
427
+
428
+ first_png_path = os.path.join(stage_1_results, first_png)
429
+ second_png_path = os.path.join(stage_1_results, second_png)
430
+ third_png_path = os.path.join(stage_1_results, third_png)
431
+ fourth_png_path = os.path.join(stage_1_results, fourth_png)
432
+
433
+ img1 = Image.open(first_png_path)
434
+ img2 = Image.open(second_png_path)
435
+ img3 = Image.open(third_png_path)
436
+ img4 = Image.open(fourth_png_path)
437
+
438
+ combined_image = Image.new('RGB', (img1.width * 2, img1.height * 2))
439
+
440
+ combined_image.paste(img1, (0, 0))
441
+ combined_image.paste(img2, (img1.width, 0))
442
+ combined_image.paste(img3, (0, img1.height))
443
+ combined_image.paste(img4, (img1.width, img1.height))
444
+
445
+ combined_image_path = os.path.join(stage_1_results, f'{partialpath}{dfif_command_message_id}.png')
446
+ combined_image.save(combined_image_path)
447
+
448
+ with open(combined_image_path, 'rb') as f:
449
+ combined_image_dfif = await thread.send(f'{ctx.author.mention}React with the image number you want to upscale!', file=discord.File(
450
+ f, f'{partialpath}{dfif_command_message_id}.png')) # named something like: tmpgtv4qjix1111269940599738479.png
451
+
452
+ async def react1234(emoji, combined_image_dfif):
453
+ for emoji in ['1️⃣', '2️⃣', '3️⃣', '4️⃣']:
454
+ await combined_image_dfif.add_reaction(emoji)
455
+
456
+ await react1234(emoji, combined_image_dfif)
457
+
458
+ ''' individual images
459
+ if png_files:
460
+ for i, png_file in enumerate(png_files):
461
+ png_file_path = os.path.join(stage_1_results, png_file)
462
+ img = Image.open(png_file_path)
463
+ image_path = os.path.join(stage_1_results, f'{i+1}{partialpath}.png')
464
+ img.save(image_path)
465
+ with open(image_path, 'rb') as f:
466
+ await thread.send(f'{ctx.author.mention}Image {i+1}', file=discord.File(f, f'{i+1}{partialpath}.png'))
467
+ await asyncio.sleep(1)
468
+
469
+ '''
470
+
471
+ except Exception as e:
472
+ print(f"Error: {e}")
473
+ await ctx.reply('stage 1 error -> posting images in thread')
474
+ await ctx.message.add_reaction('❌')
475
+
476
+ #deepfloydif try/except
477
+ except Exception as e:
478
+ print(f"Error: {e}")
479
+ await ctx.reply('An error occurred in stage 1 for deepfloydif')
480
+ await ctx.message.add_reaction('❌')
481
+
482
+ #----------------------------------------------------------------------------------------------------------------------------
483
+ # Stage 2
484
+ async def dfif2(index: int, stage_1_result_path, thread, dfif_command_message_id): # add safetychecks
485
+ try:
486
+ await thread.send(f"inside dfif2, upscaling")
487
+ selected_index_for_stage_2 = index
488
+ seed_2 = 0
489
+ guidance_scale_2 = 4
490
+ custom_timesteps_2 = 'smart50'
491
+ number_of_inference_steps_2 = 50
492
+ result_path = df.predict(stage_1_result_path, selected_index_for_stage_2, seed_2,
493
+ guidance_scale_2, custom_timesteps_2, number_of_inference_steps_2, api_name='/upscale256')
494
+
495
+ await thread.send(f"upscale done")
496
+ with open(result_path, 'rb') as f:
497
+ await thread.send(f'Here is the upscaled image! :) ', file=discord.File(f, 'result.png'))
498
+
499
+ # using custom emoji that looks nicer
500
+ emoji_guild = thread.guild
501
+ confirm_emoji_id = 1098629085955113011
502
+ confirm_emoji = discord.utils.get(emoji_guild.emojis, id=confirm_emoji_id)
503
+
504
+ # assuming dfif2 is always inside a thread, we can always exit the thread to find the channel with the original command,
505
+ # which allows us to react confirm on that message.
506
+ parent_channel = thread.parent
507
+ dfif_command_message = await parent_channel.fetch_message(dfif_command_message_id)
508
+
509
+ # reacting to original !deepfloydif command + using a custom emoji to do it
510
+ await dfif_command_message.add_reaction(confirm_emoji)
511
+ await thread.send(f"upscale posted")
512
+ #await ctx.reply('Here is the result of the second stage', file=discord.File(f, 'result.png'))
513
+ #await ctx.message.add_reaction('✅') need to fix this
514
+
515
+ '''
516
+ try:
517
+ dfif_command_message = await channel.fetch_message(dfif_command_message_id)
518
+ await dfif_command_message.add_reaction('✅')
519
+ '''
520
+
521
+ except Exception as e:
522
+ print(f"Error: {e}")
523
+
524
+ #await ctx.reply('An error occured in stage 2') need to fix
525
+ #await ctx.message.add_reaction('❌')
526
+ #----------------------------------------------------------------------------------------------------------------------------
527
+ @bot.event
528
+ async def on_reaction_add(reaction, user): # ctx = await bot.get_context(reaction.message)? could try later, might simplify
529
+ try:
530
+ # safety checks first ❌
531
+ '''
532
+ if user.bot:
533
+ return
534
+
535
+ #offline bot check ❌
536
+ offline_bot_role_id = 1103676632667017266
537
+ bot_member = reaction.message.guild.get_member(bot.user.id)
538
+ if any(role.id == offline_bot_role_id for role in bot_member.roles):
539
+ return
540
+
541
+ # verified role check ❌
542
+ guild = reaction.message.guild
543
+ required_role_id = 900063512829755413 # @verified for now
544
+ required_role = guild.get_role(required_role_id)
545
+ if required_role not in user.roles:
546
+ return
547
+
548
+ #channel check ❌
549
+ if reaction.message.channel.id != 1100458786826747945:
550
+ return
551
+
552
+ '''
553
+
554
+ thread = reaction.message.channel
555
+ threadparentid = thread.parent.id
556
+
557
+ if not user.bot:
558
+ if threadparentid == 1100458786826747945: # bot-test
559
+ # 811235357663297546 = lunarflu
560
+ if reaction.message.attachments:
561
+ if user.id == reaction.message.mentions[0].id: # if user.id == reaction.message.mentions[0].id:
562
+ # magic begins
563
+ await reaction.message.channel.send("reaction detected")
564
+ attachment = reaction.message.attachments[0]
565
+ image_name = attachment.filename # named something like: tmpgtv4qjix1111269940599738479.png
566
+ # remove .png first
567
+ partialpathmessageid = image_name[:-4] # should be tmpgtv4qjix1111269940599738479
568
+ # extract partialpath, messageid
569
+ partialpath = partialpathmessageid[:11] # tmpgtv4qjix
570
+ messageid = partialpathmessageid[11:] # 1111269940599738479
571
+ # add /tmp/ to partialpath, save as new variable
572
+ fullpath = "/tmp/" + partialpath # should be /tmp/tmpgtv4qjix
573
+ await reaction.message.channel.send(f"fullpath extracted, {fullpath}")
574
+ emoji = reaction.emoji
575
+
576
+ if emoji == "1️⃣":
577
+ index = 0
578
+ elif emoji == "2️⃣":
579
+ index = 1
580
+ elif emoji == "3️⃣":
581
+ index = 2
582
+ elif emoji == "4️⃣":
583
+ index = 3
584
+
585
+ await reaction.message.channel.send(f"index extracted, {index}")
586
+ index = index
587
+ stage_1_result_path = fullpath
588
+ thread = reaction.message.channel
589
+ dfif_command_message_id = messageid
590
+ await reaction.message.channel.send(f"calling dfif2")
591
+ await dfif2(index, stage_1_result_path, thread, dfif_command_message_id)
592
+
593
+ '''
594
+
595
+ if reaction.message.attachments:
596
+ if user.id == reaction.message.mentions[0].id: # all we care about is upscaling whatever image this is
597
+
598
+ # magic begins
599
+ attachment = reaction.message.attachments[0]
600
+ image_name = attachment.filename
601
+ # we know image_name will be something like 1tmpgtv4qjix.png
602
+ # remove .png first
603
+ indexpartialpath = image_name[:-4] # should be 1tmpgtv4qjix
604
+ # extract index as an integer (dfif2 needs integer)
605
+ index = int(indexpartialpath[0]) - 1# should be 1
606
+ # extract partialpath
607
+ partialpath = indexpartialpath[1:] # should be tmpgtv4qjix
608
+ # add /tmp/ to partialpath, save as new variable
609
+ fullpath = "/tmp/" + partialpath # should be /tmp/tmpgtv4qjix
610
+
611
+ stage_1_result_path = fullpath
612
+ index = index
613
+ await dfif2(index, stage_1_result_path, thread)
614
+
615
+ '''
616
+
617
+
618
+ except Exception as e:
619
+ print(f"Error: {e}")
620
+
621
+ #await ctx.reply('An error occured in stage 2') need to fix
622
+ #await ctx.message.add_reaction('❌')
623
+ #----------------------------------------------------------------------------------------------------------------------------
624
+
625
+
626
+ def run_bot():
627
+ bot.run(DISCORD_TOKEN)
628
+
629
+ threading.Thread(target=run_bot).start()
630
+
631
+ def greet(name):
632
+ return "Hello " + name + "!"
633
+
634
+ demo = gr.Interface(fn=greet, inputs="text", outputs="text")
635
+ demo.launch()