Skip to content

Instantly share code, notes, and snippets.

@loopyd
Created August 26, 2022 04:08
Show Gist options
  • Save loopyd/dfbb31c3fc406f4c429df40e66cfb737 to your computer and use it in GitHub Desktop.
Save loopyd/dfbb31c3fc406f4c429df40e66cfb737 to your computer and use it in GitHub Desktop.
Gradiotooth - Syntactic python sugar for gradio panels
import functools, argparse, mimetypes, sys, itertools
from sys import platform
from pyclbr import Function
from enum import Enum, auto
import gradio as gr
# gradiotooth.py | Release v0.1
#
# Code is Copyright (C) 2022 saber7ooth <https://www.github.com/loopyd>
# Licensed under DBAD: https://dbad-license.org/
#
# It allows you to bind gradio controls to interfaces with ease and execute model
# functions with toothtastic simplicity.
#
# It is the prettiest way to produce a gradio panel for a model runscript out there.
#
# If you like my code, please donate: https://paypal.me/snowflowerwolf
if hasattr(sys, 'getwindowsversion'):
mimetypes.init()
mimetypes.add_type('application/javascript', '.js')
##########################################################################
## Decorators
##########################################################################
class gr_controltype(Enum):
INPUT = auto(),
OUTPUT = auto()
def run_once(f):
def wrapper(*args, **kwargs):
if not wrapper.has_run:
wrapper.has_run = True
return f(*args, **kwargs)
wrapper.has_run = False
return wrapper
def gr_control(control_type: gr_controltype, control_constructor: Function, **kargs):
def decorator_gr_control(func):
@functools.wraps(func)
def wrapper_gr_control(*args, **kwargs):
self = args[0]
if control_constructor is not None:
data_raw = {}
data_raw["bound_method"] = func.__name__
for k, v in kargs.items():
data_raw[k] = v
if data_raw not in self.inputs_raw and control_type is gr_controltype.INPUT:
self.inputs_raw.append(data_raw)
self.inputs.append(control_constructor(**kargs))
elif data_raw not in self.outputs_raw and control_type is gr_controltype.OUTPUT:
self.outputs_raw.append(data_raw)
self.outputs.append(control_constructor(**kargs))
return func(*args, **kwargs)
return wrapper_gr_control
return decorator_gr_control
def gr_argument(*argv, **kargs):
def decorator_argument(func):
@functools.wraps(func)
def wrapper_argument(*args, **kwargs):
self = args[0]
if self.argParser is not None:
data_raw = {}
data_raw["bound_method"] = func.__name__
data_raw["bound_control"] = self.inputs_raw[(len(self.inputs_raw)-1)]
data_raw["args"] = argv[0]
for k, v in kargs.items():
data_raw[k] = v
if data_raw not in self.args_raw:
self.args_raw.append(data_raw)
self.argParser.add_argument(*argv, **kargs)
return func(*args, **kwargs)
return wrapper_argument
return decorator_argument
def gr_bound_func(func, *argv, **kargs):
@functools.wraps(func)
def wrapper_bound_func(*args, **kwargs):
self = args[0]
if self.bound_func is None:
self.bound_func = func
# magic sauce
argbuilder = []
for i, arg in enumerate(args[1:]):
arg_option_str = str(self.args_raw[i]["args"]).split('|')[0]
if arg_option_str is None:
arg_option_str = str(self.args_raw[i]["args"])
arg_t = self.args_raw[i]["type"]
arg_casted = arg_t(arg)
argbuilder.append(f"{arg_option_str}")
argbuilder.append(f"{str( arg_casted )}")
self.cmdline = ' '.join(argbuilder)
self.opts = vars(self.argParser.parse_args(argbuilder))
return func(self, *argv, **kargs)
return wrapper_bound_func
##########################################################################
## Boilerplate
##########################################################################
class GradiotoothControllerInterface(object):
def __init__(self):
self.argParser = argparse.ArgumentParser()
self.args_raw = []
self.bound_func = None
self.inputs = []
self.inputs_raw = []
self.outputs = []
self.outputs_raw = []
self.opts = []
pass
def interface_init(self):
self.bound_func = getattr(
self,
[m for m in dir(self) if m == f"{type(self).__name__}_handler" ][0]
)
self.interface = gr.Interface(
self.bound_func,
inputs = self.inputs,
outputs = self.outputs,
title = self.title,
description = self.description
)
pass
##########################################################################
## Example
##########################################################################
# A new much prettier gradio interface class with python sugar.
# Construct many to add to your gradio.
class default_interface(GradiotoothControllerInterface):
def __init__(self):
self.tab_name = "Default"
self.title = "Sabertooth Grad.io Panel"
self.description = "A default testing panel for Grad.io"
super().__init__()
self._default_interface_init()
pass
@gr_bound_func
def default_interface_handler(self):
print("Interface handler triggered, here are your instanced variables (as per the usual):\n")
# You can now do what ever you want with the values! I'll just print them.
for k in self.opts:
print(f" self.opts.{k} = {self.opts[k]}")
# And the majority of you experiencing gradio script springboard headaches probably want this one...
# this was the purpose of the design of this tool.
print("\nI can also invoke scripts! Here I won't, but I'll print you the stringified example:\n")
print(f" default_interface.py {self.cmdline}\n")
pass
@gr_control(gr_controltype.INPUT, gr.Textbox, label="textbox_test", placeholder="Enter somethin' here, champ")
@gr_control(gr_controltype.OUTPUT, gr.Gallery)
@gr_argument("--test", nargs="?", help="Just a test property to test the command binding", default="Enter somethin' here, champ.", type=str)
def _default_interface_init(self):
super().interface_init()
pass
my_default = default_interface()
demo = gr.TabbedInterface(interface_list=[my_default.interface], tab_names=[my_default.tab_name])
demo.launch(share=False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment