Skip to content
This repository was archived by the owner on Dec 29, 2021. It is now read-only.

Commit a69358b

Browse files
author
Neel Kamath
authored
Fix #12 (#13)
* Migrate to FastAPI and friends * Fix Docker daemon connection
1 parent 9e72049 commit a69358b

File tree

12 files changed

+116
-99
lines changed

12 files changed

+116
-99
lines changed

.dockerignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
*
22
!requirements.txt
3-
!app.py
3+
!main.py
44
!s2v_old/

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
s2v_old/
22
.idea/
3-
redoc-static.html
3+
redoc-static.html
4+
.pytest_cache/
5+
venv/

Dockerfile

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
FROM python:3.7
22
WORKDIR /app
3-
COPY . .
3+
ENV PYTHONUNBUFFERED 1
4+
COPY requirements.txt .
45
RUN pip install --no-cache-dir -r requirements.txt
5-
EXPOSE 8080
6+
COPY main.py .
7+
COPY s2v_old/ s2v_old/
8+
EXPOSE 8000
69
HEALTHCHECK --timeout=2s --start-period=2s --retries=1 \
7-
CMD curl -f http://localhost:8080/health_check
8-
CMD ["sh", "-c", "waitress-serve --port 8080 app:app"]
10+
CMD curl -f http://localhost:8000/health_check
11+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0"]

docker-compose.override.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
version: '3.7'
22
services:
33
app:
4-
command: sh -c 'pip install -r requirements.txt && flask run --host=0.0.0.0'
5-
ports: ['5000:5000']
6-
environment:
7-
FLASK_ENV: development
4+
command: sh setup.sh 'uvicorn main:app --host 0.0.0.0 --reload'
5+
ports: ['8000:8000']

docker-compose.test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
version: '3.7'
22
services:
33
app:
4-
command: sh -c 'pip install -r requirements.txt && python test.py'
4+
command: sh setup.sh 'pytest'

docker-compose.yml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# It is not possible to use a Docker volume to cache the dependencies because subsequent usage of the volume
2+
# occasionally gets corrupted for an unknown reason. Hence, a virtual environment is to be used instead. It is known
3+
# that virtual environments aren't needed in Docker because isolation is already provided; we use it as a cache instead.
14
version: '3.7'
25
services:
36
app:
@@ -6,9 +9,4 @@ services:
69
volumes:
710
- type: bind
811
source: .
9-
target: /app
10-
- type: volume
11-
source: cache
12-
target: /usr/local/lib/python3.7/site-packages
13-
volumes:
14-
cache:
12+
target: /app

docs/developing.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
docker-compose up --build
99
```
1010

11-
The server will be running on `http://localhost:5000`, and has automatic reload enabled.
11+
The server will be running on `http://localhost:8000`, and has automatic reload enabled.
1212

1313
### Testing
1414

@@ -22,7 +22,7 @@ docker-compose -f docker-compose.yml -f docker-compose.test.yml up --build --abo
2222
docker build -t spacy-server .
2323
```
2424

25-
The container `EXPOSE`s port `8080`. To serve at `http://localhost:8080`, run `docker run --rm -p 8080:8080 spacy-server`.
25+
The container `EXPOSE`s port `8000`. To serve at `http://localhost:8080`, run `docker run --rm -p 8000:8000 spacy-server`.
2626

2727
## Specification
2828

@@ -56,7 +56,7 @@ Open `redoc-static.html` in your browser.
5656

5757
## Releases
5858

59-
- Create a GitHub release (this will automatically create the git tag). If you bumped the version in `docs/openapi.yaml`, then create a new release. If you haven't bumped the version but have updated the HTTP API's functionality, delete the existing GitHub release and git tag, and create a new one. Otherwise, skip this step. The GitHub release's body should be ```Download and open the release asset, `redoc-static.html`, in your browser to view the HTTP API documentation.```. Upload/update the asset named `redoc-static.html` which contains the HTTP API's documentation (generated using `redoc-cli bundle docs/openapi.yaml --title 'spaCy Server' -o redoc-static.html`).
59+
- Create a GitHub release (this will automatically create the git tag). If you bumped the version in `docs/openapi.yaml`, then create a new release. If you haven't bumped the version but have updated the HTTP API's functionality, delete the existing GitHub release and git tag, and create a new one. Otherwise, skip this step. The release's title should be the features included (e.g., `NER, POS tagging, sentencizer, tokenizer, and sense2vec`). The tag should be the HTTP API's version (e.g., `v1`). The release's body should be ```Download and open the release asset, `redoc-static.html`, in your browser to view the HTTP API documentation.```. Upload the asset named `redoc-static.html` which contains the HTTP API docs.
6060
- If required, update the [Docker Hub repository](https://hub.docker.com/r/neelkamath/spacy-server)'s **Overview**.
6161
- For every commit to the `master` branch in which the tests have passed, the following will automatically be done.
6262
- The new images will be uploaded to Docker Hub.

app.py renamed to main.py

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
"""Provides spaCy NLP over an HTTP API."""
22

3+
import typing
4+
35
import en_core_web_sm
4-
import flask
5-
from sense2vec import Sense2VecComponent
6+
import fastapi
7+
import pydantic
8+
import sense2vec
9+
import starlette.status
610

7-
app = flask.Flask(__name__)
11+
app = fastapi.FastAPI()
812
nlp = en_core_web_sm.load()
9-
nlp.add_pipe(Sense2VecComponent(nlp.vocab).from_disk("s2v_old"))
13+
nlp.add_pipe(sense2vec.Sense2VecComponent(nlp.vocab).from_disk("s2v_old"))
14+
15+
16+
class SectionsModel(pydantic.BaseModel):
17+
sections: typing.List[str]
1018

1119

12-
@app.route('/ner', methods=['POST'])
13-
def recognize_named_entities():
20+
@app.post('/ner')
21+
async def recognize_named_entities(request: SectionsModel):
1422
response = {'data': []}
15-
sections = flask.request.get_json()['sections']
16-
for doc in nlp.pipe(sections, disable=['tagger']):
23+
for doc in nlp.pipe(request.sections, disable=['tagger']):
1724
for sent in doc.sents:
1825
entities = [build_entity(ent) for ent in sent.ents]
1926
data = {'text': sent.text, 'entities': entities}
@@ -41,11 +48,14 @@ def build_entity(ent):
4148
}
4249

4350

44-
@app.route('/pos', methods=['POST'])
45-
def tag_parts_of_speech():
51+
class TextModel(pydantic.BaseModel):
52+
text: str
53+
54+
55+
@app.post('/pos')
56+
async def tag_parts_of_speech(request: TextModel):
4657
data = []
47-
doc = nlp(flask.request.get_json()['text'])
48-
for token in [build_token(token) for token in doc]:
58+
for token in [build_token(token) for token in nlp(request.text)]:
4959
text = token['sent']
5060
del token['sent']
5161
if text in [obj['text'] for obj in data]:
@@ -100,20 +110,18 @@ def build_token(token):
100110
}
101111

102112

103-
@app.route('/tokenizer', methods=['POST'])
104-
def tokenize():
105-
text = flask.request.get_json()['text']
106-
doc = nlp(text, disable=['tagger', 'parser', 'ner'])
113+
@app.post('/tokenizer')
114+
async def tokenize(request: TextModel):
115+
doc = nlp(request.text, disable=['tagger', 'parser', 'ner'])
107116
return {'tokens': [token.text for token in doc]}
108117

109118

110-
@app.route('/sentencizer', methods=['POST'])
111-
def sentencize():
112-
text = flask.request.get_json()['text']
113-
doc = nlp(text, disable=['tagger', 'ner'])
119+
@app.post('/sentencizer')
120+
async def sentencize(request: TextModel):
121+
doc = nlp(request.text, disable=['tagger', 'ner'])
114122
return {'sentences': [sent.text for sent in doc.sents]}
115123

116124

117-
@app.route('/health_check')
118-
def check_health():
119-
return flask.Response(status=204)
125+
@app.get('/health_check', status_code=starlette.status.HTTP_204_NO_CONTENT)
126+
async def check_health():
127+
pass

requirements.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
spacy>=2.2.3,<3
22
https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-2.2.5/en_core_web_sm-2.2.5.tar.gz#egg=en_core_web_sm
3-
flask>=1.1.1,<2
4-
waitress>=1.3.1,<2
5-
sense2vec>=1.0.2,<2
3+
sense2vec>=1.0.2,<2
4+
fastapi==0.45.0
5+
uvicorn==0.10.8
6+
pytest>=4.6.7,<5

setup.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env bash
2+
3+
# Executes a command in a virtual environment (e.g., <sh setup.sh 'uvicorn main:app --reload'>).
4+
5+
python -m venv venv
6+
. venv/bin/activate
7+
pip install -r requirements.txt
8+
$1

0 commit comments

Comments
 (0)