Skip to content

Commit

Permalink
0.6.5: fix: handle multiple middlewares and document it, add example
Browse files Browse the repository at this point in the history
  • Loading branch information
louis030195 committed Feb 16, 2023
1 parent 86466cd commit 4d8daf9
Show file tree
Hide file tree
Showing 22 changed files with 29,232 additions and 27 deletions.
29 changes: 25 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,8 @@ Currently adding middleware is very similar to [how it is done in FastAPI](https

```py
# MYROOTPROJECT/middlewares/my_custom_middleware/my_custom_middleware.py
def middleware(app: FastAPI):
@app.middleware("http")
async def my_custom_middleware(request: Request, call_next) -> Tuple[str, str]:
class MyCustomMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next) -> Tuple[str, str]:
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
Expand All @@ -165,9 +164,31 @@ COPY ./middlewares/my_custom_middleware/my_custom_middleware.py /app/middlewares
# MYROOTPROJECT/config.yaml
# ...
middlewares:
- middlewares.my_custom_middleware
- middlewares.my_custom_middleware.my_custom_middleware.MyCustomMiddleware
```

```bash
curl -X POST -H "Content-Type: application/json" -d '{"query": "Bob"}' http://localhost:8080/v1/people/search | jq '.'
```

```json
{
"query": "Bob",
"similarities": [
{
"score": 0.828773,
"id": "ABCU75FEBE",
"data": "Elon is sipping a tea on Mars",
}
],
"headers": {
"x-process-time": "0.0001239776611328125"
}
}
```

Please see [examples](./examples/simple-react-custom-middleware) for more details and a concrete example.


## Deployment

Expand Down
8 changes: 6 additions & 2 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@ openai_api_key: "sk-xxxxxxx"
openai_organization: "org-xxxxx"

# authentication
# authentication: firebase # only firebase is supported for now
# firebase_service_account_path: "path/to/service-account.json"
# auth: firebase # only firebase is supported for now
# firebase_service_account_path: "path/to/service-account.json"

# middlewares:
# - middlewares.enrich.enrich.Enrich
# - middlewares.processing_time.processing_time.ProcessingTime
43 changes: 27 additions & 16 deletions embedbase/api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import asyncio
import hashlib
from multiprocessing.pool import ThreadPool
import time
from pandas import DataFrame
import os
Expand All @@ -9,6 +8,7 @@
import typing
import logging
from fastapi import Depends, FastAPI, Request, status
from fastapi.middleware import Middleware
from fastapi.middleware.cors import CORSMiddleware
from embedbase.models import (
DeleteRequest,
Expand Down Expand Up @@ -44,8 +44,33 @@
handler.setFormatter(formatter)
logger.addHandler(handler)

middlewares = []
if settings.middlewares:
from starlette.middleware import Middleware
for i, m in enumerate(settings.middlewares):
# import python file at path m
# and add the first class found to the list

try:
logger.debug("Importing middleware", m)
segments = m.split(".")
logger.debug("Segments", segments)
module_name = ".".join(segments[0:-1])
logger.debug("Module name", module_name)
class_name = segments[-1]
logger.debug("Class name", class_name)
module = __import__(module_name, fromlist=[class_name])
logger.debug("Module", module)
dirs = dir(module)
logger.debug("Dirs", dirs)
middleware_class = getattr(module, class_name)
logger.debug("Middleware class", middleware_class)
middlewares.append(Middleware(middleware_class))
except Exception as e:
logger.error(f"Error loading middleware {m}: {e}")


app = FastAPI()
app = FastAPI(middleware=middlewares)

if settings.sentry:
logger.info("Enabling Sentry")
Expand Down Expand Up @@ -108,20 +133,6 @@ async def firebase_auth(request: Request, call_next) -> Tuple[str, str]:
return response


if settings.middlewares:
for i, m in enumerate(settings.middlewares):
# import python file at path m
# and call middleware(app)

try:
module = __import__(m, fromlist=["middleware"])
module.middleware(app)
# Verify contents of the module:
print(dir(module))

logger.info(f"Loaded middleware {m}")
except Exception as e:
logger.error(f"Error loading middleware {m}: {e}")


app.add_middleware(
Expand Down
13 changes: 11 additions & 2 deletions examples/simple-react-auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ It is identical to [simple-react](https://github.com/another-ai/embedbase/tree/m
b. On the Sign in method tab, enable the Google sign-in method and click Save.

3. [Get your Firebase config](https://console.firebase.google.com/u/0/project/obsidian-ai/settings/general/web:NjRmMWIwZDAtMmE3OC00YTM5LThlMjItYzcxZWUzM2I2NjQ5) and add it to the `src/fb.json` file
4. `npm i`
5. `npm start`


```bash
docker-compose up
```

Start the front-end in another terminal:

```bash
npm i
npm start
```
23 changes: 23 additions & 0 deletions examples/simple-react-custom-middleware/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
3 changes: 3 additions & 0 deletions examples/simple-react-custom-middleware/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM ghcr.io/another-ai/embedbase:latest
COPY ./middlewares/processing_time/processing_time.py /app/middlewares/processing_time.py
COPY ./middlewares/enrich/enrich.py /app/middlewares/enrich.py
26 changes: 26 additions & 0 deletions examples/simple-react-custom-middleware/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## simple-react

This is a simple React app that is using **Embedbase**.

Add this to your `config.yaml`:
```yaml
# ...
middlewares:
- middlewares.processing_time
# ...
```

```bash
docker-compose up
```

Start the front-end from another terminal:

```bash
npm i
npm start
```


https://user-images.githubusercontent.com/25003283/216080514-9d40f912-7201-419e-80e3-11ad4fd52ac6.mov

15 changes: 15 additions & 0 deletions examples/simple-react-custom-middleware/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: '3.7'

services:
embedbase:
build: .
ports:
- "8000:8000"
environment:
- PYTHONUNBUFFERED=1
- PORT=8000
volumes:
- ./config.yaml:/app/config.yaml
- ./middlewares/processing_time/processing_time.py:/app/middlewares/processing_time.py
- ./middlewares/enrich/enrich.py:/app/middlewares/enrich.py

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from typing import Tuple
from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
import requests
class CustomHeaderMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next) -> Tuple[str, str]:
response = await call_next(request)
blood_types = requests.get("https://random-data-api.com/api/v2/blood_types").json()
response.headers["X-Enrich"] = str(blood_types)
print("my middleware is running")
print("enrich middleware did this:", blood_types)
print("enrich middleware ran after processing_time middleware, look what it did")
print("response.headers['X-Process-Time']", response.headers["X-Process-Time"])
return response
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import time
from typing import Tuple
from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
class CustomHeaderMiddleware(BaseHTTPMiddleware):
async def processing_time(request: Request, call_next) -> Tuple[str, str]:
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
print("my middleware is running")
print("processing_time middleware did this:", str(process_time))
return response
Loading

0 comments on commit 4d8daf9

Please sign in to comment.