File size: 1,545 Bytes
84c35be
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import asyncio, gradio as gr
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])

# WebSocket terminal
@app.websocket("/ws")
async def ws_terminal(ws: WebSocket):
    await ws.accept()
    await ws.send_text("Connected to terminal\n")
    try:
        while True:
            cmd = await ws.receive_text()
            proc = await asyncio.create_subprocess_shell(cmd,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE)
            out, err = await proc.communicate()
            msg = (out + err).decode()
            await ws.send_text(msg)
    except WebSocketDisconnect:
        print("Client disconnected")

# Gradio UI
JS = """
<script>
  const ws = new WebSocket(`ws://${location.host}/ws`);
  ws.onmessage = e => {
    const o = document.getElementById("out");
    o.value += e.data + "\\n";
    o.scrollTop = o.scrollHeight;
  };
  function sendCmd(e) {
    if (e.key === "Enter") {
      ws.send(e.target.value);
      e.target.value = "";
    }
  }
</script>
<textarea id="out" rows="20" style="width:100%;" readonly></textarea>
<input id="inp" style="width:100%;" placeholder="cmd…" onkeydown="sendCmd(event)">
"""

with gr.Blocks() as demo:
    gr.Markdown("## 🖥️ Interactive Terminal")
    gr.HTML(JS)

# Launch Gradio on port 7861
gr_app = gr.mount_gradio_app(app, demo, path="/gradio", server_port=7861)