mirror of https://github.com/skygpu/skynet.git
initial discord bot
parent
b48ce8ac3f
commit
7b0c1f0868
|
@ -10,5 +10,6 @@ docker
|
|||
aiohttp
|
||||
psycopg2-binary
|
||||
pyTelegramBotAPI
|
||||
discord.py
|
||||
|
||||
py-leap@git+https://github.com/guilledk/py-leap.git@v0.1a14
|
||||
|
|
|
@ -22,3 +22,14 @@ hyperion_url = https://skynet.ancap.tech
|
|||
ipfs_url = /ip4/169.197.140.154/tcp/4001/p2p/12D3KooWKWogLFNEcNNMKnzU7Snrnuj84RZdMBg3sLiQSQc51oEv
|
||||
|
||||
token = XXXXXXXXXX:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
[skynet.discord]
|
||||
account = discord
|
||||
permission = active
|
||||
key = 5Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
node_url = https://skynet.ancap.tech
|
||||
hyperion_url = https://skynet.ancap.tech
|
||||
ipfs_url = /ip4/169.197.140.154/tcp/4001/p2p/12D3KooWKWogLFNEcNNMKnzU7Snrnuj84RZdMBg3sLiQSQc51oEv
|
||||
|
||||
token = XXXXXXXXXX:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
|
|
@ -24,6 +24,7 @@ from .config import *
|
|||
from .nodeos import open_cleos, open_nodeos
|
||||
from .constants import *
|
||||
from .frontend.telegram import SkynetTelegramFrontend
|
||||
from .frontend.discord import SkynetDiscordFrontend
|
||||
|
||||
|
||||
@click.group()
|
||||
|
@ -43,7 +44,7 @@ def skynet(*args, **kwargs):
|
|||
@click.option('--seed', '-S', default=None)
|
||||
def txt2img(*args, **kwargs):
|
||||
from . import utils
|
||||
_, hf_token, _ = init_env_from_config()
|
||||
_, hf_token, _, _ = init_env_from_config()
|
||||
utils.txt2img(hf_token, **kwargs)
|
||||
|
||||
@click.command()
|
||||
|
@ -58,7 +59,7 @@ def txt2img(*args, **kwargs):
|
|||
@click.option('--seed', '-S', default=None)
|
||||
def img2img(model, prompt, input, output, strength, guidance, steps, seed):
|
||||
from . import utils
|
||||
_, hf_token, _ = init_env_from_config()
|
||||
_, hf_token, _, _ = init_env_from_config()
|
||||
utils.img2img(
|
||||
hf_token,
|
||||
model=model,
|
||||
|
@ -86,7 +87,7 @@ def upscale(input, output, model):
|
|||
@skynet.command()
|
||||
def download():
|
||||
from . import utils
|
||||
_, hf_token, _ = init_env_from_config()
|
||||
_, hf_token, _, _ = init_env_from_config()
|
||||
utils.download_all_models(hf_token)
|
||||
|
||||
@skynet.command()
|
||||
|
@ -408,7 +409,7 @@ def telegram(
|
|||
):
|
||||
logging.basicConfig(level=loglevel)
|
||||
|
||||
_, _, tg_token = init_env_from_config()
|
||||
_, _, tg_token, _ = init_env_from_config()
|
||||
|
||||
key, account, permission = load_account_info(
|
||||
'telegram', key, account, permission)
|
||||
|
@ -435,6 +436,66 @@ def telegram(
|
|||
asyncio.run(_async_main())
|
||||
|
||||
|
||||
@run.command()
|
||||
@click.option('--loglevel', '-l', default='INFO', help='logging level')
|
||||
@click.option(
|
||||
'--account', '-a', default='discord')
|
||||
@click.option(
|
||||
'--permission', '-p', default='active')
|
||||
@click.option(
|
||||
'--key', '-k', default=None)
|
||||
@click.option(
|
||||
'--hyperion-url', '-y', default=f'https://{DEFAULT_DOMAIN}')
|
||||
@click.option(
|
||||
'--node-url', '-n', default=f'https://{DEFAULT_DOMAIN}')
|
||||
@click.option(
|
||||
'--ipfs-url', '-i', default=DEFAULT_IPFS_REMOTE)
|
||||
@click.option(
|
||||
'--db-host', '-h', default='localhost:5432')
|
||||
@click.option(
|
||||
'--db-user', '-u', default='skynet')
|
||||
@click.option(
|
||||
'--db-pass', '-u', default='password')
|
||||
def discord(
|
||||
loglevel: str,
|
||||
account: str,
|
||||
permission: str,
|
||||
key: str | None,
|
||||
hyperion_url: str,
|
||||
ipfs_url: str,
|
||||
node_url: str,
|
||||
db_host: str,
|
||||
db_user: str,
|
||||
db_pass: str
|
||||
):
|
||||
logging.basicConfig(level=loglevel)
|
||||
|
||||
_, _, _, dc_token = init_env_from_config()
|
||||
|
||||
key, account, permission = load_account_info(
|
||||
'discord', key, account, permission)
|
||||
|
||||
node_url, _, ipfs_url = load_endpoint_info(
|
||||
'discord', node_url, None, None)
|
||||
|
||||
async def _async_main():
|
||||
frontend = SkynetDiscordFrontend(
|
||||
# dc_token,
|
||||
account,
|
||||
permission,
|
||||
node_url,
|
||||
hyperion_url,
|
||||
db_host, db_user, db_pass,
|
||||
remote_ipfs_node=ipfs_url,
|
||||
key=key
|
||||
)
|
||||
|
||||
async with frontend.open():
|
||||
await frontend.bot.start(dc_token)
|
||||
|
||||
asyncio.run(_async_main())
|
||||
|
||||
|
||||
@run.command()
|
||||
@click.option('--loglevel', '-l', default='INFO', help='logging level')
|
||||
@click.option('--name', '-n', default='skynet-ipfs', help='container name')
|
||||
|
|
|
@ -23,6 +23,7 @@ def init_env_from_config(
|
|||
hf_token: str | None = None,
|
||||
hf_home: str | None = None,
|
||||
tg_token: str | None = None,
|
||||
dc_token: str | None = None,
|
||||
file_path=DEFAULT_CONFIG_PATH
|
||||
):
|
||||
config = load_skynet_ini(file_path=file_path)
|
||||
|
@ -52,7 +53,14 @@ def init_env_from_config(
|
|||
if 'token' in sub_config:
|
||||
tg_token = sub_config['token']
|
||||
|
||||
return hf_home, hf_token, tg_token
|
||||
if 'DC_TOKEN' in os.environ:
|
||||
dc_token = os.environ['DC_TOKEN']
|
||||
elif 'skynet.discord' in config:
|
||||
sub_config = config['skynet.discord']
|
||||
if 'token' in sub_config:
|
||||
dc_token = sub_config['token']
|
||||
|
||||
return hf_home, hf_token, tg_token, dc_token
|
||||
|
||||
|
||||
def load_account_info(
|
||||
|
|
|
@ -0,0 +1,280 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from json import JSONDecodeError
|
||||
import random
|
||||
import logging
|
||||
import asyncio
|
||||
|
||||
from decimal import Decimal
|
||||
from hashlib import sha256
|
||||
from datetime import datetime
|
||||
from contextlib import ExitStack, AsyncExitStack
|
||||
from contextlib import asynccontextmanager as acm
|
||||
|
||||
from leap.cleos import CLEOS
|
||||
from leap.sugar import Name, asset_from_str, collect_stdout
|
||||
from leap.hyperion import HyperionAPI
|
||||
# from telebot.types import InputMediaPhoto
|
||||
|
||||
# import discord
|
||||
|
||||
from skynet.db import open_new_database, open_database_connection
|
||||
from skynet.ipfs import get_ipfs_file
|
||||
from skynet.ipfs.docker import open_ipfs_node
|
||||
from skynet.constants import *
|
||||
|
||||
from . import *
|
||||
from .bot import DiscordBot
|
||||
|
||||
from .utils import *
|
||||
from .handlers import create_handler_context
|
||||
|
||||
|
||||
class SkynetDiscordFrontend:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
token: str,
|
||||
account: str,
|
||||
permission: str,
|
||||
node_url: str,
|
||||
hyperion_url: str,
|
||||
db_host: str,
|
||||
db_user: str,
|
||||
# db_pass: str,
|
||||
remote_ipfs_node: str,
|
||||
key: str
|
||||
):
|
||||
self.token = token
|
||||
self.account = account
|
||||
self.permission = permission
|
||||
self.node_url = node_url
|
||||
self.hyperion_url = hyperion_url
|
||||
self.db_host = db_host
|
||||
self.db_user = db_user
|
||||
# self.db_pass = db_pass
|
||||
self.remote_ipfs_node = remote_ipfs_node
|
||||
self.key = key
|
||||
|
||||
self.bot = DiscordBot()
|
||||
self.cleos = CLEOS(None, None, url=node_url, remote=node_url)
|
||||
self.hyperion = HyperionAPI(hyperion_url)
|
||||
|
||||
self._exit_stack = ExitStack()
|
||||
self._async_exit_stack = AsyncExitStack()
|
||||
|
||||
async def start(self):
|
||||
self.ipfs_node = self._exit_stack.enter_context(
|
||||
open_ipfs_node())
|
||||
|
||||
self.ipfs_node.connect(self.remote_ipfs_node)
|
||||
logging.info(
|
||||
f'connected to remote ipfs node: {self.remote_ipfs_node}')
|
||||
|
||||
# self.db_call = await self._async_exit_stack.enter_async_context(
|
||||
# open_database_connection(
|
||||
# self.db_user, self.db_pass, self.db_host))
|
||||
|
||||
create_handler_context(self)
|
||||
|
||||
async def stop(self):
|
||||
await self._async_exit_stack.aclose()
|
||||
self._exit_stack.close()
|
||||
|
||||
@acm
|
||||
async def open(self):
|
||||
await self.start()
|
||||
yield self
|
||||
await self.stop()
|
||||
|
||||
# async def update_status_message(
|
||||
# self, status_msg, new_text: str, **kwargs
|
||||
# ):
|
||||
# await self.db_call(
|
||||
# 'update_user_request_by_sid', status_msg.id, new_text)
|
||||
# return await self.bot.edit_message_text(
|
||||
# new_text,
|
||||
# chat_id=status_msg.chat.id,
|
||||
# message_id=status_msg.id,
|
||||
# **kwargs
|
||||
# )
|
||||
|
||||
# async def append_status_message(
|
||||
# self, status_msg, add_text: str, **kwargs
|
||||
# ):
|
||||
# request = await self.db_call('get_user_request_by_sid', status_msg.id)
|
||||
# await self.update_status_message(
|
||||
# status_msg,
|
||||
# request['status'] + add_text,
|
||||
# **kwargs
|
||||
# )
|
||||
|
||||
async def work_request(
|
||||
self,
|
||||
user,
|
||||
status_msg,
|
||||
method: str,
|
||||
params: dict,
|
||||
file_id: str | None = None,
|
||||
binary_data: str = ''
|
||||
):
|
||||
if params['seed'] == None:
|
||||
params['seed'] = random.randint(0, 0xFFFFFFFF)
|
||||
|
||||
sanitized_params = {}
|
||||
for key, val in params.items():
|
||||
if isinstance(val, Decimal):
|
||||
val = str(val)
|
||||
|
||||
sanitized_params[key] = val
|
||||
|
||||
body = json.dumps({
|
||||
'method': 'diffuse',
|
||||
'params': sanitized_params
|
||||
})
|
||||
request_time = datetime.now().isoformat()
|
||||
|
||||
# await self.update_status_message(
|
||||
# status_msg,
|
||||
# f'processing a \'{method}\' request by {tg_user_pretty(user)}\n'
|
||||
# f'[{timestamp_pretty()}] <i>broadcasting transaction to chain...</i>',
|
||||
# parse_mode='HTML'
|
||||
# )
|
||||
|
||||
reward = '20.0000 GPU'
|
||||
res = await self.cleos.a_push_action(
|
||||
'telos.gpu',
|
||||
'enqueue',
|
||||
{
|
||||
'user': Name(self.account),
|
||||
'request_body': body,
|
||||
'binary_data': binary_data,
|
||||
'reward': asset_from_str(reward),
|
||||
'min_verification': 1
|
||||
},
|
||||
self.account, self.key, permission=self.permission
|
||||
)
|
||||
|
||||
if 'code' in res or 'statusCode' in res:
|
||||
logging.error(json.dumps(res, indent=4))
|
||||
# await self.update_status_message(
|
||||
# status_msg,
|
||||
# 'skynet has suffered an internal error trying to fill this request')
|
||||
# return
|
||||
|
||||
enqueue_tx_id = res['transaction_id']
|
||||
enqueue_tx_link = hlink(
|
||||
'Your request on Skynet Explorer',
|
||||
f'https://explorer.{DEFAULT_DOMAIN}/v2/explore/transaction/{enqueue_tx_id}'
|
||||
)
|
||||
|
||||
# await self.append_status_message(
|
||||
# status_msg,
|
||||
# f' <b>broadcasted!</b>\n'
|
||||
# f'<b>{enqueue_tx_link}</b>\n'
|
||||
# f'[{timestamp_pretty()}] <i>workers are processing request...</i>',
|
||||
# parse_mode='HTML'
|
||||
# )
|
||||
|
||||
out = collect_stdout(res)
|
||||
|
||||
request_id, nonce = out.split(':')
|
||||
|
||||
request_hash = sha256(
|
||||
(nonce + body + binary_data).encode('utf-8')).hexdigest().upper()
|
||||
|
||||
request_id = int(request_id)
|
||||
|
||||
logging.info(f'{request_id} enqueued.')
|
||||
|
||||
tx_hash = None
|
||||
ipfs_hash = None
|
||||
for i in range(60):
|
||||
try:
|
||||
submits = await self.hyperion.aget_actions(
|
||||
account=self.account,
|
||||
filter='telos.gpu:submit',
|
||||
sort='desc',
|
||||
after=request_time
|
||||
)
|
||||
actions = [
|
||||
action
|
||||
for action in submits['actions']
|
||||
if action[
|
||||
'act']['data']['request_hash'] == request_hash
|
||||
]
|
||||
if len(actions) > 0:
|
||||
tx_hash = actions[0]['trx_id']
|
||||
data = actions[0]['act']['data']
|
||||
ipfs_hash = data['ipfs_hash']
|
||||
worker = data['worker']
|
||||
logging.info('Found matching submit!')
|
||||
break
|
||||
|
||||
except JSONDecodeError:
|
||||
logging.error(f'network error while getting actions, retry..')
|
||||
|
||||
await asyncio.sleep(1)
|
||||
|
||||
if not ipfs_hash:
|
||||
# await self.update_status_message(
|
||||
# status_msg,
|
||||
# f'\n[{timestamp_pretty()}] <b>timeout processing request</b>',
|
||||
# parse_mode='HTML'
|
||||
# )
|
||||
return
|
||||
|
||||
tx_link = hlink(
|
||||
'Your result on Skynet Explorer',
|
||||
f'https://explorer.{DEFAULT_DOMAIN}/v2/explore/transaction/{tx_hash}'
|
||||
)
|
||||
|
||||
# await self.append_status_message(
|
||||
# status_msg,
|
||||
# f' <b>request processed!</b>\n'
|
||||
# f'<b>{tx_link}</b>\n'
|
||||
# f'[{timestamp_pretty()}] <i>trying to download image...</i>\n',
|
||||
# parse_mode='HTML'
|
||||
# )
|
||||
|
||||
# attempt to get the image and send it
|
||||
ipfs_link = f'https://ipfs.{DEFAULT_DOMAIN}/ipfs/{ipfs_hash}/image.png'
|
||||
resp = await get_ipfs_file(ipfs_link)
|
||||
|
||||
caption = generate_reply_caption(
|
||||
user, params, tx_hash, worker, reward)
|
||||
|
||||
if not resp or resp.status_code != 200:
|
||||
logging.error(f'couldn\'t get ipfs hosted image at {ipfs_link}!')
|
||||
# await self.update_status_message(
|
||||
# status_msg,
|
||||
# caption,
|
||||
# reply_markup=build_redo_menu(),
|
||||
# parse_mode='HTML'
|
||||
# )
|
||||
#
|
||||
else:
|
||||
logging.info(f'success! sending generated image')
|
||||
# await self.bot.delete_message(
|
||||
# chat_id=status_msg.chat.id, message_id=status_msg.id)
|
||||
# if file_id: # img2img
|
||||
# await self.bot.send_media_group(
|
||||
# status_msg.chat.id,
|
||||
# media=[
|
||||
# InputMediaPhoto(file_id),
|
||||
# InputMediaPhoto(
|
||||
# resp.raw,
|
||||
# caption=caption,
|
||||
# parse_mode='HTML'
|
||||
# )
|
||||
# ],
|
||||
# )
|
||||
#
|
||||
# else: # txt2img
|
||||
# await self.bot.send_photo(
|
||||
# status_msg.chat.id,
|
||||
# caption=caption,
|
||||
# photo=resp.raw,
|
||||
# reply_markup=build_redo_menu(),
|
||||
# parse_mode='HTML'
|
||||
# )
|
|
@ -0,0 +1,73 @@
|
|||
# import os
|
||||
import discord
|
||||
# import asyncio
|
||||
# from dotenv import load_dotenv
|
||||
# from pathlib import Path
|
||||
from discord.ext import commands
|
||||
|
||||
|
||||
# # Auth
|
||||
# current_dir = Path(__file__).resolve().parent
|
||||
# # parent_dir = current_dir.parent
|
||||
# env_file_path = current_dir / ".env"
|
||||
# load_dotenv(dotenv_path=env_file_path)
|
||||
#
|
||||
# discordToken = os.getenv("DISCORD_TOKEN")
|
||||
|
||||
|
||||
# Actual Discord bot.
|
||||
class DiscordBot(commands.Bot):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
intents = discord.Intents(
|
||||
messages=True,
|
||||
guilds=True,
|
||||
typing=True,
|
||||
members=True,
|
||||
presences=True,
|
||||
reactions=True,
|
||||
message_content=True,
|
||||
voice_states=True
|
||||
)
|
||||
super().__init__(command_prefix='\\', intents=intents, *args, **kwargs)
|
||||
|
||||
# async def setup_hook(self):
|
||||
# db.poll_db.start()
|
||||
|
||||
async def on_ready(self):
|
||||
print(f'{self.user.name} has connected to Discord!')
|
||||
for guild in self.guilds:
|
||||
for channel in guild.channels:
|
||||
if channel.name == "skynet":
|
||||
await channel.send('Skynet bot online')
|
||||
|
||||
print("\n==============")
|
||||
print("Logged in as")
|
||||
print(self.user.name)
|
||||
print(self.user.id)
|
||||
print("==============")
|
||||
|
||||
async def on_command_error(self, ctx, error):
|
||||
if isinstance(error, commands.MissingRequiredArgument):
|
||||
await ctx.send('You missed a required argument, please try again.')
|
||||
|
||||
# async def on_message(self, message):
|
||||
# print(f"message from {message.author} what he said {message.content}")
|
||||
# await message.channel.send(message.content)
|
||||
|
||||
# bot=DiscordBot()
|
||||
# @bot.command(name='config', help='Responds with the configuration')
|
||||
# async def config(ctx):
|
||||
# response = "This is the bot configuration" # Put your bot configuration here
|
||||
# await ctx.send(response)
|
||||
#
|
||||
# @bot.command(name='helper', help='Responds with a help')
|
||||
# async def helper(ctx):
|
||||
# response = "This is help information" # Put your help response here
|
||||
# await ctx.send(response)
|
||||
#
|
||||
# @bot.command(name='txt2img', help='Responds with an image')
|
||||
# async def txt2img(ctx, *, arg):
|
||||
# response = f"This is your prompt: {arg}"
|
||||
# await ctx.send(response)
|
||||
# bot.run(discordToken)
|
|
@ -0,0 +1,372 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from PIL import Image
|
||||
# from telebot.types import CallbackQuery, Message
|
||||
|
||||
from skynet.frontend import validate_user_config_request
|
||||
from skynet.constants import *
|
||||
|
||||
|
||||
def create_handler_context(frontend: 'SkynetDiscordFrontend'):
|
||||
|
||||
bot = frontend.bot
|
||||
cleos = frontend.cleos
|
||||
# db_call = frontend.db_call
|
||||
work_request = frontend.work_request
|
||||
|
||||
ipfs_node = frontend.ipfs_node
|
||||
|
||||
|
||||
@bot.command(name='config', help='Responds with the configuration')
|
||||
async def config(ctx):
|
||||
response = "This is the bot configuration" # Put your bot configuration here
|
||||
await ctx.send(response)
|
||||
|
||||
@bot.command(name='helper', help='Responds with a help')
|
||||
async def helper(ctx):
|
||||
response = "This is help information" # Put your help response here
|
||||
await ctx.send(response)
|
||||
|
||||
@bot.command(name='txt2img', help='Responds with an image')
|
||||
async def send_txt2img(ctx, *, arg):
|
||||
user = 'tests'
|
||||
status_msg = 'status'
|
||||
params = {
|
||||
'prompt': prompt,
|
||||
}
|
||||
ec = await work_request(user, status_msg, 'txt2img', params)
|
||||
print(ec)
|
||||
|
||||
# if ec == 0:
|
||||
# await db_call('increment_generated', user.id)
|
||||
|
||||
response = f"This is your prompt: {arg}"
|
||||
await ctx.send(response)
|
||||
|
||||
# generic / simple handlers
|
||||
|
||||
# @bot.message_handler(commands=['help'])
|
||||
# async def send_help(message):
|
||||
# splt_msg = message.text.split(' ')
|
||||
#
|
||||
# if len(splt_msg) == 1:
|
||||
# await bot.reply_to(message, HELP_TEXT)
|
||||
#
|
||||
# else:
|
||||
# param = splt_msg[1]
|
||||
# if param in HELP_TOPICS:
|
||||
# await bot.reply_to(message, HELP_TOPICS[param])
|
||||
#
|
||||
# else:
|
||||
# await bot.reply_to(message, HELP_UNKWNOWN_PARAM)
|
||||
#
|
||||
# @bot.message_handler(commands=['cool'])
|
||||
# async def send_cool_words(message):
|
||||
# await bot.reply_to(message, '\n'.join(COOL_WORDS))
|
||||
#
|
||||
# @bot.message_handler(commands=['queue'])
|
||||
# async def queue(message):
|
||||
# an_hour_ago = datetime.now() - timedelta(hours=1)
|
||||
# queue = await cleos.aget_table(
|
||||
# 'telos.gpu', 'telos.gpu', 'queue',
|
||||
# index_position=2,
|
||||
# key_type='i64',
|
||||
# sort='desc',
|
||||
# lower_bound=int(an_hour_ago.timestamp())
|
||||
# )
|
||||
# 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
|
||||
# try:
|
||||
# attr, val, reply_txt = validate_user_config_request(
|
||||
# message.text)
|
||||
#
|
||||
# logging.info(f'user config update: {attr} to {val}')
|
||||
# await db_call('update_user_config', user, attr, val)
|
||||
# logging.info('done')
|
||||
#
|
||||
# except BaseException as e:
|
||||
# reply_txt = str(e)
|
||||
#
|
||||
# finally:
|
||||
# await bot.reply_to(message, reply_txt)
|
||||
#
|
||||
# @bot.message_handler(commands=['stats'])
|
||||
# async def user_stats(message):
|
||||
# user = message.from_user.id
|
||||
#
|
||||
# await db_call('get_or_create_user', user)
|
||||
# generated, joined, role = await db_call('get_user_stats', user)
|
||||
#
|
||||
# stats_str = f'generated: {generated}\n'
|
||||
# stats_str += f'joined: {joined}\n'
|
||||
# stats_str += f'role: {role}\n'
|
||||
#
|
||||
# await bot.reply_to(
|
||||
# message, stats_str)
|
||||
#
|
||||
# @bot.message_handler(commands=['donate'])
|
||||
# async def donation_info(message):
|
||||
# await bot.reply_to(
|
||||
# message, DONATION_INFO)
|
||||
#
|
||||
# @bot.message_handler(commands=['say'])
|
||||
# async def say(message):
|
||||
# chat = message.chat
|
||||
# user = message.from_user
|
||||
#
|
||||
# if (chat.type == 'group') or (user.id != 383385940):
|
||||
# return
|
||||
#
|
||||
# await bot.send_message(GROUP_ID, message.text[4:])
|
||||
|
||||
|
||||
# generic txt2img handler
|
||||
|
||||
# async def _generic_txt2img(message_or_query):
|
||||
# if isinstance(message_or_query, CallbackQuery):
|
||||
# query = message_or_query
|
||||
# message = query.message
|
||||
# user = query.from_user
|
||||
# chat = query.message.chat
|
||||
#
|
||||
# else:
|
||||
# message = message_or_query
|
||||
# user = message.from_user
|
||||
# chat = message.chat
|
||||
#
|
||||
# reply_id = None
|
||||
# if chat.type == 'group' and chat.id == GROUP_ID:
|
||||
# reply_id = message.message_id
|
||||
#
|
||||
# user_row = await db_call('get_or_create_user', user.id)
|
||||
#
|
||||
# # init new msg
|
||||
# init_msg = 'started processing txt2img request...'
|
||||
# status_msg = await bot.reply_to(message, init_msg)
|
||||
# await db_call(
|
||||
# 'new_user_request', user.id, message.id, status_msg.id, status=init_msg)
|
||||
#
|
||||
# prompt = ' '.join(message.text.split(' ')[1:])
|
||||
#
|
||||
# if len(prompt) == 0:
|
||||
# await bot.edit_message_text(
|
||||
# 'Empty text prompt ignored.',
|
||||
# chat_id=status_msg.chat.id,
|
||||
# message_id=status_msg.id
|
||||
# )
|
||||
# await db_call('update_user_request', status_msg.id, 'Empty text prompt ignored.')
|
||||
# return
|
||||
#
|
||||
# logging.info(f'mid: {message.id}')
|
||||
#
|
||||
# user_config = {**user_row}
|
||||
# del user_config['id']
|
||||
#
|
||||
# params = {
|
||||
# 'prompt': prompt,
|
||||
# **user_config
|
||||
# }
|
||||
#
|
||||
# await db_call(
|
||||
# 'update_user_stats', user.id, 'txt2img', last_prompt=prompt)
|
||||
#
|
||||
# ec = await work_request(user, status_msg, 'txt2img', params)
|
||||
|
||||
# if ec == 0:
|
||||
# await db_call('increment_generated', user.id)
|
||||
#
|
||||
#
|
||||
# # generic img2img handler
|
||||
#
|
||||
# async def _generic_img2img(message_or_query):
|
||||
# if isinstance(message_or_query, CallbackQuery):
|
||||
# query = message_or_query
|
||||
# message = query.message
|
||||
# user = query.from_user
|
||||
# chat = query.message.chat
|
||||
#
|
||||
# else:
|
||||
# message = message_or_query
|
||||
# user = message.from_user
|
||||
# chat = message.chat
|
||||
#
|
||||
# reply_id = None
|
||||
# if chat.type == 'group' and chat.id == GROUP_ID:
|
||||
# reply_id = message.message_id
|
||||
#
|
||||
# user_row = await db_call('get_or_create_user', user.id)
|
||||
#
|
||||
# # init new msg
|
||||
# init_msg = 'started processing txt2img request...'
|
||||
# status_msg = await bot.reply_to(message, init_msg)
|
||||
# await db_call(
|
||||
# 'new_user_request', user.id, message.id, status_msg.id, status=init_msg)
|
||||
#
|
||||
# if not message.caption.startswith('/img2img'):
|
||||
# await bot.reply_to(
|
||||
# message,
|
||||
# 'For image to image you need to add /img2img to the beggining of your caption'
|
||||
# )
|
||||
# return
|
||||
#
|
||||
# prompt = ' '.join(message.caption.split(' ')[1:])
|
||||
#
|
||||
# if len(prompt) == 0:
|
||||
# await bot.reply_to(message, 'Empty text prompt ignored.')
|
||||
# return
|
||||
#
|
||||
# file_id = message.photo[-1].file_id
|
||||
# file_path = (await bot.get_file(file_id)).file_path
|
||||
# image_raw = await bot.download_file(file_path)
|
||||
|
||||
# with Image.open(io.BytesIO(image_raw)) as image:
|
||||
# w, h = 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')
|
||||
#
|
||||
# ipfs_hash = ipfs_node.add('image.png')
|
||||
# ipfs_node.pin(ipfs_hash)
|
||||
#
|
||||
# logging.info(f'published input image {ipfs_hash} on ipfs')
|
||||
#
|
||||
# logging.info(f'mid: {message.id}')
|
||||
#
|
||||
# user_config = {**user_row}
|
||||
# del user_config['id']
|
||||
#
|
||||
# params = {
|
||||
# 'prompt': prompt,
|
||||
# **user_config
|
||||
# }
|
||||
#
|
||||
# await db_call(
|
||||
# 'update_user_stats',
|
||||
# user.id,
|
||||
# 'img2img',
|
||||
# last_file=file_id,
|
||||
# last_prompt=prompt,
|
||||
# last_binary=ipfs_hash
|
||||
# )
|
||||
#
|
||||
# ec = await work_request(
|
||||
# user, status_msg, 'img2img', params,
|
||||
# file_id=file_id,
|
||||
# binary_data=ipfs_hash
|
||||
# )
|
||||
#
|
||||
# if ec == 0:
|
||||
# await db_call('increment_generated', user.id)
|
||||
#
|
||||
|
||||
# generic redo handler
|
||||
|
||||
# async def _redo(message_or_query):
|
||||
# is_query = False
|
||||
# if isinstance(message_or_query, CallbackQuery):
|
||||
# is_query = True
|
||||
# query = message_or_query
|
||||
# message = query.message
|
||||
# user = query.from_user
|
||||
# chat = query.message.chat
|
||||
#
|
||||
# elif isinstance(message_or_query, Message):
|
||||
# message = message_or_query
|
||||
# user = message.from_user
|
||||
# chat = message.chat
|
||||
#
|
||||
# init_msg = 'started processing redo request...'
|
||||
# if is_query:
|
||||
# status_msg = await bot.send_message(chat.id, init_msg)
|
||||
#
|
||||
# else:
|
||||
# status_msg = await bot.reply_to(message, init_msg)
|
||||
#
|
||||
# method = await db_call('get_last_method_of', user.id)
|
||||
# prompt = await db_call('get_last_prompt_of', user.id)
|
||||
#
|
||||
# file_id = None
|
||||
# binary = ''
|
||||
# if method == 'img2img':
|
||||
# file_id = await db_call('get_last_file_of', user.id)
|
||||
# binary = await db_call('get_last_binary_of', user.id)
|
||||
#
|
||||
# if not prompt:
|
||||
# await bot.reply_to(
|
||||
# message,
|
||||
# 'no last prompt found, do a txt2img cmd first!'
|
||||
# )
|
||||
# return
|
||||
#
|
||||
#
|
||||
# user_row = await db_call('get_or_create_user', user.id)
|
||||
# await db_call(
|
||||
# 'new_user_request', user.id, message.id, status_msg.id, status=init_msg)
|
||||
# user_config = {**user_row}
|
||||
# del user_config['id']
|
||||
#
|
||||
# params = {
|
||||
# 'prompt': prompt,
|
||||
# **user_config
|
||||
# }
|
||||
#
|
||||
# await work_request(
|
||||
# user, status_msg, 'redo', params,
|
||||
# file_id=file_id,
|
||||
# binary_data=binary
|
||||
# )
|
||||
|
||||
|
||||
# "proxy" handlers just request routers
|
||||
|
||||
# @bot.message_handler(commands=['txt2img'])
|
||||
# async def send_txt2img(message):
|
||||
# await _generic_txt2img(message)
|
||||
#
|
||||
# @bot.message_handler(func=lambda message: True, content_types=[
|
||||
# 'photo', 'document'])
|
||||
# async def send_img2img(message):
|
||||
# await _generic_img2img(message)
|
||||
#
|
||||
# @bot.message_handler(commands=['img2img'])
|
||||
# async def img2img_missing_image(message):
|
||||
# await bot.reply_to(
|
||||
# message,
|
||||
# 'seems you tried to do an img2img command without sending image'
|
||||
# )
|
||||
#
|
||||
# @bot.message_handler(commands=['redo'])
|
||||
# async def redo(message):
|
||||
# await _redo(message)
|
||||
#
|
||||
# @bot.callback_query_handler(func=lambda call: True)
|
||||
# async def callback_query(call):
|
||||
# msg = json.loads(call.data)
|
||||
# logging.info(call.data)
|
||||
# method = msg.get('method')
|
||||
# match method:
|
||||
# case 'redo':
|
||||
# await _redo(call)
|
||||
|
||||
|
||||
# catch all handler for things we dont support
|
||||
|
||||
# @bot.message_handler(func=lambda message: True)
|
||||
# async def echo_message(message):
|
||||
# if message.text[0] == '/':
|
||||
# await bot.reply_to(message, UNKNOWN_CMD_TEXT)
|
|
@ -0,0 +1,106 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
import json
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from telebot.types import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telebot.async_telebot import ExceptionHandler
|
||||
from telebot.formatting import hlink
|
||||
|
||||
from skynet.constants import *
|
||||
|
||||
|
||||
def timestamp_pretty():
|
||||
return datetime.now(timezone.utc).strftime('%H:%M:%S')
|
||||
|
||||
|
||||
def tg_user_pretty(tguser):
|
||||
if tguser.username:
|
||||
return f'@{tguser.username}'
|
||||
else:
|
||||
return f'{tguser.first_name} id: {tguser.id}'
|
||||
|
||||
|
||||
class SKYExceptionHandler(ExceptionHandler):
|
||||
|
||||
def handle(exception):
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def build_redo_menu():
|
||||
btn_redo = InlineKeyboardButton("Redo", callback_data=json.dumps({'method': 'redo'}))
|
||||
inline_keyboard = InlineKeyboardMarkup()
|
||||
inline_keyboard.add(btn_redo)
|
||||
return inline_keyboard
|
||||
|
||||
|
||||
def prepare_metainfo_caption(tguser, worker: str, reward: str, meta: dict) -> str:
|
||||
prompt = meta["prompt"]
|
||||
if len(prompt) > 256:
|
||||
prompt = prompt[:256]
|
||||
|
||||
|
||||
meta_str = f'<u>by {tg_user_pretty(tguser)}</u>\n'
|
||||
meta_str += f'<i>performed by {worker}</i>\n'
|
||||
meta_str += f'<b><u>reward: {reward}</u></b>\n'
|
||||
|
||||
meta_str += f'<code>prompt:</code> {prompt}\n'
|
||||
meta_str += f'<code>seed: {meta["seed"]}</code>\n'
|
||||
meta_str += f'<code>step: {meta["step"]}</code>\n'
|
||||
meta_str += f'<code>guidance: {meta["guidance"]}</code>\n'
|
||||
if meta['strength']:
|
||||
meta_str += f'<code>strength: {meta["strength"]}</code>\n'
|
||||
meta_str += f'<code>algo: {meta["model"]}</code>\n'
|
||||
if meta['upscaler']:
|
||||
meta_str += f'<code>upscaler: {meta["upscaler"]}</code>\n'
|
||||
|
||||
meta_str += f'<b><u>Made with Skynet v{VERSION}</u></b>\n'
|
||||
meta_str += f'<b>JOIN THE SWARM: @skynetgpu</b>'
|
||||
return meta_str
|
||||
|
||||
|
||||
def generate_reply_caption(
|
||||
tguser, # telegram user
|
||||
params: dict,
|
||||
tx_hash: str,
|
||||
worker: str,
|
||||
reward: str
|
||||
):
|
||||
explorer_link = hlink(
|
||||
'SKYNET Transaction Explorer',
|
||||
f'https://explorer.{DEFAULT_DOMAIN}/v2/explore/transaction/{tx_hash}'
|
||||
)
|
||||
|
||||
meta_info = prepare_metainfo_caption(tguser, worker, reward, params)
|
||||
|
||||
final_msg = '\n'.join([
|
||||
'Worker finished your task!',
|
||||
explorer_link,
|
||||
f'PARAMETER INFO:\n{meta_info}'
|
||||
])
|
||||
|
||||
final_msg = '\n'.join([
|
||||
f'<b><i>{explorer_link}</i></b>',
|
||||
f'{meta_info}'
|
||||
])
|
||||
|
||||
logging.info(final_msg)
|
||||
|
||||
return final_msg
|
||||
|
||||
|
||||
async def get_global_config(cleos):
|
||||
return (await cleos.aget_table(
|
||||
'telos.gpu', 'telos.gpu', 'config'))[0]
|
||||
|
||||
async def get_user_nonce(cleos, user: str):
|
||||
return (await cleos.aget_table(
|
||||
'telos.gpu', 'telos.gpu', 'users',
|
||||
index_position=1,
|
||||
key_type='name',
|
||||
lower_bound=user,
|
||||
upper_bound=user
|
||||
))[0]['nonce']
|
Loading…
Reference in New Issue