File size: 4,348 Bytes
8a10f4e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import asyncio
from starlette.applications import Starlette
from starlette.endpoints import WebSocketEndpoint, HTTPEndpoint
from starlette.responses import HTMLResponse
from starlette.routing import Route, WebSocketRoute, Mount
from starlette.websockets import WebSocket
from starlette.types import Message, Receive, Scope, Send

# -------------------- gradio ------------------------
import gradio as gr

async def name_fn(name):
    await mbase.add_msg(f'gradio_name: {name}')
    return "Name: " + name + "!"

io = gr.Interface(fn=name_fn, inputs=gr.Textbox(lines=2, placeholder="Name Here..."), outputs="text")
gradio_app = gr.routes.App.create_app(io)

# -------------------- shiny ------------------------
import shiny 
from shiny import App, render, ui, reactive
import numpy as np
import matplotlib.pyplot as plt

app_ui = ui.page_fluid(
    ui.input_slider("n", "Number of bins", 1, 100, 20),
    ui.output_plot("plot", width='30%', height='120px'),
)

def server(input, output, session):
    @output
    @render.plot(alt="A histogram")
    async def plot():
        await mbase.add_msg(f'shiny_bin: {input.n()}')
        x = 100 + 15 * np.random.randn(120)
        fig, ax = plt.subplots()
        ax.hist(x, input.n(), density=True)
        return fig
     
    
app_shiny = App(ui = app_ui, server = server)

# -------------------- main + msg store and dispatch ------------------------
ws_list = []

class MsgBase():
    """ Store and send messages to clients """
    msg_history = ['start logging..',]
    
    async def add_msg(self, msg):
        self.msg_history.insert(0, msg)
        if len(self.msg_history) > 15:
            self.msg_history.pop()
        for ws in ws_list:
            await ws.send_text(msg)
            
    async def send_all_msg(self, ws):
        """ Restore all messages in new page or reloaded page"""
        ws_list.append(ws)
        for msg in self.msg_history:
            await ws.send_text(msg)

mbase = MsgBase()        


html = """
<!DOCTYPE html>
<html><head><title>Shiny and Gradio Test App</title>
        <style> 
            .bottom_div { position:absolute; background: #E8F8E8; bottom:0; width:99%; height:100px; max-height: 30%; overflow-y: auto;} 
            .log_msg { font-size: 0.75em; font-family: sans-serif; padding: .2em; margin: 0; line-height: 1em;} 
        </style>
    </head>
    <body>
       <script type="text/javascript">
            var ws = new WebSocket("ws://localhost:8000/ws");
            ws.onmessage = function(event) {
                var newNode = document.createElement('li');
                var content = document.createTextNode(event.data);
                newNode.appendChild(content);
                var messages = document.getElementById('log_msg'); 
                messages.insertBefore(newNode, messages.children[0]);
                
                // remove last evement
                remove_idx = messages.getElementsByTagName("li").length -1;
                if (remove_idx > 15) {
                     messages.children[remove_idx].remove();
                }
                
            }
       </script>
       Shiny App
       <iframe src="/shiny/" width="100%" height="250" style="border:1px solid blue;"></iframe>
       Gradio App
       <iframe src="/gradio/" width="100%" height="250" style="border:1px solid red;"></iframe>
       <div class="bottom_div"><ul class="log_msg" id="log_msg"></ul></div> 
    </body>
</html>"""

class Homepage(HTTPEndpoint):
    async def get(self, request):
        return HTMLResponse(html)

class Echo(WebSocketEndpoint):
    async def on_connect(self, websocket: WebSocket) -> None:
        await websocket.accept()
        await mbase.send_all_msg(websocket)
        
    async def on_disconnect(self, websocket: WebSocket, close_code: int) -> None:
        ws_list.remove(websocket)
        
routes = [
    Route("/", Homepage),
    WebSocketRoute("/ws", Echo),
    Mount('/shiny', app=app_shiny),
    Mount('/gradio', app=gradio_app)
]
app = Starlette(routes=routes)


# as a main work loop..
@app.on_event("startup")  
async def startup_event():
    asyncio.create_task(dispatch_task())

async def dispatch_task():
    """ background task to dispatch autonomous events """
    for i in range(20):
        await mbase.add_msg(f'(main loop) I am work!({i})')
        await asyncio.sleep(8)