Spaces:
Configuration error
Configuration error
Commit
Β·
f06506b
1
Parent(s):
bbd6e0a
π§° refactor/clean module, demos, docker-compose, and README.md
Browse files- README.md +18 -10
- backend/src/__init__.py +2 -2
- backend/src/__pycache__/__init__.cpython-39.pyc +0 -0
- backend/src/__pycache__/demo.cpython-39.pyc +0 -0
- backend/src/{index.py β demoC.py} +8 -2
- backend/src/{demo.py β demoF.py} +6 -1
- backend/src/example/__pycache__/examples.cpython-37.pyc +0 -0
- backend/src/example/__pycache__/examples.cpython-38.pyc +0 -0
- backend/src/example/__pycache__/examples.cpython-39.pyc +0 -0
- backend/src/resources/__pycache__/__init__.cpython-38.pyc +0 -0
- backend/src/resources/__pycache__/compiler.cpython-39.pyc +0 -0
- backend/src/resources/__pycache__/dock.cpython-39.pyc +0 -0
- backend/src/resources/__pycache__/module.cpython-38.pyc +0 -0
- backend/src/resources/__pycache__/module.cpython-39.pyc +0 -0
- backend/src/resources/module.py +80 -77
- backend/test/test.py +35 -6
- docker-compose.yml +1 -0
README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
# Gradio Flow π€
|
| 2 |
|
| 3 |
-
**A web application with a backend in Flask and frontend in Rect, and
|
| 4 |
-
stream both gradio and streamlit interfaces, within a single application.**
|
| 5 |
|
| 6 |
|
| 7 |
## Tabel Of Contents π
|
|
@@ -78,7 +78,7 @@ Now that you're within the docker backend container environment you can start ad
|
|
| 78 |
|
| 79 |
```console
|
| 80 |
> cd ./src
|
| 81 |
-
> python
|
| 82 |
//run example gradio application
|
| 83 |
```
|
| 84 |
|
|
@@ -110,7 +110,7 @@ It is quite simple, and similar within the docker build, the first way you can a
|
|
| 110 |
**NOTE** If you use the gradio decorator compiler for gradio flow you need to set a listen port to 2000 or else the api will never get the key and will throw you an error, I'll also provided an example below if this isn't clear.
|
| 111 |
|
| 112 |
```python
|
| 113 |
-
#backend/src/
|
| 114 |
##########
|
| 115 |
from resources import register, tabularGradio
|
| 116 |
|
|
@@ -118,33 +118,41 @@ from resources import register, tabularGradio
|
|
| 118 |
def Hello_World(name):
|
| 119 |
return f"Hello {name}, and welcome to Gradio Flow π€"
|
| 120 |
|
| 121 |
-
@register(["number", "number"], ["number"], examples=[[1,1]])
|
| 122 |
def add(x, y):
|
| 123 |
return x + y
|
| 124 |
|
| 125 |
if __name__ == "__main__":
|
|
|
|
| 126 |
tabularGradio([Hello_World(), add()], ["Hello World", "Add"])
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
```
|
| 128 |
|
| 129 |
```python
|
| 130 |
-
#backend/src/
|
| 131 |
###########
|
| 132 |
from resources import GradioModule, register
|
| 133 |
|
| 134 |
@GradioModule
|
| 135 |
class Greeting:
|
| 136 |
|
| 137 |
-
@register(["text"], ["text"])
|
| 138 |
def Hello_World(self, name):
|
| 139 |
return f"Hello {name}, and welcome to Gradio Flow π€"
|
| 140 |
|
| 141 |
-
@register(["number", "number"], ["number"], examples=[[1,1]])
|
| 142 |
def add(self, x, y):
|
| 143 |
return x + y
|
| 144 |
|
| 145 |
|
| 146 |
if __name__ == "__main__":
|
| 147 |
-
|
|
|
|
|
|
|
|
|
|
| 148 |
````
|
| 149 |
## Application ποΈ
|
| 150 |
-

|
|
|
|
| 1 |
# Gradio Flow π€
|
| 2 |
|
| 3 |
+
**A web application with a backend in Flask and frontend in Rect, and [React flow](https://reactflow.dev/) node base environment to
|
| 4 |
+
stream both [gradio](https://gradio.app) ( and later [streamlit](https://streamlit.io) ) interfaces, within a single application.**
|
| 5 |
|
| 6 |
|
| 7 |
## Tabel Of Contents π
|
|
|
|
| 78 |
|
| 79 |
```console
|
| 80 |
> cd ./src
|
| 81 |
+
> python demoC.py
|
| 82 |
//run example gradio application
|
| 83 |
```
|
| 84 |
|
|
|
|
| 110 |
**NOTE** If you use the gradio decorator compiler for gradio flow you need to set a listen port to 2000 or else the api will never get the key and will throw you an error, I'll also provided an example below if this isn't clear.
|
| 111 |
|
| 112 |
```python
|
| 113 |
+
#backend/src/demoF.py (functional base)
|
| 114 |
##########
|
| 115 |
from resources import register, tabularGradio
|
| 116 |
|
|
|
|
| 118 |
def Hello_World(name):
|
| 119 |
return f"Hello {name}, and welcome to Gradio Flow π€"
|
| 120 |
|
| 121 |
+
@register(inputs=["number", "number"], outputs=["number"], examples=[[1,1]])
|
| 122 |
def add(x, y):
|
| 123 |
return x + y
|
| 124 |
|
| 125 |
if __name__ == "__main__":
|
| 126 |
+
# run single gradio
|
| 127 |
tabularGradio([Hello_World(), add()], ["Hello World", "Add"])
|
| 128 |
+
|
| 129 |
+
# run it within Gradio-Flow
|
| 130 |
+
# tabularGradio([Hello_World(), add()], ["Hello World", "Add"], listen=2000)
|
| 131 |
+
|
| 132 |
```
|
| 133 |
|
| 134 |
```python
|
| 135 |
+
#backend/src/demoC.py (Class Base)
|
| 136 |
###########
|
| 137 |
from resources import GradioModule, register
|
| 138 |
|
| 139 |
@GradioModule
|
| 140 |
class Greeting:
|
| 141 |
|
| 142 |
+
@register(["text"], ["text"], examples=[["Luca Vivona"]])
|
| 143 |
def Hello_World(self, name):
|
| 144 |
return f"Hello {name}, and welcome to Gradio Flow π€"
|
| 145 |
|
| 146 |
+
@register(inputs=["number", "number"], outputs=["number"], examples=[[1,1]])
|
| 147 |
def add(self, x, y):
|
| 148 |
return x + y
|
| 149 |
|
| 150 |
|
| 151 |
if __name__ == "__main__":
|
| 152 |
+
# run just gradio
|
| 153 |
+
Greeting().launch()
|
| 154 |
+
# run it within Gradio-flow
|
| 155 |
+
# Greeting().launch(listen=2000)
|
| 156 |
````
|
| 157 |
## Application ποΈ
|
| 158 |
+

|
backend/src/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
import examples
|
| 2 |
import resource
|
| 3 |
-
import src.
|
| 4 |
-
import src.
|
|
|
|
| 1 |
import examples
|
| 2 |
import resource
|
| 3 |
+
import src.demoF
|
| 4 |
+
import src.demoC
|
backend/src/__pycache__/__init__.cpython-39.pyc
DELETED
|
Binary file (254 Bytes)
|
|
|
backend/src/__pycache__/demo.cpython-39.pyc
DELETED
|
Binary file (701 Bytes)
|
|
|
backend/src/{index.py β demoC.py}
RENAMED
|
@@ -3,7 +3,7 @@ from resources import GradioModule, register
|
|
| 3 |
@GradioModule
|
| 4 |
class Greeting:
|
| 5 |
|
| 6 |
-
@register(["text"], ["text"])
|
| 7 |
def Hello_World(self, name):
|
| 8 |
return f"Hello {name}, and welcome to Gradio Flow π€"
|
| 9 |
|
|
@@ -11,5 +11,11 @@ class Greeting:
|
|
| 11 |
def add(self, x, y):
|
| 12 |
return x + y
|
| 13 |
|
|
|
|
| 14 |
if __name__ == "__main__":
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
@GradioModule
|
| 4 |
class Greeting:
|
| 5 |
|
| 6 |
+
@register(["text"], ["text"], examples=[["Luca Vivona"]])
|
| 7 |
def Hello_World(self, name):
|
| 8 |
return f"Hello {name}, and welcome to Gradio Flow π€"
|
| 9 |
|
|
|
|
| 11 |
def add(self, x, y):
|
| 12 |
return x + y
|
| 13 |
|
| 14 |
+
|
| 15 |
if __name__ == "__main__":
|
| 16 |
+
# run just gradio
|
| 17 |
+
Greeting().launch()
|
| 18 |
+
# run it within Gradio-flow
|
| 19 |
+
# Greeting().launch(listen=2000)
|
| 20 |
+
|
| 21 |
+
|
backend/src/{demo.py β demoF.py}
RENAMED
|
@@ -10,4 +10,9 @@ def add(x, y):
|
|
| 10 |
return x + y
|
| 11 |
|
| 12 |
if __name__ == "__main__":
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
return x + y
|
| 11 |
|
| 12 |
if __name__ == "__main__":
|
| 13 |
+
# run single gradio
|
| 14 |
+
tabularGradio([Hello_World(), add()], ["Hello World", "Add"])
|
| 15 |
+
|
| 16 |
+
# run it within Gradio-Flow
|
| 17 |
+
# tabularGradio([Hello_World(), add()], ["Hello World", "Add"], listen=2000)
|
| 18 |
+
|
backend/src/example/__pycache__/examples.cpython-37.pyc
DELETED
|
Binary file (6.13 kB)
|
|
|
backend/src/example/__pycache__/examples.cpython-38.pyc
DELETED
|
Binary file (4.52 kB)
|
|
|
backend/src/example/__pycache__/examples.cpython-39.pyc
DELETED
|
Binary file (4.58 kB)
|
|
|
backend/src/resources/__pycache__/__init__.cpython-38.pyc
DELETED
|
Binary file (144 Bytes)
|
|
|
backend/src/resources/__pycache__/compiler.cpython-39.pyc
DELETED
|
Binary file (7.74 kB)
|
|
|
backend/src/resources/__pycache__/dock.cpython-39.pyc
DELETED
|
Binary file (1.15 kB)
|
|
|
backend/src/resources/__pycache__/module.cpython-38.pyc
DELETED
|
Binary file (7.84 kB)
|
|
|
backend/src/resources/__pycache__/module.cpython-39.pyc
CHANGED
|
Binary files a/backend/src/resources/__pycache__/module.cpython-39.pyc and b/backend/src/resources/__pycache__/module.cpython-39.pyc differ
|
|
|
backend/src/resources/module.py
CHANGED
|
@@ -32,10 +32,15 @@ DOCKER_LOCAL_HOST = '0.0.0.0'
|
|
| 32 |
DOCKER_PORT = Dock()
|
| 33 |
|
| 34 |
def tabularGradio(funcs, names, name="Tabular Temp Name", **kwargs):
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
| 38 |
port= kwargs["port"] if "port" in kwargs else DOCKER_PORT.determinePort()
|
|
|
|
|
|
|
| 39 |
if 'listen' in kwargs:
|
| 40 |
try:
|
| 41 |
requests.post(f"http://{DOCKER_LOCAL_HOST}:{ kwargs[ 'listen' ] }/api/append/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : 'Not Applicable', "name" : name, "kwargs" : kwargs})
|
|
@@ -43,6 +48,7 @@ def tabularGradio(funcs, names, name="Tabular Temp Name", **kwargs):
|
|
| 43 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe listening api is either not up or you choose the wrong port.π \n {e}")
|
| 44 |
return
|
| 45 |
|
|
|
|
| 46 |
gr.TabbedInterface(funcs, names).launch(server_port=port,
|
| 47 |
server_name=f"{DOCKER_LOCAL_HOST}",
|
| 48 |
inline= kwargs['inline'] if "inline" in kwargs else True,
|
|
@@ -63,53 +69,74 @@ def tabularGradio(funcs, names, name="Tabular Temp Name", **kwargs):
|
|
| 63 |
ssl_certfile=kwargs['ssl_certfile'] if "ssl_certfile" in kwargs else None,
|
| 64 |
ssl_keyfile_password=kwargs['ssl_keyfile_password'] if "ssl_keyfile_password" in kwargs else None,
|
| 65 |
quiet=kwargs['quiet'] if "quiet" in kwargs else False)
|
|
|
|
|
|
|
| 66 |
if 'listen' in kwargs:
|
| 67 |
try:
|
| 68 |
requests.post(f"http://{DOCKER_LOCAL_HOST}:{ kwargs[ 'listen' ] }/api/remove/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : 'Not Applicable', "name" : name, "kwargs" : kwargs})
|
| 69 |
-
except Exception as e:
|
| 70 |
-
|
| 71 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe api either lost connection or was turned off...π \n {e}")
|
| 72 |
|
| 73 |
return
|
| 74 |
|
| 75 |
-
|
|
|
|
| 76 |
def register(inputs, outputs, examples=None, **kwargs):
|
| 77 |
def register_gradio(func):
|
| 78 |
-
|
| 79 |
-
fn_name = func.__name__
|
| 80 |
|
| 81 |
-
|
| 82 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
"""
|
| 84 |
given the decorator is on a class then
|
| 85 |
initialize a registered_gradio_functons
|
| 86 |
if not already initialize.
|
| 87 |
"""
|
| 88 |
-
|
|
|
|
|
|
|
| 89 |
|
| 90 |
try:
|
| 91 |
self = args[0]
|
| 92 |
self.registered_gradio_functons
|
| 93 |
except AttributeError:
|
| 94 |
-
print("β¨Initializing Class Functions...β¨\n")
|
| 95 |
self.registered_gradio_functons = dict()
|
| 96 |
|
| 97 |
-
|
| 98 |
-
|
| 99 |
if not fn_name in self.registered_gradio_functons:
|
| 100 |
-
self.registered_gradio_functons[fn_name] = dict(inputs=inputs,
|
| 101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
if len(args[1:]) == (func.__code__.co_argcount - 1):
|
| 103 |
return func(*args, **wargs)
|
|
|
|
| 104 |
else :
|
| 105 |
"""
|
| 106 |
the function is not a class function
|
| 107 |
"""
|
| 108 |
-
|
|
|
|
| 109 |
|
|
|
|
| 110 |
if len(args) == (func.__code__.co_argcount):
|
| 111 |
return func(*args, **wargs)
|
| 112 |
|
|
|
|
| 113 |
return gr.Interface(fn=func,
|
| 114 |
inputs=inputs,
|
| 115 |
outputs=outputs,
|
|
@@ -126,82 +153,60 @@ def register(inputs, outputs, examples=None, **kwargs):
|
|
| 126 |
allow_flagging=kwargs['allow_flagging'] if "allow_flagging" in kwargs else None,
|
| 127 |
theme='default',
|
| 128 |
)
|
| 129 |
-
|
| 130 |
-
return None
|
| 131 |
-
return wrap
|
| 132 |
return register_gradio
|
| 133 |
|
| 134 |
def GradioModule(cls):
|
| 135 |
class Decorator:
|
| 136 |
|
| 137 |
def __init__(self) -> None:
|
| 138 |
-
self.
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
for func in self.get_funcs():
|
| 146 |
-
this = getattr(self.cls, func, None)
|
| 147 |
-
if this.__name__ == "wrap":
|
| 148 |
-
this()
|
| 149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
demos, names = [], []
|
| 151 |
-
for func, param in self.
|
| 152 |
names.append(func)
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
num_shap=kwargs['num_shap'] if "num_shap" in kwargs else 2.0,
|
| 161 |
-
title=kwargs['title'] if "title" in kwargs else None,
|
| 162 |
-
article=kwargs['article'] if "article" in kwargs else None,
|
| 163 |
-
thumbnail=kwargs['thumbnail'] if "thumbnail" in kwargs else None,
|
| 164 |
-
css=kwargs['css'] if "css" in kwargs else None,
|
| 165 |
-
live=kwargs['live'] if "live" in kwargs else False,
|
| 166 |
-
allow_flagging=kwargs['allow_flagging'] if "allow_flagging" in kwargs else None,
|
| 167 |
-
theme='default',
|
| 168 |
-
))
|
| 169 |
-
print(f"{func}....{bcolor.BOLD}{bcolor.OKGREEN} done {bcolor.ENDC}")
|
| 170 |
-
|
| 171 |
-
print("\nHappy Visualizing... π")
|
| 172 |
return gr.TabbedInterface(demos, names)
|
| 173 |
|
| 174 |
-
def
|
| 175 |
-
try:
|
| 176 |
-
self.cls.registered_gradio_functons
|
| 177 |
-
except AttributeError:
|
| 178 |
-
return None
|
| 179 |
-
return self.cls.registered_gradio_functons
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
def run(self, **kwargs):
|
| 183 |
port= kwargs["port"] if "port" in kwargs else DOCKER_PORT.determinePort()
|
| 184 |
if 'listen' in kwargs:
|
| 185 |
try:
|
| 186 |
-
requests.post(f"http://{DOCKER_LOCAL_HOST}:{ kwargs[ 'listen' ] }/api/append/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : getfile(self.
|
| 187 |
except Exception:
|
| 188 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe listening api is either not up or you choose the wrong port.π")
|
| 189 |
return
|
| 190 |
|
| 191 |
-
self.
|
| 192 |
-
allow_flagging=kwargs[ 'allow_flagging' ] if "allow_flagging" in kwargs else None,
|
| 193 |
-
cache_examples=kwargs['cache_examples'] if "cache_examples" in kwargs else None,
|
| 194 |
-
examples_per_page=kwargs['cache_examples'] if "cache_examples" in kwargs else 10,
|
| 195 |
-
interpretation=kwargs['interpretation'] if "interpretation" in kwargs else None,
|
| 196 |
-
num_shap=kwargs['num_shap'] if "num_shap" in kwargs else 2.0,
|
| 197 |
-
title=kwargs['title'] if "title" in kwargs else None,
|
| 198 |
-
article=kwargs['article'] if "article" in kwargs else None,
|
| 199 |
-
thumbnail=kwargs['thumbnail'] if "thumbnail" in kwargs else None,
|
| 200 |
-
css=kwargs['css'] if "css" in kwargs else None,
|
| 201 |
-
theme=kwargs['theme'] if "theme" in kwargs else None,
|
| 202 |
-
).launch(server_port=port,
|
| 203 |
server_name=f"{DOCKER_LOCAL_HOST}",
|
| 204 |
-
inline= kwargs['inline'] if "inline" in kwargs else
|
| 205 |
share=kwargs['share'] if "share" in kwargs else None,
|
| 206 |
debug=kwargs['debug'] if "debug" in kwargs else False,
|
| 207 |
enable_queue=kwargs['enable_queue'] if "enable_queue" in kwargs else None,
|
|
@@ -221,15 +226,13 @@ def GradioModule(cls):
|
|
| 221 |
quiet=kwargs['quiet'] if "quiet" in kwargs else False)
|
| 222 |
if 'listen' in kwargs:
|
| 223 |
try:
|
| 224 |
-
requests.post(f"http://{DOCKER_LOCAL_HOST}:{ kwargs[ 'listen' ] }/api/remove/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : getfile(self.
|
| 225 |
except Exception:
|
| 226 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe api either lost connection or was turned off...π")
|
| 227 |
return
|
| 228 |
|
| 229 |
return Decorator
|
| 230 |
|
| 231 |
-
|
| 232 |
-
|
| 233 |
class bcolor:
|
| 234 |
HEADER = '\033[95m'
|
| 235 |
OKBLUE = '\033[94m'
|
|
|
|
| 32 |
DOCKER_PORT = Dock()
|
| 33 |
|
| 34 |
def tabularGradio(funcs, names, name="Tabular Temp Name", **kwargs):
|
| 35 |
+
"""
|
| 36 |
+
takes all gradio Interfaces, and names
|
| 37 |
+
from input and launch the gradio.
|
| 38 |
+
"""
|
| 39 |
+
|
| 40 |
+
assert len(funcs) == len(names), f"{bcolor.BOLD}{bcolor.FAIL}π something went wrong!!! The function you appended dose not match the length of the names{bcolor.ENDC}"
|
| 41 |
port= kwargs["port"] if "port" in kwargs else DOCKER_PORT.determinePort()
|
| 42 |
+
|
| 43 |
+
# send this to the backend api for it to be read by the react frontend
|
| 44 |
if 'listen' in kwargs:
|
| 45 |
try:
|
| 46 |
requests.post(f"http://{DOCKER_LOCAL_HOST}:{ kwargs[ 'listen' ] }/api/append/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : 'Not Applicable', "name" : name, "kwargs" : kwargs})
|
|
|
|
| 48 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe listening api is either not up or you choose the wrong port.π \n {e}")
|
| 49 |
return
|
| 50 |
|
| 51 |
+
# provided by gradio a tabularInterface function that take function and names
|
| 52 |
gr.TabbedInterface(funcs, names).launch(server_port=port,
|
| 53 |
server_name=f"{DOCKER_LOCAL_HOST}",
|
| 54 |
inline= kwargs['inline'] if "inline" in kwargs else True,
|
|
|
|
| 69 |
ssl_certfile=kwargs['ssl_certfile'] if "ssl_certfile" in kwargs else None,
|
| 70 |
ssl_keyfile_password=kwargs['ssl_keyfile_password'] if "ssl_keyfile_password" in kwargs else None,
|
| 71 |
quiet=kwargs['quiet'] if "quiet" in kwargs else False)
|
| 72 |
+
|
| 73 |
+
# Ctrl+C that ends the process and then continue the code which will remove from the api
|
| 74 |
if 'listen' in kwargs:
|
| 75 |
try:
|
| 76 |
requests.post(f"http://{DOCKER_LOCAL_HOST}:{ kwargs[ 'listen' ] }/api/remove/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : 'Not Applicable', "name" : name, "kwargs" : kwargs})
|
| 77 |
+
except Exception as e:
|
|
|
|
| 78 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe api either lost connection or was turned off...π \n {e}")
|
| 79 |
|
| 80 |
return
|
| 81 |
|
| 82 |
+
|
| 83 |
+
|
| 84 |
def register(inputs, outputs, examples=None, **kwargs):
|
| 85 |
def register_gradio(func):
|
| 86 |
+
|
|
|
|
| 87 |
|
| 88 |
+
def decorator(*args, **wargs):
|
| 89 |
+
if type(outputs) is list:
|
| 90 |
+
assert len(outputs) >= 1, f"β {bcolor.BOLD}{bcolor.FAIL}you have no outputs π€¨... {str(type(outputs))} {bcolor.ENDC}"
|
| 91 |
+
|
| 92 |
+
fn_name = func.__name__
|
| 93 |
+
if 'self' in func.__code__.co_varnames and func.__code__.co_varnames[0] == 'self' and fn_name in dir(args[0]):
|
| 94 |
"""
|
| 95 |
given the decorator is on a class then
|
| 96 |
initialize a registered_gradio_functons
|
| 97 |
if not already initialize.
|
| 98 |
"""
|
| 99 |
+
|
| 100 |
+
if type(inputs) is list:
|
| 101 |
+
assert len(inputs) == func.__code__.co_argcount - 1, f"β {bcolor.BOLD}{bcolor.FAIL}inputs should have the same length as arguments{bcolor.ENDC}"
|
| 102 |
|
| 103 |
try:
|
| 104 |
self = args[0]
|
| 105 |
self.registered_gradio_functons
|
| 106 |
except AttributeError:
|
|
|
|
| 107 |
self.registered_gradio_functons = dict()
|
| 108 |
|
|
|
|
|
|
|
| 109 |
if not fn_name in self.registered_gradio_functons:
|
| 110 |
+
self.registered_gradio_functons[fn_name] = dict(inputs=inputs,
|
| 111 |
+
outputs=outputs,
|
| 112 |
+
examples=examples,
|
| 113 |
+
cache_examples=kwargs['cache_examples'] if "cache_examples" in kwargs else None,
|
| 114 |
+
examples_per_page=kwargs['examples_per_page'] if "examples_per_page" in kwargs else 10,
|
| 115 |
+
interpretation=kwargs['interpretation'] if "interpretation" in kwargs else None,
|
| 116 |
+
num_shap=kwargs['num_shap'] if "num_shap" in kwargs else 2.0,
|
| 117 |
+
title=kwargs['title'] if "title" in kwargs else None,
|
| 118 |
+
article=kwargs['article'] if "article" in kwargs else None,
|
| 119 |
+
thumbnail=kwargs['thumbnail'] if "thumbnail" in kwargs else None,
|
| 120 |
+
css=kwargs['css'] if "css" in kwargs else None,
|
| 121 |
+
live=kwargs['live'] if "live" in kwargs else False,
|
| 122 |
+
allow_flagging=kwargs['allow_flagging'] if "allow_flagging" in kwargs else None,
|
| 123 |
+
theme=kwargs['theme'] if "theme" in kwargs else 'default', )
|
| 124 |
+
|
| 125 |
if len(args[1:]) == (func.__code__.co_argcount - 1):
|
| 126 |
return func(*args, **wargs)
|
| 127 |
+
return None
|
| 128 |
else :
|
| 129 |
"""
|
| 130 |
the function is not a class function
|
| 131 |
"""
|
| 132 |
+
if type(inputs) is list:
|
| 133 |
+
assert len(inputs) == func.__code__.co_argcount, f"β {bcolor.BOLD}{bcolor.FAIL}inputs should have the same length as arguments{bcolor.ENDC}"
|
| 134 |
|
| 135 |
+
# if the arguments within the functions are inputed then just return the output
|
| 136 |
if len(args) == (func.__code__.co_argcount):
|
| 137 |
return func(*args, **wargs)
|
| 138 |
|
| 139 |
+
# if there is nothing in the arugumrnt then return the gradio interface
|
| 140 |
return gr.Interface(fn=func,
|
| 141 |
inputs=inputs,
|
| 142 |
outputs=outputs,
|
|
|
|
| 153 |
allow_flagging=kwargs['allow_flagging'] if "allow_flagging" in kwargs else None,
|
| 154 |
theme='default',
|
| 155 |
)
|
| 156 |
+
return decorator
|
|
|
|
|
|
|
| 157 |
return register_gradio
|
| 158 |
|
| 159 |
def GradioModule(cls):
|
| 160 |
class Decorator:
|
| 161 |
|
| 162 |
def __init__(self) -> None:
|
| 163 |
+
self.__cls__ = cls()
|
| 164 |
+
self.__get_funcs_attr()
|
| 165 |
+
self.interface = self.__compile()
|
| 166 |
+
|
| 167 |
+
def get_funcs_names(self):
|
| 168 |
+
assert self.get_registered_map() != None, "this is not possible..."
|
| 169 |
+
return [ name for name in self.get_registered_map().keys()]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
+
def get_registered_map(self):
|
| 172 |
+
assert self.__cls__.registered_gradio_functons != None, "what happen!!!!"
|
| 173 |
+
return self.__cls__.registered_gradio_functons
|
| 174 |
+
|
| 175 |
+
def __get_funcs_attr(self):
|
| 176 |
+
for func in dir(self.__cls__):
|
| 177 |
+
fn = getattr(self.__cls__, func, None)
|
| 178 |
+
if not func.startswith("__") and fn.__name__ == "decorator":
|
| 179 |
+
fn()
|
| 180 |
+
|
| 181 |
+
def __compile(self):
|
| 182 |
+
"""
|
| 183 |
+
Initialize all the function
|
| 184 |
+
within the class that are registeed
|
| 185 |
+
"""
|
| 186 |
demos, names = [], []
|
| 187 |
+
for func, param in self.get_registered_map().items():
|
| 188 |
names.append(func)
|
| 189 |
+
try:
|
| 190 |
+
demos.append(gr.Interface(fn=getattr(self.__cls__, func, None), **param))
|
| 191 |
+
except Exception as e :
|
| 192 |
+
raise e
|
| 193 |
+
|
| 194 |
+
print(f"{bcolor.OKBLUE}COMPLETED: {bcolor.ENDC}All functions are mapped, and ready to launch π",
|
| 195 |
+
"\n===========================================================\n")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
return gr.TabbedInterface(demos, names)
|
| 197 |
|
| 198 |
+
def launch(self, **kwargs):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 199 |
port= kwargs["port"] if "port" in kwargs else DOCKER_PORT.determinePort()
|
| 200 |
if 'listen' in kwargs:
|
| 201 |
try:
|
| 202 |
+
requests.post(f"http://{DOCKER_LOCAL_HOST}:{ kwargs[ 'listen' ] }/api/append/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : getfile(self.__cls__.__class__), "name" : self.__cls__.__class__.__name__, "kwargs" : kwargs})
|
| 203 |
except Exception:
|
| 204 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe listening api is either not up or you choose the wrong port.π")
|
| 205 |
return
|
| 206 |
|
| 207 |
+
self.interface.launch(server_port=port,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
server_name=f"{DOCKER_LOCAL_HOST}",
|
| 209 |
+
inline= kwargs['inline'] if "inline" in kwargs else None,
|
| 210 |
share=kwargs['share'] if "share" in kwargs else None,
|
| 211 |
debug=kwargs['debug'] if "debug" in kwargs else False,
|
| 212 |
enable_queue=kwargs['enable_queue'] if "enable_queue" in kwargs else None,
|
|
|
|
| 226 |
quiet=kwargs['quiet'] if "quiet" in kwargs else False)
|
| 227 |
if 'listen' in kwargs:
|
| 228 |
try:
|
| 229 |
+
requests.post(f"http://{DOCKER_LOCAL_HOST}:{ kwargs[ 'listen' ] }/api/remove/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : getfile(self.__cls__.__class__), "name" : self.__cls__.__class__.__name__, "kwargs" : kwargs})
|
| 230 |
except Exception:
|
| 231 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe api either lost connection or was turned off...π")
|
| 232 |
return
|
| 233 |
|
| 234 |
return Decorator
|
| 235 |
|
|
|
|
|
|
|
| 236 |
class bcolor:
|
| 237 |
HEADER = '\033[95m'
|
| 238 |
OKBLUE = '\033[94m'
|
backend/test/test.py
CHANGED
|
@@ -21,19 +21,48 @@ def Hello(name):
|
|
| 21 |
def Goodbye(name):
|
| 22 |
return f"Goodbye, {name}."
|
| 23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
class GradioFlowTestCase(unittest.TestCase):
|
| 25 |
-
|
| 26 |
def test_class_func_return(self):
|
| 27 |
-
self.assertEqual(self.
|
| 28 |
-
self.assertEqual(self.
|
| 29 |
|
|
|
|
|
|
|
| 30 |
|
| 31 |
def test_func_return(self):
|
| 32 |
self.assertEqual(Hello("Luca"), "Hello, Luca.")
|
| 33 |
self.assertEqual(Goodbye("Luca"), "Goodbye, Luca.")
|
| 34 |
-
|
| 35 |
-
|
| 36 |
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
unittest.main()
|
|
|
|
| 21 |
def Goodbye(name):
|
| 22 |
return f"Goodbye, {name}."
|
| 23 |
|
| 24 |
+
@register(['number', 'number'], ['number'], examples=[[9, 10]])
|
| 25 |
+
def add(x=0, y=0):
|
| 26 |
+
return x + y
|
| 27 |
+
|
| 28 |
+
@register(['number'], ['number'], examples=[[9, 10]])
|
| 29 |
+
def error_param(x=0, y=0):
|
| 30 |
+
return x + y
|
| 31 |
+
|
| 32 |
+
@register(['number', "number"], [], examples=[[9, 10]])
|
| 33 |
+
def error_no_output(x=0, y=0):
|
| 34 |
+
return x + y
|
| 35 |
+
|
| 36 |
+
@register(['number', "number"], "number", examples=[[9, 10]])
|
| 37 |
+
def foo(x=0, y=0):
|
| 38 |
+
return x + y
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
|
| 43 |
class GradioFlowTestCase(unittest.TestCase):
|
| 44 |
+
hodl = test()
|
| 45 |
def test_class_func_return(self):
|
| 46 |
+
self.assertEqual(self.hodl.__cls__.Hello("Luca"), "Hello, Luca.")
|
| 47 |
+
self.assertEqual(self.hodl.__cls__.Goodbye("Luca"), "Goodbye, Luca.")
|
| 48 |
|
| 49 |
+
def test_func_default_return(self):
|
| 50 |
+
self.assertEqual(add(1,1), 2)
|
| 51 |
|
| 52 |
def test_func_return(self):
|
| 53 |
self.assertEqual(Hello("Luca"), "Hello, Luca.")
|
| 54 |
self.assertEqual(Goodbye("Luca"), "Goodbye, Luca.")
|
|
|
|
|
|
|
| 55 |
|
| 56 |
+
def test_foo(self):
|
| 57 |
+
self.assertEqual(foo(1,1),2)
|
| 58 |
+
|
| 59 |
+
def test_functions_error_catch(self):
|
| 60 |
+
with self.assertRaises(AssertionError):
|
| 61 |
+
error_param()
|
| 62 |
+
|
| 63 |
+
def test_function_error_no_output(self):
|
| 64 |
+
with self.assertRaises(AssertionError):
|
| 65 |
+
error_no_output()
|
| 66 |
+
|
| 67 |
|
| 68 |
unittest.main()
|
docker-compose.yml
CHANGED
|
@@ -11,6 +11,7 @@ services:
|
|
| 11 |
ports:
|
| 12 |
- "2000:2000"
|
| 13 |
- "7860-7880:7860-7880"
|
|
|
|
| 14 |
command: "python app.py -p 2000"
|
| 15 |
frontend :
|
| 16 |
container_name: frontend
|
|
|
|
| 11 |
ports:
|
| 12 |
- "2000:2000"
|
| 13 |
- "7860-7880:7860-7880"
|
| 14 |
+
# - "8501:8501" # streamlit application test
|
| 15 |
command: "python app.py -p 2000"
|
| 16 |
frontend :
|
| 17 |
container_name: frontend
|