diff --git a/.env b/.env new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.local.yml b/docker-compose.local.yml new file mode 100644 index 0000000..75e4334 --- /dev/null +++ b/docker-compose.local.yml @@ -0,0 +1,48 @@ +services: + traefik: + image: traefik:v2.0 + container_name: "explorer-proxy-local-traefik" + command: + - --providers.docker=true + # Enable the API handler in insecure mode, + # which means that the Traefik API will be available directly + # on the entry point named traefik. + - --api.insecure=true + # Define Traefik entry points to port [80] for http and port [443] for https. + - --entrypoints.invariant-explorer-proxy-web.address=0.0.0.0:80 + - --log.level=INFO + networks: + - invariant-explorer-proxy-web + ports: + - '${PORT_HTTP:-80}:80' + volumes: + - /var/run/docker.sock:/var/run/docker.sock + labels: + - "traefik.enable=true" + - "traefik.http.routers.traefik-http.entrypoints=invariant-explorer-proxy-web" + + explorer-proxy: + build: + context: ./proxy + dockerfile: ../proxy/Dockerfile.proxy + working_dir: /srv/proxy + env_file: + - .env + environment: + - DEV_MODE=true + networks: + - internal + - invariant-explorer-proxy-web + ports: + - "8001:8000" + labels: + - "traefik.enable=true" + - "traefik.http.routers.explorer-proxy-api.rule=(Host(`localhost`) && PathPrefix(`/api/v1/proxy/`)) || (Host(`127.0.0.1`) && PathPrefix(`/api/v1/proxy/`))" + - "traefik.http.routers.explorer-proxy-api.entrypoints=invariant-explorer-proxy-web" + - "traefik.http.services.explorer-proxy-api.loadbalancer.server.port=8000" + - "traefik.docker.network=invariant-explorer-proxy-web" + +networks: + invariant-explorer-proxy-web: + external: true + internal: \ No newline at end of file diff --git a/proxy/Dockerfile.proxy b/proxy/Dockerfile.proxy new file mode 100644 index 0000000..906df0e --- /dev/null +++ b/proxy/Dockerfile.proxy @@ -0,0 +1,9 @@ +FROM python:3.10 + +COPY ./requirements.txt /srv/proxy/requirements.txt +WORKDIR /srv/proxy + +RUN pip install --no-cache-dir -r requirements.txt +COPY . /srv/proxy + +ENTRYPOINT ./run.sh \ No newline at end of file diff --git a/proxy/proxy.py b/proxy/proxy.py new file mode 100644 index 0000000..0ba465b --- /dev/null +++ b/proxy/proxy.py @@ -0,0 +1,11 @@ +"""Proxy service to forward requests to the appropriate language model provider""" + +from fastapi import FastAPI + +proxy = FastAPI() + + +@proxy.post("/u/{username}/{dataset_name}/{llm_provider}") +async def chat_completion(username: str, dataset_name: str, llm_provider: str): + """Proxy call to a language model provider""" + return {"message": f"Upload {dataset_name} for {username} to {llm_provider}"} diff --git a/proxy/requirements.txt b/proxy/requirements.txt new file mode 100644 index 0000000..f0615cf --- /dev/null +++ b/proxy/requirements.txt @@ -0,0 +1,2 @@ +fastapi +uvicorn \ No newline at end of file diff --git a/proxy/run.sh b/proxy/run.sh new file mode 100644 index 0000000..54b8698 --- /dev/null +++ b/proxy/run.sh @@ -0,0 +1,7 @@ +#/bin/bash +# if DEV_MODE is true, then run the app with auto-reload +if [ "$DEV_MODE" = "true" ]; then + uvicorn serve:proxy_app --host 0.0.0.0 --port 8000 --reload +else + uvicorn serve:proxy_app --host 0.0.0.0 --port 8000 +fi diff --git a/proxy/serve.py b/proxy/serve.py new file mode 100644 index 0000000..d5e8715 --- /dev/null +++ b/proxy/serve.py @@ -0,0 +1,27 @@ +"""Serve the API""" + +import fastapi +from proxy import proxy + +v1 = fastapi.FastAPI() + +# install the API routes +v1.mount("/proxy", proxy) + + +# for debugging, we can check if the API is up +@v1.get("/") +async def home(): + """Check if the API is up""" + return {"message": "Hello v1 proxy"} + + +# mount the API under /api/v1 +proxy_app = fastapi.FastAPI() +proxy_app.mount("/api/v1", v1) + +# serve the API +if __name__ == "__main__": + import uvicorn + + uvicorn.run(proxy_app, host="0.0.0.0", port=8000)