From 92c7d0a75b0860c109dc036fa3c78552362a469a Mon Sep 17 00:00:00 2001 From: Duc Nguyen Date: Wed, 12 Jul 2023 18:50:33 -0400 Subject: [PATCH] WIP --- front_end/public/{ => assets}/favicon.ico | Bin front_end/public/{ => assets}/manifest.json | 0 front_end/public/{ => assets}/robots.txt | 0 front_end/public/index.html | 4 +- front_end/public/{ => styles}/styles.css | 0 llm_gateway/_version.py | 4 + llm_gateway/app.py | 97 +++++++++++++++----- llm_gateway/cli.py | 32 +++++++ poetry.lock | 8 +- pyproject.toml | 33 ------- setup.py | 63 +++++++++++++ 11 files changed, 180 insertions(+), 61 deletions(-) rename front_end/public/{ => assets}/favicon.ico (100%) rename front_end/public/{ => assets}/manifest.json (100%) rename front_end/public/{ => assets}/robots.txt (100%) rename front_end/public/{ => styles}/styles.css (100%) create mode 100644 llm_gateway/_version.py create mode 100644 llm_gateway/cli.py delete mode 100644 pyproject.toml create mode 100644 setup.py diff --git a/front_end/public/favicon.ico b/front_end/public/assets/favicon.ico similarity index 100% rename from front_end/public/favicon.ico rename to front_end/public/assets/favicon.ico diff --git a/front_end/public/manifest.json b/front_end/public/assets/manifest.json similarity index 100% rename from front_end/public/manifest.json rename to front_end/public/assets/manifest.json diff --git a/front_end/public/robots.txt b/front_end/public/assets/robots.txt similarity index 100% rename from front_end/public/robots.txt rename to front_end/public/assets/robots.txt diff --git a/front_end/public/index.html b/front_end/public/index.html index f22e966..19e3aed 100644 --- a/front_end/public/index.html +++ b/front_end/public/index.html @@ -4,9 +4,9 @@ LLM Gateway - + - + diff --git a/front_end/public/styles.css b/front_end/public/styles/styles.css similarity index 100% rename from front_end/public/styles.css rename to front_end/public/styles/styles.css diff --git a/llm_gateway/_version.py b/llm_gateway/_version.py new file mode 100644 index 0000000..81c9261 --- /dev/null +++ b/llm_gateway/_version.py @@ -0,0 +1,4 @@ +# file generated by setuptools_scm +# don't change, don't track in version control +__version__ = version = "0.1.1.dev4" +__version_tuple__ = version_tuple = (0, 1, 1, "dev4") diff --git a/llm_gateway/app.py b/llm_gateway/app.py index 54b87a1..566e46c 100644 --- a/llm_gateway/app.py +++ b/llm_gateway/app.py @@ -15,37 +15,90 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pathlib + from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import HTMLResponse +from fastapi.staticfiles import StaticFiles from llm_gateway.routers import cohere_api, openai_api -app = FastAPI() -app.title = "LLM Proxy" -app.description = "LLM Proxy Developed by Wealthsimple" +def create_bare_app() -> FastAPI: + app = FastAPI() + app.title = "LLM Proxy" + app.description = "LLM Proxy Developed by Wealthsimple" + return app + + +def attach_api_service(app: FastAPI) -> FastAPI: + api = FastAPI(openapi_prefix="/api") + api.include_router(openai_api.router, prefix="/openai") + api.include_router(cohere_api.router, prefix="/cohere") + + @api.get("/healthcheck") + async def healthcheck(): + """ + Endpoint to verify that the service is up and running + """ + return {"message": "llm-gateway is healthy"} + + app.mount("/api", api, name="api") + return app + + +def attach_middleware(app: FastAPI) -> FastAPI: + # Allow Front-end Origin in local development + origins = ["http://localhost:3000"] + + app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + return app + + +def mount_front_end(app: FastAPI) -> FastAPI: + FRONT_END_BUILD_DIRECTORY = ( + pathlib.Path(__file__).parent.parent / "front_end" / "build" + ) + app.mount( + "/assets", + StaticFiles(directory=FRONT_END_BUILD_DIRECTORY / "assets"), + name="assets", + ) + + app.mount( + "/static", + StaticFiles(directory=FRONT_END_BUILD_DIRECTORY / "static"), + name="static", + ) + + app.mount( + "/styles", + StaticFiles(directory=FRONT_END_BUILD_DIRECTORY / "styles"), + name="styles", + ) -api = FastAPI(openapi_prefix="/api") -api.include_router(openai_api.router, prefix="/openai") -api.include_router(cohere_api.router, prefix="/cohere") + @app.get("/") + async def home() -> HTMLResponse: + with open(FRONT_END_BUILD_DIRECTORY / "index.html", "r", encoding="utf-8") as f: + return HTMLResponse(f.read()) -app.mount("/api", api, name="api") + return app -# Allow Front-end Origin in local development -origins = ["http://localhost:3000"] -app.add_middleware( - CORSMiddleware, - allow_origins=origins, - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) +def create_app() -> FastAPI: + app = create_bare_app() + app = attach_middleware(app) + app = mount_front_end(app) + app = attach_api_service(app) + print("Finished app initialization ") + return app -@api.get("/healthcheck") -async def healthcheck(): - """ - Endpoint to verify that the service is up and running - """ - return {"message": "llm-gateway is healthy"} +app = create_app() diff --git a/llm_gateway/cli.py b/llm_gateway/cli.py new file mode 100644 index 0000000..3c3e2f1 --- /dev/null +++ b/llm_gateway/cli.py @@ -0,0 +1,32 @@ +import click + + +@click.group(no_args_is_help=True) +def cli(): + pass + + +@cli.command("start") +@click.option( + "--host", + type=str, + help="Bind socket to this host. Default: 127.0.0.1", +) +@click.option( + "--port", + type=int, + help="Bind socket to this port. Default: 8000", +) +def start( + host=None, + port=None, +): + import uvicorn + + host = host or "127.0.0.1" + port = 8000 if port is None else port + uvicorn.run("llm_gateway.app:app", host=host, port=port, log_level="info") + + +if __name__ == "__main__": + cli() diff --git a/poetry.lock b/poetry.lock index 343cd3e..515fc96 100644 --- a/poetry.lock +++ b/poetry.lock @@ -366,14 +366,14 @@ files = [ [[package]] name = "click" -version = "8.1.3" +version = "8.1.4" description = "Composable command line interface toolkit" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, + {file = "click-8.1.4-py3-none-any.whl", hash = "sha256:2739815aaa5d2c986a88f1e9230c55e17f0caad3d958a5e13ad0797c166db9e3"}, + {file = "click-8.1.4.tar.gz", hash = "sha256:b97d0c74955da062a7d4ef92fadb583806a585b2ea81958a81bd72726cbb8e37"}, ] [package.dependencies] @@ -2037,4 +2037,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = "3.11.*" -content-hash = "b6cc8d020d3452611da92779246deb064100ee2e4fde1ad8f236d94458a55825" +content-hash = "21d0c214ebcb9a7b94264a03fc407d9cff516a6ae23269876fc2af73878b12ef" diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 947f389..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,33 +0,0 @@ -[tool.poetry] -name = "llm-gateway" -version = "0.1.0" -description = "Service to facilitate access to large language models" -authors = ["Data Science & Engineering @ Wealthsimple "] -license = "Apache-2.0" -readme = "README.md" - -[tool.poetry.dependencies] -python = "3.11.*" -fastapi = "^0.95.0" -pydantic = "^1.10.7" -psycopg2-binary = "~2.9.3" -alembic = "~1.8.0" -sqlalchemy = ">=1.3.0" -uvicorn = {extras = ["standard"], version = "^0.21.1"} -openai = {extras = ["datalib"], version = "^0.27.4"} -cohere = "^4.6.1" - -[tool.poetry.group.dev.dependencies] -black = "23.3.0" -isort = "5.12.0" -flake8 = "^6.0.0" -pre-commit = "^3.2.2" -pytest = "^7.3.0" -urllib3 = "1.26.15" # https://github.com/psf/requests/issues/6437 - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" - -[tool.isort] -profile = "black" diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..33017e4 --- /dev/null +++ b/setup.py @@ -0,0 +1,63 @@ +import os +from os.path import exists + +from setuptools import find_packages, setup + +description = open("README.md").read() if exists("README.md") else "" + +setup( + name="llm_gateway", + description="", + long_description=description, + long_description_content_type="text/markdown", + url="https://github.com/wealthsimple/llm-gateway", + author="Wealthsimple Data Science & Engineering", + author_email="data@wealthsimple.com", + license="Apache License 2.0", + packages=find_packages(include=["llm_gateway", "front_end"]), + package_data={"front_end": ["front_end/**"]}, + entry_points={ + "console_scripts": [ + "llm_gateway = llm_gateway.cli:cli", + ], + }, + use_scm_version={ + "write_to": "llm_gateway/_version.py", + "fallback_version": "0.0.0", + "local_scheme": "no-local-version", + }, + setup_requires=["setuptools_scm"], + install_requires=[ + "click", + "fastapi>=0.95.0", + "pydantic>=1.10.7", + "psycopg2-binary~=2.9.3", + "alembic~=1.8.0", + "sqlalchemy>=1.3.0", + "uvicorn[standard]>=0.21.1", + "openai[datalib]>=0.27.4", + "cohere>=4.6.1", + "click>=8.1.4", + ], + extras_require={ + "openai": [ + "datalib", + ], + "dev": [ + "black==23.3.0", + "isort==5.12.0", + "flake8>=6.0.0", + "pre-commit>=3.2.2", + "pytest>=7.3.0", + "urllib3==1.26.15", + ], + }, + classifiers=[ + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", + ], +)