Skip to content
This repository has been archived by the owner on Jun 13, 2024. It is now read-only.

Commit

Permalink
Merge pull request #17 from khyew/voice-verification-api
Browse files Browse the repository at this point in the history
Added Python libs for majority of voice Verification API calls
  • Loading branch information
Mohamed Mohsen committed Feb 23, 2016
2 parents d8613e3 + c5c8840 commit ef44a42
Show file tree
Hide file tree
Showing 9 changed files with 411 additions and 0 deletions.
24 changes: 24 additions & 0 deletions SpeakerRecognition/Python/Verification/CreateProfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import VerificationServiceHttpClientHelper
import sys

def create_profile(subscription_key, locale):
"""Creates a profile on the server.
Arguments:
subscription_key -- the subscription key string
locale -- the locale string
"""
helper = VerificationServiceHttpClientHelper.VerificationServiceHttpClientHelper(
subscription_key)

creation_response = helper.create_profile(locale)

print('Profile ID = {0}'.format(creation_response.get_profile_id()))

if __name__ == "__main__":
if len(sys.argv) < 2:
print('Usage: python CreateProfile.py <subscription_key>')
print('\t<subscription_key> is the subscription key for the service')
sys.exit('Error: Incorrect Usage.')

create_profile(sys.argv[1], 'en-us')
32 changes: 32 additions & 0 deletions SpeakerRecognition/Python/Verification/EnrollProfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import VerificationServiceHttpClientHelper
import sys

def enroll_profile(subscription_key, profile_id, file_path):
"""Enrolls a profile on the server.
Arguments:
subscription_key -- the subscription key string
profile_id -- the profile ID of the profile to enroll
file_path -- the path of the file to use for enrollment
"""
helper = VerificationServiceHttpClientHelper.VerificationServiceHttpClientHelper(
subscription_key)

enrollment_response = helper.enroll_profile(profile_id, file_path)

print('Enrollments Completed = {0}'.format(enrollment_response.get_enrollments_count()))
print('Remaining Enrollments = {0}'.format(enrollment_response.get_remaining_enrollments()))
print('Enrollment Status = {0}'.format(enrollment_response.get_enrollment_status()))
print('Enrollment Phrase = {0}'.format(enrollment_response.get_enrollment_phrase()))

if __name__ == "__main__":
if len(sys.argv) < 4:
print('Usage: python EnrollProfile.py <subscription_key> <profile_id> '
'<enrollment_file_path>')
print('\t<subscription_key> is the subscription key for the service')
print('\t<profile_id> is the profile ID of the profile to enroll')
print('\t<enrollment_file_path> is the enrollment audio file path')

sys.exit('Error: Incorrect Usage.')

enroll_profile(sys.argv[1], sys.argv[2], sys.argv[3])
34 changes: 34 additions & 0 deletions SpeakerRecognition/Python/Verification/EnrollmentResponse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
class EnrollmentResponse:
"""This class encapsulates the enrollment response."""

_ENROLLMENT_STATUS = 'enrollmentStatus'
_ENROLLMENTS_COUNT = 'enrollmentsCount'
_REMAINING_ENROLLMENTS = 'remainingEnrollments'
_ENROLLMENT_PHRASE = 'phrase'

def __init__(self, response):
"""Constructor of the EnrollmentResponse class.
Arguments:
response -- the dictionary of the deserialized python response
"""
self._enrollment_status = response.get(self._ENROLLMENT_STATUS, None)
self._enrollments_count = response.get(self._ENROLLMENTS_COUNT, None)
self._remaining_enrollments = response.get(self._REMAINING_ENROLLMENTS, None)
self._enrollment_phrase = response.get(self._ENROLLMENT_PHRASE, None)

def get_enrollment_status(self):
"""Returns the enrollment status"""
return self._enrollment_status

def get_enrollments_count(self):
"""Returns the number of enrollments already performed"""
return self._enrollments_count

def get_enrollment_phrase(self):
"""Returns the enrollment phrase extracted from this request"""
return self._enrollment_phrase

def get_remaining_enrollments(self):
"""Returns the number of remaining enrollments before the profile is ready for verification"""
return self._remaining_enrollments
33 changes: 33 additions & 0 deletions SpeakerRecognition/Python/Verification/PrintAllProfiles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import VerificationServiceHttpClientHelper
import sys

def print_all_profiles(subscription_key):
"""Print all the profiles for the given subscription key.
Arguments:
subscription_key -- the subscription key string
"""
helper = VerificationServiceHttpClientHelper.VerificationServiceHttpClientHelper(
subscription_key)

profiles = helper.get_all_profiles()

print('Profile ID, Locale, Enrollments Count, Remaining Enrollments Count,'
' Created Date Time, Last Action Date Time, Enrollment Status')
for profile in profiles:
print('{0}, {1}, {2}, {3}, {4}, {5}, {6}'.format(
profile.get_profile_id(),
profile.get_locale(),
profile.get_enrollments_count(),
profile.get_remaining_enrollments_count(),
profile.get_created_date_time(),
profile.get_last_action_date_time(),
profile.get_enrollment_status()))

if __name__ == "__main__":
if len(sys.argv) < 2:
print('Usage: python PrintAllProfiles.py <subscription_key>')
print('\t<subscription_key> is the subscription key for the service')
sys.exit('Error: Incorrect Usage.')

print_all_profiles(sys.argv[1])
16 changes: 16 additions & 0 deletions SpeakerRecognition/Python/Verification/ProfileCreationResponse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class ProfileCreationResponse:
"""This class encapsulates the response of the creation of a user profile."""

_PROFILE_ID = 'verificationProfileId'

def __init__(self, response):
"""Constructor of the ProfileCreationResponse class.
Arguments:
response -- the dictionary of the deserialized python response
"""
self._profile_id = response.get(self._PROFILE_ID, None)

def get_profile_id(self):
"""Returns the profile ID of the user"""
return self._profile_id
52 changes: 52 additions & 0 deletions SpeakerRecognition/Python/Verification/VerificationProfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
class VerificationProfile:
"""This class encapsulates a user profile."""

_PROFILE_ID = 'verificationProfileId'
_LOCALE = 'locale'
_ENROLLMENTS_COUNT = 'enrollmentsCount'
_REMAINING_ENROLLMENTS_COUNT = 'remainingEnrollmentsCount'
_CREATED_DATE_TIME = 'createdDateTime'
_LAST_ACTION_DATE_TIME = 'lastActionDateTime'
_ENROLLMENT_STATUS = 'enrollmentStatus'

def __init__(self, response):
"""Constructor of the VerificationProfile class.
Arguments:
response -- the dictionary of the deserialized python response
"""
self._profile_id = response.get(self._PROFILE_ID, None)
self._locale = response.get(self._LOCALE, None)
self._enrollments_count = response.get(self._ENROLLMENTS_COUNT, None)
self._remaining_enrollments_count = response.get(self._REMAINING_ENROLLMENTS_COUNT, None)
self._created_date_time = response.get(self._CREATED_DATE_TIME, None)
self._last_action_date_time = response.get(self._LAST_ACTION_DATE_TIME, None)
self._enrollment_status = response.get(self._ENROLLMENT_STATUS, None)

def get_profile_id(self):
"""Returns the profile ID of the user"""
return self._profile_id

def get_locale(self):
"""Returns the locale of the user"""
return self._locale

def get_enrollments_count(self):
"""Returns the total number of speech samples submitted for enrollment for this user"""
return self._enrollments_count

def get_remaining_enrollments_count(self):
"""Returns the number of speech samples required remaining to complete enrollment"""
return self._remaining_enrollments_count

def get_created_date_time(self):
"""Returns the creation date time of the user"""
return self._created_date_time

def get_last_action_date_time(self):
"""Returns the last action date time of the user"""
return self._last_action_date_time

def get_enrollment_status(self):
"""Returns the enrollment status of the user"""
return self._enrollment_status
22 changes: 22 additions & 0 deletions SpeakerRecognition/Python/Verification/VerificationResponse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class VerificationResponse:
"""This class encapsulates the verification response."""

_RESULT = 'result'
_CONFIDENCE = 'confidence'

def __init__(self, response):
"""Constructor of the VerificationResponse class.
Arguments:
response -- the dictionary of the deserialized python response
"""
self._result = response.get(self._RESULT, None)
self._confidence = response.get(self._CONFIDENCE, None)

def get_result(self):
"""Returns whether the voice clip belongs to the profile (Accept / Reject)"""
return self._result

def get_confidence(self):
"""Returns the verification confidence"""
return self._confidence
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import http.client
import urllib.parse
import json
import time
from contextlib import closing
import ProfileCreationResponse
import EnrollmentResponse
import VerificationResponse
import VerificationProfile
import logging

class VerificationServiceHttpClientHelper:
"""Abstracts the interaction with the Verification service."""

_STATUS_OK = 200
_BASE_URI = 'api.projectoxford.ai'
_VERIFICATION_PROFILES_URI = '/spid/v1.0/verificationProfiles'
_VERIFICATION_URI = '/spid/v1.0/verify'
_SUBSCRIPTION_KEY_HEADER = 'Ocp-Apim-Subscription-Key'
_CONTENT_TYPE_HEADER = 'Content-Type'
_JSON_CONTENT_HEADER_VALUE = 'application/json'
_STREAM_CONTENT_HEADER_VALUE = 'application/octet-stream'

def __init__(self, subscription_key):
"""Constructor of the VerificationServiceHttpClientHelper class.
Arguments:
subscription_key -- the subscription key string
"""
self._subscription_key = subscription_key

def get_all_profiles(self):
"""Return a list of all profiles on the server."""
try:
# Send the request
res, message = self._send_request(
'GET',
self._BASE_URI,
self._VERIFICATION_PROFILES_URI,
self._JSON_CONTENT_HEADER_VALUE)

if res.status == self._STATUS_OK:
# Parse the response body
profiles_raw = json.loads(message)
return [VerificationProfile.VerificationProfile(profiles_raw[i])
for i in range(0, len(profiles_raw))]
else:
raise Exception('Error getting all profiles: ' + res.reason)
except:
logging.error('Error getting all profiles.')
raise

def create_profile(self, locale):
"""Creates a profile on the server and returns a dictionary of the creation response.
Arguments:
locale -- the locale string for the profile
"""
try:
# Prepare the body of the message
body = json.dumps({'locale': '{0}'.format(locale)})

# Send the request
res, message = self._send_request(
'POST',
self._BASE_URI,
self._VERIFICATION_PROFILES_URI,
self._JSON_CONTENT_HEADER_VALUE,
body)

if res.status == self._STATUS_OK:
# Parse the response body
return ProfileCreationResponse.ProfileCreationResponse(json.loads(message))
else:
message = res.read().decode('utf-8')
raise Exception('Error creating profile: ' + res.reason)
except:
logging.error('Error creating profile.')
raise

def enroll_profile(self, profile_id, file_path):
"""Enrolls a profile using an audio file and returns a
dictionary of the enrollment response.
Arguments:
profile_id -- the profile ID string of the user to enroll
file_path -- the file path string of the audio file to use
"""
try:
# Prepare the request
request_url = '{0}/{1}/enroll'.format(
self._VERIFICATION_PROFILES_URI,
urllib.parse.quote(profile_id))


# Prepare the body of the message
with open(file_path, 'rb') as body:
# Send the request
res, message = self._send_request(
'POST',
self._BASE_URI,
request_url,
self._STREAM_CONTENT_HEADER_VALUE,
body)
if res.status == self._STATUS_OK:
# Parse the response body
return EnrollmentResponse.EnrollmentResponse(json.loads(message))
else:
raise Exception('Error enrolling profile: ' + res.reason)
except:
logging.error('Error enrolling profile.')
raise

def verify_file(self, file_path, profile_id):
"""Verifies a profile using an audio file and returns a
Arguments:
file_path -- the file path of the audio file to test
profile_id -- a profile to test against
"""
try:
# Prepare the request
request_url = '{0}?verificationProfileId={1}'.format(
self._VERIFICATION_URI,
urllib.parse.quote(profile_id))

# Prepare the body of the message
with open(file_path, 'rb') as body:
# Send the request
res, message = self._send_request(
'POST',
self._BASE_URI,
request_url,
self._STREAM_CONTENT_HEADER_VALUE,
body)

if res.status == self._STATUS_OK:
# Parse the response body
return VerificationResponse.VerificationResponse(json.loads(message))
else:
raise Exception('Error verifying audio from file: ' + res.reason)
except:
logging.error('Error performing verification.')
raise

def _send_request(self, method, base_url, request_url, content_type_value, body=None):
"""Sends the request to the server then returns the response and the response body string.
Arguments:
method -- specifies whether the request is a GET or POST request
base_url -- the base url for the connection
request_url -- the request url for the connection
content_type_value -- the value of the content type field in the headers
body -- the body of the request (needed only in POST methods)
"""
try:
# Set the headers
headers = {self._CONTENT_TYPE_HEADER: content_type_value,
self._SUBSCRIPTION_KEY_HEADER: self._subscription_key}

# Start the connection
with closing(http.client.HTTPSConnection(base_url)) as conn:
# Send the request
conn.request(method, request_url, body, headers)
res = conn.getresponse()
message = res.read().decode('utf-8')

return res, message
except:
logging.error('Error sending the request.')
raise
Loading

0 comments on commit ef44a42

Please sign in to comment.