Merge pull request #28 from skygpu/discord-upate

Discord update
telos_testnet
Guillermo Rodriguez 2024-11-27 13:20:27 -03:00 committed by GitHub
commit 99fe66135e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 100 additions and 72 deletions

View File

@ -453,7 +453,12 @@ def discord(
node_url = load_key(config, 'skynet.discord.node_url')
hyperion_url = load_key(config, 'skynet.discord.hyperion_url')
ipfs_gateway_url = load_key(config, 'skynet.discord.ipfs_gateway_url')
try:
ipfs_gateway_url = load_key(config, 'skynet.discord.ipfs_gateway_url')
except ConfigParsingError:
ipfs_gateway_url = None
ipfs_url = load_key(config, 'skynet.discord.ipfs_url')
try:

View File

@ -17,7 +17,9 @@ from leap.hyperion import HyperionAPI
# from telebot.types import InputMediaPhoto
import discord
import requests
import io
from PIL import Image, UnidentifiedImageError
from skynet.db import open_database_connection
from skynet.ipfs import get_ipfs_file, AsyncIPFSHTTP
@ -66,7 +68,7 @@ class SkynetDiscordFrontend:
self.bot = DiscordBot(self)
self.cleos = CLEOS(None, None, url=node_url, remote=node_url)
self.hyperion = HyperionAPI(hyperion_url)
self.ipfs_node = AsyncIPFSHTTP(ipfs_node)
self.ipfs_node = AsyncIPFSHTTP(ipfs_url)
self._exit_stack = ExitStack()
self._async_exit_stack = AsyncExitStack()
@ -234,7 +236,7 @@ class SkynetDiscordFrontend:
await message.edit(embed=embed)
return False
tx_link = f'[**Your result on Skynet Explorer**](https://explorer.{DEFAULT_DOMAIN}/v2/explore/transaction/{tx_hash})'
tx_link = f'[**Your result on Skynet Explorer**](https://{self.explorer_domain}/v2/explore/transaction/{tx_hash})'
msg_text += f'**request processed!**\n{tx_link}\n[{timestamp_pretty()}] *trying to download image...*\n '
embed = discord.Embed(
@ -264,7 +266,8 @@ class SkynetDiscordFrontend:
results[link] = png_img
except UnidentifiedImageError:
logging.warning(f'couldn\'t get ipfs binary data at {link}!')
logging.warning(
f'couldn\'t get ipfs binary data at {link}!')
tasks = [
get_and_set_results(ipfs_link),
@ -280,32 +283,35 @@ class SkynetDiscordFrontend:
png_img = results[ipfs_link]
if not png_img:
await self.update_status_message(
status_msg,
caption,
reply_markup=build_redo_menu(),
parse_mode='HTML'
)
logging.error(f'couldn\'t get ipfs hosted image at {ipfs_link}!')
embed.add_field(
name='Error', value=f'couldn\'t get ipfs hosted image [**here**]({ipfs_link})!')
await message.edit(embed=embed, view=SkynetView(self))
return True
# reword this function, may not need caption
caption, embed = generate_reply_caption(
user, params, tx_hash, worker, reward)
user, params, tx_hash, worker, reward, self.explorer_domain)
if not resp or resp.status_code != 200:
logging.error(f'couldn\'t get ipfs hosted image at {ipfs_link}!')
embed.add_field(name='Error', value=f'couldn\'t get ipfs hosted image [**here**]({ipfs_link})!')
await message.edit(embed=embed, view=SkynetView(self))
else:
logging.info(f'success! sending generated image')
await message.delete()
if file_id: # img2img
embed.set_thumbnail(
url='https://ipfs.skygpu.net/ipfs/' + binary_data + '/image.png')
embed.set_image(url=ipfs_link)
await send(embed=embed, view=SkynetView(self))
else: # txt2img
embed.set_image(url=ipfs_link)
logging.info(f'success! sending generated image')
await message.delete()
if file_id: # img2img
embed.set_image(url=ipfs_link)
orig_url = f'https://{self.ipfs_domain}/ipfs/' + binary_data
res = requests.get(orig_url, stream=True)
if res.status_code == 200:
with io.BytesIO(res.content) as img:
file = discord.File(img, filename='image.png')
embed.set_thumbnail(url='attachment://image.png')
await send(embed=embed, view=SkynetView(self), file=file)
# orig_url = f'https://{self.ipfs_domain}/ipfs/' \
# + binary_data + '/image.png'
# embed.set_thumbnail(
# url=orig_url)
else:
await send(embed=embed, view=SkynetView(self))
else: # txt2img
embed.set_image(url=ipfs_link)
await send(embed=embed, view=SkynetView(self))
return True

View File

@ -44,7 +44,7 @@ class DiscordBot(commands.Bot):
await channel.send('Skynet bot online', view=SkynetView(self.bot))
# intro_msg = await channel.send('Welcome to the Skynet discord bot.\nSkynet is a decentralized compute layer, focused on supporting AI paradigms. Skynet leverages blockchain technology to manage work requests and fills. We are currently featuring image generation and support 11 different models. Get started with the /help command, or just click on some buttons. Here is an example command to generate an image:\n/txt2img a big red tractor in a giant field of corn')
intro_msg = await channel.send("Welcome to Skynet's Discord Bot,\n\nSkynet operates as a decentralized compute layer, offering a wide array of support for diverse AI paradigms through the use of blockchain technology. Our present focus is image generation, powered by 11 distinct models.\n\nTo begin exploring, use the '/help' command or directly interact with the provided buttons. Here is an example command to generate an image:\n\n'/txt2img a big red tractor in a giant field of corn'")
await intro_msg.pin()
# await intro_msg.pin()
print("\n==============")
print("Logged in as")

View File

@ -42,6 +42,7 @@ def create_handler_context(frontend: 'SkynetDiscordFrontend'):
await ctx.reply(content=reply_txt, view=SkynetView(frontend))
bot.remove_command('help')
@bot.command(name='help', help='Responds with a help')
async def help(ctx):
splt_msg = ctx.message.content.split(' ')
@ -62,7 +63,7 @@ def create_handler_context(frontend: 'SkynetDiscordFrontend'):
clean_cool_word = '\n'.join(CLEAN_COOL_WORDS)
await ctx.send(content=f'```{clean_cool_word}```', view=SkynetView(frontend))
@bot.command(name='stats', help='See user statistics' )
@bot.command(name='stats', help='See user statistics')
async def user_stats(ctx):
user = ctx.author
@ -96,9 +97,8 @@ def create_handler_context(frontend: 'SkynetDiscordFrontend'):
prompt = ' '.join(ctx.message.content.split(' ')[1:])
if len(prompt) == 0:
await status_msg.edit(content=
'Empty text prompt ignored.'
)
await status_msg.edit(content='Empty text prompt ignored.'
)
await db_call('update_user_request', status_msg.id, 'Empty text prompt ignored.')
return
@ -209,14 +209,23 @@ def create_handler_context(frontend: 'SkynetDiscordFrontend'):
file_id = str(file.id)
# file bytes
image_raw = await file.read()
user_config = {**user_row}
del user_config['id']
with Image.open(io.BytesIO(image_raw)) as image:
w, h = image.size
if w > 512 or h > 512:
if w > user_config['width'] or h > user_config['height']:
logging.warning(f'user sent img of size {image.size}')
image.thumbnail((512, 512))
image.thumbnail(
(user_config['width'], user_config['height']))
logging.warning(f'resized it to {image.size}')
# if w > 512 or h > 512:
# logging.warning(f'user sent img of size {image.size}')
# image.thumbnail((512, 512))
# logging.warning(f'resized it to {image.size}')
# image.save(f'ipfs-docker-staging/image.png', format='PNG')
image_loc = 'ipfs-staging/image.png'
image.save(image_loc, format='PNG')
@ -228,9 +237,6 @@ def create_handler_context(frontend: 'SkynetDiscordFrontend'):
logging.info(f'mid: {ctx.message.id}')
user_config = {**user_row}
del user_config['id']
params = {
'prompt': prompt,
**user_config
@ -240,8 +246,8 @@ def create_handler_context(frontend: 'SkynetDiscordFrontend'):
'update_user_stats',
user.id,
'img2img',
last_file=file_id,
last_prompt=prompt,
last_file=file_id,
last_binary=ipfs_hash
)
@ -254,8 +260,6 @@ def create_handler_context(frontend: 'SkynetDiscordFrontend'):
if success:
await db_call('increment_generated', user.id)
# TODO: DELETE BELOW
# user = 'testworker3'
# status_msg = 'status'
@ -314,7 +318,6 @@ def create_handler_context(frontend: 'SkynetDiscordFrontend'):
# await bot.reply_to(
# message, f'Total requests on skynet queue: {len(queue)}')
# @bot.message_handler(commands=['config'])
# async def set_config(message):
# user = message.from_user.id
@ -361,7 +364,6 @@ def create_handler_context(frontend: 'SkynetDiscordFrontend'):
#
# await bot.send_message(GROUP_ID, message.text[4:])
# generic txt2img handler
# async def _generic_txt2img(message_or_query):
@ -562,7 +564,6 @@ def create_handler_context(frontend: 'SkynetDiscordFrontend'):
# binary_data=binary
# )
# "proxy" handlers just request routers
# @bot.message_handler(commands=['txt2img'])
@ -594,7 +595,6 @@ def create_handler_context(frontend: 'SkynetDiscordFrontend'):
# case 'redo':
# await _redo(call)
# catch all handler for things we dont support
# @bot.message_handler(func=lambda message: True)

View File

@ -11,14 +11,22 @@ class SkynetView(discord.ui.View):
def __init__(self, bot):
self.bot = bot
super().__init__(timeout=None)
self.add_item(RedoButton('redo', discord.ButtonStyle.primary, self.bot))
self.add_item(Txt2ImgButton('txt2img', discord.ButtonStyle.primary, self.bot))
self.add_item(Img2ImgButton('img2img', discord.ButtonStyle.primary, self.bot))
self.add_item(StatsButton('stats', discord.ButtonStyle.secondary, self.bot))
self.add_item(DonateButton('donate', discord.ButtonStyle.secondary, self.bot))
self.add_item(ConfigButton('config', discord.ButtonStyle.secondary, self.bot))
self.add_item(HelpButton('help', discord.ButtonStyle.secondary, self.bot))
self.add_item(CoolButton('cool', discord.ButtonStyle.secondary, self.bot))
self.add_item(RedoButton(
'redo', discord.ButtonStyle.primary, self.bot))
self.add_item(Txt2ImgButton(
'txt2img', discord.ButtonStyle.primary, self.bot))
self.add_item(Img2ImgButton(
'img2img', discord.ButtonStyle.primary, self.bot))
self.add_item(StatsButton(
'stats', discord.ButtonStyle.secondary, self.bot))
self.add_item(DonateButton(
'donate', discord.ButtonStyle.secondary, self.bot))
self.add_item(ConfigButton(
'config', discord.ButtonStyle.secondary, self.bot))
self.add_item(HelpButton(
'help', discord.ButtonStyle.secondary, self.bot))
self.add_item(CoolButton(
'cool', discord.ButtonStyle.secondary, self.bot))
class Txt2ImgButton(discord.ui.Button):
@ -44,9 +52,8 @@ class Txt2ImgButton(discord.ui.Button):
prompt = msg.content
if len(prompt) == 0:
await status_msg.edit(content=
'Empty text prompt ignored.'
)
await status_msg.edit(content='Empty text prompt ignored.'
)
await db_call('update_user_request', status_msg.id, 'Empty text prompt ignored.')
return
@ -111,26 +118,35 @@ class Img2ImgButton(discord.ui.Button):
file_id = str(file.id)
# file bytes
image_raw = await file.read()
user_config = {**user_row}
del user_config['id']
with Image.open(io.BytesIO(image_raw)) as image:
w, h = image.size
if w > 512 or h > 512:
if w > user_config['width'] or h > user_config['height']:
logging.warning(f'user sent img of size {image.size}')
image.thumbnail((512, 512))
image.thumbnail(
(user_config['width'], user_config['height']))
logging.warning(f'resized it to {image.size}')
image.save(f'ipfs-docker-staging/image.png', format='PNG')
# if w > 512 or h > 512:
# logging.warning(f'user sent img of size {image.size}')
# image.thumbnail((512, 512))
# logging.warning(f'resized it to {image.size}')
# image.save(f'ipfs-docker-staging/image.png', format='PNG')
image_loc = 'ipfs-staging/image.png'
image.save(image_loc, format='PNG')
ipfs_hash = ipfs_node.add('image.png')
ipfs_node.pin(ipfs_hash)
ipfs_info = await ipfs_node.add(image_loc)
ipfs_hash = ipfs_info['Hash']
await ipfs_node.pin(ipfs_hash)
logging.info(f'published input image {ipfs_hash} on ipfs')
logging.info(f'mid: {msg.id}')
user_config = {**user_row}
del user_config['id']
params = {
'prompt': prompt,
**user_config
@ -140,8 +156,8 @@ class Img2ImgButton(discord.ui.Button):
'update_user_stats',
user.id,
'img2img',
last_file=file_id,
last_prompt=prompt,
last_file=file_id,
last_binary=ipfs_hash
)
@ -307,5 +323,3 @@ async def grab(prompt, interaction):
await interaction.response.send_message(prompt, ephemeral=True)
message = await interaction.client.wait_for('message', check=vet)
return message

View File

@ -32,7 +32,8 @@ class SKYExceptionHandler(ExceptionHandler):
def build_redo_menu():
btn_redo = InlineKeyboardButton("Redo", callback_data=json.dumps({'method': 'redo'}))
btn_redo = InlineKeyboardButton(
"Redo", callback_data=json.dumps({'method': 'redo'}))
inline_keyboard = InlineKeyboardMarkup()
inline_keyboard.add(btn_redo)
return inline_keyboard
@ -42,7 +43,7 @@ def prepare_metainfo_caption(user, worker: str, reward: str, meta: dict, embed)
prompt = meta["prompt"]
if len(prompt) > 256:
prompt = prompt[:256]
gen_str = f'generated by {user.name}\n'
gen_str += f'performed by {worker}\n'
gen_str += f'reward: {reward}\n'
@ -69,7 +70,7 @@ def prepare_metainfo_caption(user, worker: str, reward: str, meta: dict, embed)
embed.add_field(name='Parameters', value=f'```{meta_str}```', inline=False)
foot_str = f'Made with Skynet v{VERSION}\n'
foot_str += f'JOIN THE SWARM: https://discord.gg/JYM4YPMgK'
foot_str += f'JOIN THE SWARM: https://discord.gg/PAabjJtZAF'
embed.set_footer(text=foot_str)
@ -89,7 +90,8 @@ def generate_reply_caption(
url=f'https://{explorer_domain}/v2/explore/transaction/{tx_hash}',
color=discord.Color.blue())
meta_info = prepare_metainfo_caption(user, worker, reward, params, explorer_link)
meta_info = prepare_metainfo_caption(
user, worker, reward, params, explorer_link)
# why do we have this?
final_msg = '\n'.join([
@ -98,10 +100,10 @@ def generate_reply_caption(
f'PARAMETER INFO:\n{meta_info}'
])
final_msg = '\n'.join([
# f'***{explorer_link}***',
f'{meta_info}'
])
# final_msg += '\n'.join([
# # f'***{explorer_link}***',
# f'{meta_info}'
# ])
logging.info(final_msg)
@ -112,6 +114,7 @@ async def get_global_config(cleos):
return (await cleos.aget_table(
'gpu.scd', 'gpu.scd', 'config'))[0]
async def get_user_nonce(cleos, user: str):
return (await cleos.aget_table(
'gpu.scd', 'gpu.scd', 'users',