Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/google api #10

Merged
merged 11 commits into from
Sep 18, 2020
212 changes: 212 additions & 0 deletions notebooks/submission_endpoint_interations.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
{
lorischl-otter marked this conversation as resolved.
Show resolved Hide resolved
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6-final"
},
"orig_nbformat": 2,
"kernelspec": {
"name": "python_defaultSpec_1600367979214",
"display_name": "Python 3.7.6 64-bit ('ds-base': conda)"
}
},
"nbformat": 4,
"nbformat_minor": 2,
"cells": [
{
"source": [
"# outlining the submission endpoints interactions\n",
"\n"
],
"cell_type": "markdown",
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"from requests import get, post"
]
},
{
"source": [
"## Launch the API via uvicorn using the following command:\n",
"```\n",
"export GOOGLE_CREDS=[content of service account key file]\n",
"uvicorn app.main:app --reload --workers 1 --host 0.0.0.0 --port 8000\n",
"```"
],
"cell_type": "markdown",
"metadata": {}
},
{
"source": [
"## the following cell will check if the api is runnning and accepting requests"
],
"cell_type": "markdown",
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": "200"
},
"metadata": {},
"execution_count": 3
}
],
"source": [
"server_check = get(\"http://0.0.0.0:8000\")\n",
"server_check.status_code"
]
},
{
"source": [
"## Open a local file and nest it in a files dictonary"
],
"cell_type": "markdown",
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"tags": []
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": "{'files': ('3101.jpg', <_io.BufferedReader name='3101.jpg'>)}"
},
"metadata": {},
"execution_count": 3
}
],
"source": [
"image = open('3101.jpg', 'rb')\n",
"files = {\"files\":(image.name, image)}\n",
"files"
]
},
{
"source": [
"## Make a post request to the `/submission/text` enpoint using the keyword `files` and the url argument `story_id`"
],
"cell_type": "markdown",
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"tags": []
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": "200\n"
}
],
"source": [
"story_id = \"3101\"\n",
"args = f\"?story_id={story_id}\"\n",
"response = post(f\"http://0.0.0.0:8000/submission/text\" + args, files=files)\n",
"print(response.status_code)\n"
]
},
{
"source": [
"## Open an illustraion file"
],
"cell_type": "markdown",
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": "{'files': ('questionable.png', <_io.BufferedReader name='questionable.png'>)}"
},
"metadata": {},
"execution_count": 4
}
],
"source": [
"image = open('questionable.png', 'rb')\n",
"files = {\"files\":(image.name, image)}\n",
"files"
]
},
{
"source": [
"## post to the `/submission/illustration` enpoint and print the results"
],
"cell_type": "markdown",
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"tags": []
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": "200\n"
}
],
"source": [
"response = post(\"http://0.0.0.0:8000/submission/illustration\", files=files)\n",
"print(response.status_code)\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": "b'{\"is_flagged\":true,\"reason\":[\"adult: VERY_UNLIKELY\",\"violence: VERY_UNLIKELY\",\"racy: POSSIBLE\"]}'"
},
"metadata": {},
"execution_count": 8
}
],
"source": [
"response.content"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
]
}
48 changes: 35 additions & 13 deletions project/app/api/submission.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import logging
from fastapi import APIRouter, File, UploadFile
from pydantic import BaseModel, Field, validator
from app.utils.google_api import GoogleAPI, NoTextFoundException
import json

router = APIRouter()
log = logging.getLogger(__name__)
# init the GoogleAPI service to fetch responses from the google vision api
vision = GoogleAPI()


class Submission(BaseModel):
"""Data Model to parse Request body JSON, using the Default values
will check if the s3 API server is currently accepting requests"""

story_id: str = Field(..., example="12345")
story_file: bytes = Field(..., example=b"10gh1r447/s4413.")
story_file: str = Field(..., example=b"10gh1r447/s4413.")

@validator("story_id")
def no_none_ids(cls, value):
Expand All @@ -28,7 +32,7 @@ def check_file(cls, value):


@router.post("/submission/text")
async def submission_text(sub: Submission):
async def submission_text(story_id: str, files: UploadFile = File(...)):
"""This function takes the passed file in Submission and calls two services,
one that uses the Google Vision API and transcribes the text from the file
and looks for moderation markers. the other service will take the binary
Expand All @@ -39,30 +43,48 @@ async def submission_text(sub: Submission):

## Arguments:
-----------

sub {Submission} - submission model that is created on post
story_id `str` - story_id
story_file `UploadFile` - UGC passed with enctype=multipart/form-data

## Returns:
-----------

json - {"is_flagged": bool, "s3_link": type(url)}
response `json` - {"is_flagged": bool, "s3_link": type(url)}
"""
return {sub}
# catch custom exception for no text
try:
# await for the vision API to process the image
transcript = await vision.transcribe(files)
story_id = story_id
Jwilson1172 marked this conversation as resolved.
Show resolved Hide resolved

# log the error then return what the error is
except NoTextFoundException as e:
log.error(e, stack_info=True)
return {"error": e}
print((story_id, transcript))

# return moderation flag and s3_link for that file (not yet implemented)
return {"is_flagged": None, "s3_path": None}


@router.post("/submission/illustration")
async def submission_illustration(sub: Submission):
"""Function that takes an illustration from form data and checks the
illustration against the google.cloud.vision api and see's if the content
is NSFW
async def submission_illustration(files: UploadFile = File(...)):
"""Function that checks the illustration against the google.cloud.vision
api and see's if the content is NSFW.
Jwilson1172 marked this conversation as resolved.
Show resolved Hide resolved

## Arguments:
-----------
files `UploadFile` - UGC to be uploaded, transcribed, and stored

sub {Submission} - submission model that is created on post
eg.
```python3
files = {"files": (file.name, file)}
```

## Returns:
-----------

json - {"is_flagged": bool, "s3_link": type(url)}"""
return {sub}
response `json` - {"is_flagged": bool, "reason":`reason`}"""
response = await vision.detect_safe_search(files)
return response

Loading