SatCat's picture
Create app.py
8a10f4e
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)