## Face classification server instructions for Development

The contents of this repo/docker depend on [oarriaga/face_classification](https://github.com/oarriaga/face_classification)
which is licensed under the MIT license. Our customisations to their code can be found as prepatched files under the contrib
directory. The Dockerfile copies the contrib directory on top of a clean checkout of their code. For more details see
"API endpoints" below

Depending on whether this is used long term we may want to make a proper fork and scrub their simple Docker support out
replacing it with this.

### Using docker to test changes locally

1. Install docker or docker toolbox (Windows 10 Home or "worse")
2. To test the server through docker locally use the following commands

```shell
# build and run the container, exposing port 80 at physical port 80
$ docker build -t smartbusstop-tensorflow:latest .
$ docker run -p 80:80 -it --name=smartbusstop-tensorflow smartbusstop-tensorflow:latest

# to see your running container instance use (in a different terminal)
$ docker ps

# to access a shell from your running container instance use
$ docker exec -it smartbusstop-tensorflow bash

# to remove a container (after it has been stoped, ie. Ctrl+C)
$ docker rm smartbusstop-tensorflow

# to (re)start or stop the container you created with run use
$ docker start smartbusstop-tensorflow
$ docker stop smartbusstop-tensorflow

# see any images you have currently built
$ docker images

# remove built images with
$ docker rmi <image_id_or_name>
```

The docker container is based on the `nginx:latest` docker that pulls in a slim
debian, it installs python 3.5 and [supervisor](http://supervisord.org/) to run
both nginx and the Flask application inside the same container. The configuration
files for Supervisor and Nginx can be found in the conf directory. Nginx acts as
a basic reverse proxy to let us reap the performance benefits from it for static
files.

While it is possible to get shell access to running container through `docker exec`
it is important to note that any actions taken through this kind of shell do not
persist across containers.

To access the python virtual environment for the face classification scripts use
the following command from shell or script

```shell
# if running locally, start with this as above
$ docker exec -it smartbusstop-tensorflow bash
$ source .venv/bin/activate
$ cd face_classification/src
```

If you want to use or train custom models I recommend running the script in a local
docker instance through this kind of shell then using the `docker cp` command to
pull the files from the container to your local machine. After put them online
somewhere as a tar.gz archive and reference that from Dockerfile as needed using
`ADD`, which can handle archives and urls as source for you, unlike `COPY`, placing
them under contrib/trained_models where `docker build` will find them. This will avoid
storing them in this git repository itself.

### Deploying changes

Changes must be deployed manually through the gitlab web UI, using the "Run pipeline"
button under CI / CD > [Pipelines](https://gitlab.utu.fi/Smart_Bus_Stop/tensorflow-server/pipelines).

### API endpoints (tentative)

**TODO**

The api endpoints are similar to what had been defined upstream, notably support
for GET requests and json results has been added. The ability to turn emotion
detection on or off was also added and the processor code refactored for  more
control and better memory management. 

There is no usage control or sanity checks which is a problem. *Logging requests is
largely absent when they succeed.* Version number added as part of the URI same as
frontend WIP endpoints. Stop code can optionally be passed as a query string argument
(stop_code), but it is only logged for processing errors.

```
URI: POST /api/v1/classifyImage[/<type>][?stop_code=<gtfs_stop_code>&detect_emotion=<1/0>]
```
**Notes:** accepts image uploads as [multipart/form-data](https://stackoverflow.com/questions/12385179/how-to-send-a-multipart-form-data-with-requests-in-python)
the name/key for the sent file should be "image". The type argument can be either `json` or `png`, it determines the response type. Emotion detection can be toggled
on with the `detect_emotion` integer key by setting its value to be non-zero. Without an explicit type the results are returned as encoded json from memory
if a type is provided however, the results are first always saved to the disk before being sent. 

```
URI: GET /api/v1/classifyImage[/<type>]?uri=<urlencoded_image_uri>[&stop_code=<gtfs_stop_code>&detect_emotion=<1/0>]
```
**Notes:** accepts an URI to image hosted online to use as the input image, otherwise indentical to above.
