-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from MLH-Fellowship/3-speech-to-test
#3 Use AWS Transcribe service in order to evaluate the speaking/pronunciation
- Loading branch information
Showing
20 changed files
with
211 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
AWS_ACCESS_KEY_ID= | ||
AWS_SECRET_ACCESS_KEY= | ||
AWS_DEFAULT_REGION= | ||
AWS_BUCKET_NAME= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.contrib import admin | ||
|
||
# Register your models here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class TranscribeConfig(AppConfig): | ||
default_auto_field = 'django.db.models.BigAutoField' | ||
name = 'backend.transcribe' |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.db import models | ||
|
||
# Create your models here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.test import TestCase | ||
|
||
# Create your tests here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from rest_framework import routers | ||
from django.urls import path, include | ||
from . import views | ||
|
||
router = routers.DefaultRouter() | ||
|
||
urlpatterns = [ | ||
path('', views.TranscribeViewSet.as_view(), name='transcribe'), | ||
path('/<int:id>', views.TranscribeViewSet.as_view(), name='transcribe'), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
from django.shortcuts import render | ||
from rest_framework.views import APIView | ||
from rest_framework.response import Response | ||
import environ | ||
import boto3 | ||
import urllib | ||
import json | ||
|
||
env = environ.Env() | ||
environ.Env.read_env() | ||
|
||
transcribe_client = boto3.client('transcribe', aws_access_key_id=env( | ||
'AWS_ACCESS_KEY_ID'), aws_secret_access_key=env('AWS_SECRET_ACCESS_KEY')) | ||
s3_client = boto3.client('s3', aws_access_key_id=env( | ||
'AWS_ACCESS_KEY_ID'), aws_secret_access_key=env('AWS_SECRET_ACCESS_KEY')) | ||
|
||
|
||
class TranscribeViewSet(APIView): | ||
|
||
""" | ||
The post method should receive the following JSON (example) | ||
{ | ||
"s3_url": "https://s3.amazonaws.com/bucket/file.mp3", | ||
"language_code": "en-US", | ||
} | ||
The API will respond with a JSON object with the following fields: | ||
{ | ||
"message": "Successfully started transcription job" || "Failed to start transcription job", | ||
"transcription_job_name": "transcription_job_name", | ||
"aws_response": "aws_response" | ||
} | ||
The transcription job name has to be stored to be used in the get method to get the results | ||
""" | ||
|
||
def post(self, request): | ||
s3_url = request.data.get('s3_url') | ||
language_code = request.data.get('language_code') | ||
|
||
s3_filename = s3_url.split('/')[-1] | ||
s3_uri = "s3://{}/{}".format(env('AWS_BUCKET_NAME'), s3_filename) | ||
|
||
if not s3_url or not language_code: | ||
return Response({"message": "Please provide all the required fields."}) | ||
|
||
response = transcribe_client.start_transcription_job( | ||
TranscriptionJobName=s3_filename+'_transcription', | ||
Media={'MediaFileUri': s3_uri}, | ||
MediaFormat=s3_url.split('.')[-1], | ||
LanguageCode=language_code, | ||
OutputBucketName=env('AWS_BUCKET_NAME'), | ||
OutputKey='transcriptions/', | ||
) | ||
|
||
if response: | ||
return Response({"message": "Successfully started transcription job", "transcription_job_name": response['TranscriptionJob']['TranscriptionJobName'], "aws_response": response}) | ||
else: | ||
return Response({"message": "Failed to start transcription job", "aws_response": response}) | ||
|
||
""" | ||
This get method should recive the following query parameters: | ||
Example: api.url/transcribe/?transcription-job-name=test_transcription | ||
The API will respond with a JSON object with the following fields: | ||
{ | ||
message: "Successfully fetched transcription" || "Failed to get transcription job" || "Transcription job not completed yet", | ||
transcription: [{words}], | ||
aws_response: "Response from AWS", | ||
status: "success" || "failed" || "pending" | ||
} | ||
""" | ||
|
||
def get(self, request): | ||
transcription_job_name = request.query_params.get( | ||
'transcription-job-name') | ||
|
||
if not transcription_job_name: | ||
return Response({"message": "Please provide the transcription job name."}) | ||
response = transcribe_client.get_transcription_job( | ||
TranscriptionJobName=transcription_job_name) | ||
|
||
if response: | ||
s3_url = response['TranscriptionJob']['Transcript']['TranscriptFileUri'] | ||
if response['TranscriptionJob']['TranscriptionJobStatus'] == 'COMPLETED': | ||
|
||
s3_client.put_object_acl( | ||
ACL='public-read', Bucket=env('AWS_BUCKET_NAME'), Key="transcriptions/"+transcription_job_name+'.json') | ||
json_data = urllib.request.urlopen(s3_url) | ||
data = json.loads(json_data.read()) | ||
words = [] | ||
|
||
for item in data['results']['items']: | ||
word = item['alternatives'][0]['content'] | ||
confidence = float(item['alternatives'][0]['confidence']) | ||
if confidence > 0.7 or confidence == 0: | ||
words.append( | ||
{'word': word, 'confidence': confidence, 'color': 'green'}) | ||
elif confidence <= 0.7 and confidence > 0.4: | ||
words.append( | ||
{'word': word, 'confidence': confidence, 'color': 'yellow'}) | ||
else: | ||
words.append( | ||
{'word': word, 'confidence': confidence, 'color': 'red'}) | ||
|
||
return Response({"message": "Successfully fetched transcription", "transcription": words, "aws_response": response, "status": "success"}) | ||
else: | ||
return Response({"message": "Transcription job not completed yet", "aws_response": response, "status": "pending"}) | ||
else: | ||
return Response({"message": "Failed to get transcription job", "aws_response": response, "status": "failed"}) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.contrib import admin | ||
|
||
# Register your models here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class UploadConfig(AppConfig): | ||
default_auto_field = 'django.db.models.BigAutoField' | ||
name = 'backend.upload' |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.db import models | ||
|
||
# Create your models here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.test import TestCase | ||
|
||
# Create your tests here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from rest_framework import routers | ||
from django.urls import path, include | ||
from . import views | ||
|
||
router = routers.DefaultRouter() | ||
|
||
urlpatterns = [ | ||
path('', views.UploadViewSet.as_view(), name='upload'), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from django.shortcuts import render | ||
from rest_framework.views import APIView | ||
from rest_framework.response import Response | ||
import environ | ||
import boto3 | ||
|
||
env = environ.Env() | ||
environ.Env.read_env() | ||
|
||
s3_client = boto3.client('s3', aws_access_key_id=env( | ||
'AWS_ACCESS_KEY_ID'), aws_secret_access_key=env('AWS_SECRET_ACCESS_KEY')) | ||
|
||
|
||
class UploadViewSet(APIView): | ||
""" | ||
This put method should receive a file in form-data with the name "audio_file". | ||
The API will put the file in the S3 bucket and return the URL of the file together with the response from AWS. | ||
""" | ||
|
||
def put(self, request): | ||
audio_file = request.FILES['audio_file'] | ||
if audio_file.content_type not in ['audio/mpeg', 'audio/mp3']: | ||
return Response({"message": "The file is not a valid audio file."}) | ||
response = s3_client.put_object( | ||
Body=audio_file, Bucket=env('AWS_BUCKET_NAME'), Key=audio_file.name, ACL='public-read') | ||
if response: | ||
URL = "https://{}.s3.amazonaws.com/{}".format( | ||
env('AWS_BUCKET_NAME'), audio_file.name) | ||
return Response({"message": "Successfully uploaded file", "s3_url": URL, "aws_response": response}) | ||
else: | ||
return Response({"message": "Failed to upload file", "aws_response": response}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters