Deploying with the HTTP Service

In this tutorial we will deploy a dataflow(ffmpeg dataflow) which converts a video to gif over an HTTP service. We’ll also see how to deploy the same in a docker container. Finally in Serving the DataFlow we’ll setup another HTTP service which waits on GitHub webhooks to rebuilt and deploy the ffmpeg dataflow.

Note

All the code for this example is located under the examples/ffmpeg directory of the DFFML source code.

We’ll be using additional plugins from dffml, dffml-config-yaml and dffml-http-service.

$ pip install dffml-config-yaml dffml-http-service

Writing the function

We’ll first write the function to convert videos files to gif by calling ffmpeg (Make sure you download and install it) in operation.py. The function accepts bytes (of the video), converts it to gif and outputs it as bytes.

operations.py

import asyncio
import tempfile


async def convert_to_gif(input_file: bytes, resolution: int) -> bytes:
    temp_input_file = tempfile.NamedTemporaryFile(prefix="ffmpeg-")
    temp_input_file.write(input_file)
    temp_input_file.seek(0)
    proc = await asyncio.create_subprocess_exec(
        "ffmpeg",
        "-ss",
        "0.3",
        "-t",
        "10",
        "-i",
        temp_input_file.name,
        "-y",
        "-vf",
        f"fps=10,scale={resolution}:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse",
        "-loop",
        "0",
        "-f",
        "gif",
        "pipe:1",
        stdout=asyncio.subprocess.PIPE,
    )
    out, error = await proc.communicate()
    temp_input_file.close()
    return {"output_file": out}

Dataflow and Config files

DFFML can create a dataflow out of our python function.

$ dffml dataflow create -config yaml operations:convert_to_gif get_single \
    -inputs 480=operations.convert_to_gif.inputs.resolution \
    "['operations.convert_to_gif.outputs.result']=get_single_spec" \
     > deploy/df/ffmpeg.yaml

Here through the inputs argument, we set the default resolution to 480 and output of the dataflow to result of convert_to_gif.

Create the config file for the HTTP service in deploy/mc/http/ffmpeg.yaml

$ cat > ./deploy/mc/http/ffmpeg.yaml <<EOF
path: /ffmpeg
input_mode: bytes:operations.convert_to_gif.inputs.input_file
output_mode: bytes:image/gif:post_input."operations.convert_to_gif.outputs.result".output_file
EOF
  • input_mode

    • bytes:operations.convert_to_gif.inputs.input_file

      • We want the input from the request to be treated as bytes with definition operations.convert_to_gif.inputs.input_file.

  • output_mode

    • bytes:image/gif:post_input."operations.convert_to_gif.outputs.result".output_file

      • We want the response (content_type = image/gif) to be bytes taken from results["post_input"]["operations.convert_to_gif.outputs.result"][output_file], where results is the output of the dataflow.

For more details see HttpChannelConfig .

Serving the DataFlow

Serving the dataflow on port 8080

$ dffml service http server -insecure -mc-config deploy -port 8080

Warning

The -insecure flag is only being used here to speed up this tutorial. See documentation on HTTP API Security for more information.

Now from another terminal, we can send post requests to the dataflow running at this port.

$ curl -v --request POST --data-binary @input.mp4 http://localhost:8080/ffmpeg -o output.gif

You should replace input.mp4 with path to your video file and output.gif to where you want the converted gif to be output to. An example video is available here .

Deploying via container

Dockerfile

# Usage
# docker build -t $USER/ffmpeg .
# docker run --rm -ti -p 8080:8080 $USER/ffmpeg -mc-config deploy -insecure -log debug
#
# curl -v --request POST --data-binary @input.mp4 http://localhost:8080/ffmpeg -o output.gif
FROM ubuntu:20.04

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
  apt-get install -y \
    gcc \
    python3-dev \
    python3-pip \
    python3 \
    ca-certificates \
    ffmpeg && \
  python3 -m pip install -U pip && \
  python3 -m pip install dffml-service-http && \
  python3 -m pip install dffml-config-yaml && \
  apt-get purge -y \
    gcc \
    python3-dev && \
  rm -rf /var/lib/apt/lists/*

WORKDIR /usr/src/app
COPY . /usr/src/app

ENTRYPOINT ["python3", "-m", "dffml", "service", "http", "server", "-addr", "0.0.0.0"]
CMD ["-mc-config", "deploy"]

Note

The run command in the comment section of the Dockerfile will be used to execute the container after receving webhooks, so make sure you change it to your usecase.

For this tutorial we will set it to

# docker run --rm -ti -p 8080:8080 $USER/ffmpeg -mc-config deploy -insecure -log debug

Note

The image built after pulling the contaier will be taged USERNAME/REPONAME, where USERNAME and REPONAME are gathered from the github html url, received in the webhook.

We can run the container and sent a post request to verify that the container is working.

$ docker build -t $USER/ffmpeg .
$ docker run --rm -ti -p 8080:8080 $USER/ffmpeg -mc-config deploy -insecure -log debug

Now in another terminal

$ curl -v --request POST --data-binary @input.mp4 http://localhost:8080/ffmpeg -o output.gif

Now in Redeploying on receiving GitHub webhook we’ll setup this container to be automatically redeployed whenever we push to the Git repo containing this code.