Spaces:
Sleeping
Sleeping
import httpx | |
from fastapi import FastAPI, Request | |
from fastapi.responses import Response, StreamingResponse, JSONResponse | |
from fastapi.middleware.cors import CORSMiddleware | |
import uvicorn | |
import subprocess | |
import signal | |
import time | |
import os | |
app = FastAPI() | |
app.add_middleware( | |
CORSMiddleware, | |
allow_origins=["*"], | |
allow_credentials=True, | |
allow_methods=["*"], | |
allow_headers=["*"], | |
) | |
PYTHON_PORT = 7860 | |
NODE_PORT = 4321 | |
NODE_SCRIPT_PATH = "build" | |
node_process = subprocess.Popen(["node", NODE_SCRIPT_PATH]) | |
def handle_sigterm(signum, frame): | |
print("Stopping Node.js server...") | |
node_process.terminate() | |
node_process.wait() | |
exit(0) | |
signal.signal(signal.SIGTERM, handle_sigterm) | |
client = httpx.AsyncClient() | |
def shutdown_event(): | |
print("Stopping Node.js server...") | |
node_process.terminate() | |
node_process.wait() | |
async def route_with_config(): | |
return JSONResponse(content={"one": "hello", "two": "from", "three": "Python"}) | |
# async def proxy_to_node(request: Request): | |
# # Preserve the full path including query parameters | |
# full_path = request.url.path | |
# if request.url.query: | |
# full_path += f"?{request.url.query}" | |
# url = f"http://localhost:{NODE_PORT}{full_path}" | |
# headers = { | |
# k: v | |
# for k, v in request.headers.items() | |
# if k.lower() not in ["host", "content-length"] | |
# } | |
# print(headers) | |
# # body = await request.body() | |
# # async with client: | |
# # response = await client.request( | |
# # method=request.method, url=url, headers=headers, content=body | |
# # ) | |
# # return StreamingResponse( | |
# # response.iter_bytes(), | |
# # status_code=response.status_code, | |
# # headers=response.headers, | |
# # ) | |
# req = client.build_request("GET", httpx.URL(url), headers=headers) | |
# r = await client.send(req, stream=True) | |
# return StreamingResponse( | |
# r.aiter_raw(), headers=r.headers | |
# ) | |
async def proxy_to_node( | |
request: Request, | |
server_name: str, | |
node_port: int, | |
python_port: int, | |
scheme: str = "http", | |
mounted_path: str = "", | |
): | |
start_time = time.time() | |
full_path = request.url.path | |
if mounted_path: | |
full_path = full_path.replace(mounted_path, "") | |
if request.url.query: | |
full_path += f"?{request.url.query}" | |
url = f"{scheme}://{server_name}:{node_port}{full_path}" | |
headers = dict(request.headers) | |
print( | |
headers, | |
) | |
server_url = f"{scheme}://{server_name}" | |
if python_port: | |
server_url += f":{python_port}" | |
if mounted_path: | |
server_url += mounted_path | |
headers["x-gradio-server"] = server_url | |
headers["x-gradio-port"] = str(python_port) | |
print( | |
f"Proxying request from {request.url.path} to {url} with server url {server_url}" | |
) | |
if os.getenv("GRADIO_LOCAL_DEV_MODE"): | |
headers["x-gradio-local-dev-mode"] = "1" | |
print(f"Time to prepare request: {time.time() - start_time:.4f} seconds") | |
print( | |
f"Total setup time before streaming: {time.time() - start_time:.4f} seconds" | |
) | |
req = client.build_request(request.method, httpx.URL(url), headers=headers) | |
r = await client.send(req) | |
print(f"Time to prepare request: {time.time() - start_time:.4f} seconds") | |
print(f"\nHeaders: {r.headers}\n") | |
return Response( | |
content=r.content, | |
status_code=r.status_code, | |
headers=dict(r.headers), | |
) | |
async def catch_all(request: Request, path: str): | |
return await proxy_to_node( | |
request, | |
"0.0.0.0", | |
4321, | |
request.url.port, | |
request.url.scheme, | |
"", | |
) | |
if __name__ == "__main__": | |
print( | |
f"Starting dual server. Python handles specific routes, Node handles the rest." | |
) | |
uvicorn.run(app, host="0.0.0.0", port=PYTHON_PORT) | |