feat: backend reverse proxy

This commit is contained in:
Timothy J. Baek 2023-11-14 16:28:51 -08:00
parent 611b10a79d
commit 6a9bef755b
13 changed files with 179 additions and 13 deletions

2
backend/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
__pycache__
.env

View file

@ -0,0 +1,55 @@
from flask import Flask, request, Response
from flask_cors import CORS
import requests
import json
from config import OLLAMA_API_BASE_URL
app = Flask(__name__)
CORS(
app
) # Enable Cross-Origin Resource Sharing (CORS) to allow requests from different domains
# Define the target server URL
TARGET_SERVER_URL = OLLAMA_API_BASE_URL
@app.route("/", defaults={"path": ""}, methods=["GET", "POST", "PUT", "DELETE"])
@app.route("/<path:path>", methods=["GET", "POST", "PUT", "DELETE"])
def proxy(path):
# Combine the base URL of the target server with the requested path
target_url = f"{TARGET_SERVER_URL}/{path}"
print(target_url)
# Get data from the original request
data = request.get_data()
headers = dict(request.headers)
# Make a request to the target server
target_response = requests.request(
method=request.method,
url=target_url,
data=data,
headers=headers,
stream=True, # Enable streaming for server-sent events
)
# Proxy the target server's response to the client
def generate():
for chunk in target_response.iter_content(chunk_size=8192):
yield chunk
response = Response(generate(), status=target_response.status_code)
# Copy headers from the target server's response to the client's response
for key, value in target_response.headers.items():
response.headers[key] = value
return response
if __name__ == "__main__":
app.run(debug=True)

15
backend/config.py Normal file
View file

@ -0,0 +1,15 @@
import sys
import os
from dotenv import load_dotenv, find_dotenv
load_dotenv(find_dotenv())
ENV = os.environ.get("ENV", "dev")
OLLAMA_API_BASE_URL = os.environ.get(
"OLLAMA_API_BASE_URL", "http://localhost:11434/api"
)
if ENV == "prod":
if OLLAMA_API_BASE_URL == "/ollama/api":
OLLAMA_API_BASE_URL = "http://host.docker.internal:11434/api"

1
backend/dev.sh Normal file
View file

@ -0,0 +1 @@
uvicorn main:app --port 8080 --reload

51
backend/main.py Normal file
View file

@ -0,0 +1,51 @@
import time
import sys
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi import HTTPException
from starlette.exceptions import HTTPException as StarletteHTTPException
from fastapi.middleware.wsgi import WSGIMiddleware
from fastapi.middleware.cors import CORSMiddleware
from apps.ollama.main import app as ollama_app
class SPAStaticFiles(StaticFiles):
async def get_response(self, path: str, scope):
try:
return await super().get_response(path, scope)
except (HTTPException, StarletteHTTPException) as ex:
if ex.status_code == 404:
return await super().get_response("index.html", scope)
else:
raise ex
app = FastAPI()
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.middleware("http")
async def check_url(request: Request, call_next):
start_time = int(time.time())
response = await call_next(request)
process_time = int(time.time()) - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
app.mount("/ollama/api", WSGIMiddleware(ollama_app))
app.mount("/", SPAStaticFiles(directory="../build", html=True), name="spa-static-files")

19
backend/requirements.txt Normal file
View file

@ -0,0 +1,19 @@
fastapi
uvicorn[standard]
pydantic
python-multipart
flask
flask_cors
python-socketio
python-jose
passlib[bcrypt]
uuid
requests
pymongo
bcrypt
PyJWT
pyjwt[crypto]

1
backend/start.sh Normal file
View file

@ -0,0 +1 @@
uvicorn main:app --host 0.0.0.0 --port 8080