CORVO-AI commited on
Commit
0c626a7
·
verified ·
1 Parent(s): 7289b1b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -18
app.py CHANGED
@@ -3,13 +3,15 @@ import gradio as gr
3
  import subprocess, os, sys, time
4
  import urllib.request, urllib.error
5
  from fastapi import Request
6
- from fastapi.responses import Response, PlainTextResponse, HTMLResponse
7
 
8
  PORT = 9001
9
  FM_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "file-manager")
10
  MODEL_ID = "Qwen/Qwen2.5-0.5B-Instruct"
11
 
12
- # --- Launch the file manager as a background child process ---
 
 
13
  proc = {"p": None}
14
  def start_fm():
15
  if proc["p"] and proc["p"].poll() is None:
@@ -23,7 +25,9 @@ def start_fm():
23
 
24
  start_fm()
25
 
26
- # --- GPU info: runs nvidia-smi INSIDE the gate (GPU only attached here) ---
 
 
27
  @spaces.GPU
28
  def gpu_report():
29
  import torch
@@ -41,7 +45,9 @@ def gpu_report():
41
  lines.append(f"nvidia-smi error: {e}")
42
  return "\n".join(lines)
43
 
44
- # --- LLM inference: model loads + generates INSIDE the gate ---
 
 
45
  _state = {"model": None, "tok": None}
46
 
47
  @spaces.GPU
@@ -60,9 +66,11 @@ def run_llm(prompt: str):
60
  reply = tok.decode(out[0][inputs.input_ids.shape[1]:], skip_special_tokens=True)
61
  return f"[GPU: {torch.cuda.get_device_name(0)}]\n\n{reply}"
62
 
63
- # --- Gradio owns the ONLY public port 7860 ---
 
 
64
  with gr.Blocks() as demo:
65
- gr.Markdown("Self-editing computer. File manager + terminal at /fm")
66
  with gr.Row():
67
  prompt = gr.Textbox(label="Ask the LLM")
68
  out = gr.Textbox(label="Reply")
@@ -74,26 +82,36 @@ demo.queue()
74
  demo.launch(server_name="0.0.0.0", server_port=7860,
75
  ssr_mode=False, prevent_thread_lock=True)
76
 
77
- app = demo.app
78
 
79
- # --- Hot-reload: respawn ONLY the file-manager process, no Space rebuild ---
 
 
80
  @app.get("/reload")
81
  def reload_fm():
82
  start_fm()
83
  time.sleep(1)
84
  return HTMLResponse('Reloaded file-manager process. <a href="/fm/">back to /fm</a>')
85
 
86
- # --- GPU info route ---
 
 
87
  @app.get("/gpuinfo")
88
  def gpuinfo():
89
  return PlainTextResponse(gpu_report())
90
 
91
- # --- LLM route ---
 
 
92
  @app.get("/llm")
93
  def llm(q: str = "Say hello and tell me which GPU you are running on."):
94
  return PlainTextResponse(run_llm(q))
95
 
96
- # --- Proxy: /fm/... -> 127.0.0.1:9001/fm/... (methods + body forwarded) ---
 
 
 
 
97
  @app.api_route("/fm", methods=["GET", "POST"])
98
  @app.api_route("/fm/{path:path}", methods=["GET", "POST"])
99
  async def proxy(request: Request, path: str = ""):
@@ -104,16 +122,33 @@ async def proxy(request: Request, path: str = ""):
104
  fwd = {k: v for k, v in request.headers.items() if k.lower() != "host"}
105
  req = urllib.request.Request(url, data=body or None, method=request.method, headers=fwd)
106
  try:
107
- with urllib.request.urlopen(req) as r:
108
- data, status, headers = r.read(), r.status, r.headers
109
  except urllib.error.HTTPError as e:
110
- data, status, headers = e.read(), e.code, e.headers
 
 
111
  except urllib.error.URLError:
112
  return Response(content=b"file-manager not up yet on 9001", status_code=502)
113
- out = {k: v for k, v in headers.items()
114
- if k.lower() in ("set-cookie", "location", "content-type")}
115
- return Response(content=data, status_code=status, headers=out)
116
 
117
- # --- Keep the process alive (launch returned control) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  while True:
119
  time.sleep(3600)
 
3
  import subprocess, os, sys, time
4
  import urllib.request, urllib.error
5
  from fastapi import Request
6
+ from fastapi.responses import Response, PlainTextResponse, HTMLResponse, StreamingResponse
7
 
8
  PORT = 9001
9
  FM_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "file-manager")
10
  MODEL_ID = "Qwen/Qwen2.5-0.5B-Instruct"
11
 
12
+ # =================================================================
13
+ # Launch the file manager as a background child process
14
+ # =================================================================
15
  proc = {"p": None}
16
  def start_fm():
17
  if proc["p"] and proc["p"].poll() is None:
 
25
 
26
  start_fm()
27
 
28
+ # =================================================================
29
+ # GPU info: runs nvidia-smi INSIDE the gate (GPU only attached here)
30
+ # =================================================================
31
  @spaces.GPU
32
  def gpu_report():
33
  import torch
 
45
  lines.append(f"nvidia-smi error: {e}")
46
  return "\n".join(lines)
47
 
48
+ # =================================================================
49
+ # LLM inference: model loads + generates INSIDE the gate
50
+ # =================================================================
51
  _state = {"model": None, "tok": None}
52
 
53
  @spaces.GPU
 
66
  reply = tok.decode(out[0][inputs.input_ids.shape[1]:], skip_special_tokens=True)
67
  return f"[GPU: {torch.cuda.get_device_name(0)}]\n\n{reply}"
68
 
69
+ # =================================================================
70
+ # Gradio owns the ONLY public port 7860
71
+ # =================================================================
72
  with gr.Blocks() as demo:
73
+ gr.Markdown("Self-editing computer. File manager + terminal + Python REPL at /fm")
74
  with gr.Row():
75
  prompt = gr.Textbox(label="Ask the LLM")
76
  out = gr.Textbox(label="Reply")
 
82
  demo.launch(server_name="0.0.0.0", server_port=7860,
83
  ssr_mode=False, prevent_thread_lock=True)
84
 
85
+ app = demo.app # Gradio's FastAPI app on 7860
86
 
87
+ # =================================================================
88
+ # Hot-reload: respawn ONLY the file-manager process, no Space rebuild
89
+ # =================================================================
90
  @app.get("/reload")
91
  def reload_fm():
92
  start_fm()
93
  time.sleep(1)
94
  return HTMLResponse('Reloaded file-manager process. <a href="/fm/">back to /fm</a>')
95
 
96
+ # =================================================================
97
+ # GPU info route
98
+ # =================================================================
99
  @app.get("/gpuinfo")
100
  def gpuinfo():
101
  return PlainTextResponse(gpu_report())
102
 
103
+ # =================================================================
104
+ # LLM route
105
+ # =================================================================
106
  @app.get("/llm")
107
  def llm(q: str = "Say hello and tell me which GPU you are running on."):
108
  return PlainTextResponse(run_llm(q))
109
 
110
+ # =================================================================
111
+ # Proxy: /fm/... -> 127.0.0.1:9001/fm/...
112
+ # Streams text/plain (live shell) chunk by chunk; buffers everything else.
113
+ # Forwards method + body so POST forms and the JSON REPL work.
114
+ # =================================================================
115
  @app.api_route("/fm", methods=["GET", "POST"])
116
  @app.api_route("/fm/{path:path}", methods=["GET", "POST"])
117
  async def proxy(request: Request, path: str = ""):
 
122
  fwd = {k: v for k, v in request.headers.items() if k.lower() != "host"}
123
  req = urllib.request.Request(url, data=body or None, method=request.method, headers=fwd)
124
  try:
125
+ r = urllib.request.urlopen(req)
 
126
  except urllib.error.HTTPError as e:
127
+ return Response(
128
+ content=e.read(), status_code=e.code,
129
+ headers={"content-type": e.headers.get("content-type", "text/plain")})
130
  except urllib.error.URLError:
131
  return Response(content=b"file-manager not up yet on 9001", status_code=502)
 
 
 
132
 
133
+ ctype = r.headers.get("content-type", "text/html")
134
+ # Stream the live shell output; buffer normal pages
135
+ if ctype.startswith("text/plain"):
136
+ def gen():
137
+ while True:
138
+ chunk = r.read(1024)
139
+ if not chunk:
140
+ break
141
+ yield chunk
142
+ return StreamingResponse(gen(), media_type="text/plain")
143
+
144
+ out_headers = {"content-type": ctype}
145
+ for k, v in r.headers.items():
146
+ if k.lower() in ("set-cookie", "location"):
147
+ out_headers[k] = v
148
+ return Response(content=r.read(), status_code=r.status, headers=out_headers)
149
+
150
+ # =================================================================
151
+ # Keep the process alive (launch returned control)
152
+ # =================================================================
153
  while True:
154
  time.sleep(3600)