""" ********************************************************************************************************************** * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * * documentation files (the "Software"), to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and * * to permit persons to whom the Software is furnished to do so. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO * * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * * IN THE SOFTWARE. * ********************************************************************************************************************** """ # Version: 2021.12.14 # Import the necessary modules for this flow to work import json import os import logging import boto3 from awsscv.sf import Salesforce import phonenumbers logger = logging.getLogger() logger.setLevel(logging.getLevelName(os.getenv('lambda_logging_level', 'DEBUG'))) def lambda_handler(event, context): logger.debug(event) connect_client = boto3.client('connect') loop_counter = 0 # Process the records in the event for record in event['Records']: # Increment loop counter loop_counter = loop_counter+1 # Establish data for transcript and recording try: transcript_key = record['s3']['object']['key'] contact_id = transcript_key.replace('.json','') recording_key = transcript_key.replace('.json','.wav') transcript_bucket = os.environ['s3_transcripts_bucket'] recording_bucket = os.environ['s3_recordings_bucket'] except Exception as e: logger.error(e) logger.error('Record {0} Result: Failed to extract keys'.format(loop_counter)) continue # Invoke presigner Lambda to generate presigned URL for recording and the formatted version for SCV try: client = boto3.client('lambda') input_params = { 'recording_bucket': recording_bucket, 'recording_key': recording_key } lambda_response = client.invoke( FunctionName = os.environ['presigner_function_arn'], InvocationType = 'RequestResponse', Payload = json.dumps(input_params) ) response_from_presigner = json.load(lambda_response['Payload']) raw_url = response_from_presigner['presigned_url'] sf_formatted_url = 'Play Voicemail'.format(response_from_presigner['presigned_url']) except Exception as e: logger.error(e) logger.error('Record {0} Result: Failed to generate presigned URL'.format(loop_counter)) continue # Extract the tags from the recording object try: s3_client = boto3.client('s3') object_data = s3_client.get_object_tagging( Bucket = recording_bucket, Key = recording_key ) object_tags = object_data['TagSet'] loaded_tags = {} for i in object_tags: loaded_tags.update({i['Key']:i['Value']}) except Exception as e: logger.error(e) logger.error('Record {0} Result: Failed to extract tags'.format(loop_counter)) continue # Grab the transcript from S3 try: s3_resource = boto3.resource('s3') transcript_object = s3_resource.Object(transcript_bucket, transcript_key) file_content = transcript_object.get()['Body'].read().decode('utf-8') json_content = json.loads(file_content) transcript_contents = json_content['results']['transcripts'][0]['transcript'] except Exception as e: logger.error(e) logger.error('Record 0 Result: Failed to retrieve transcript'.format(loop_counter)) continue # Determine if this was a queue or agent directed voicemail and grab the name for the entity. Set vars accordingly connect_client = boto3.client('connect') if loaded_tags['vm_queue_type'] == 'agent': vm_prefix = 'Direct' try: queue_arn = loaded_tags['vm_queue_arn'] split_1 = queue_arn.split('instance/')[1] instance_id = split_1.split('/queue')[0] agent_id = split_1.split('agent/')[1] get_agent = connect_client.describe_user( UserId = agent_id, InstanceId = instance_id ) logger.debug(get_agent['User']['IdentityInfo']) entity_name = get_agent['User']['IdentityInfo']['FirstName']+' '+get_agent['User']['IdentityInfo']['LastName'] full_agent_id = get_agent['User']['Username'] if full_agent_id.count('@') == 1: sf_agent_id = full_agent_id.split('@')[0] else: sf_agent_id = full_agent_id.split('@')[1] target_email = full_agent_id if '@' not in target_email: logger.error('Agent does not have an email associated') except Exception as e: logger.error(e) logger.error('Record {0} Result: Failed to find agent'.format(loop_counter)) entity_name = 'UNKNOWN' else: vm_prefix = 'Queue' queue_arn = loaded_tags['vm_queue_arn'] split_1 = queue_arn.split('instance/')[1] instance_id = split_1.split('/queue')[0] queue_id = split_1.split('queue/')[1] get_queue_details = connect_client.describe_queue( InstanceId=instance_id, QueueId=queue_id ) # Determine email address for queue if present, or set default. try: target_email = get_queue_details['Queue']['Description'].split('QVM::')[1] except: target_email = os.environ['default_email'] try: entity_name = loaded_tags['vm_queue_name'] except Exception as e: logger.error(e) logger.error('Record {0} Result: Failed to extract queue name'.format(loop_counter)) entity_name = 'UNKNOWN' # Build the human readable phone number for the subject try: incoming_phone = '+' + loaded_tags['vm_from'] parsed_phone = phonenumbers.parse(incoming_phone, None) international_phone = phonenumbers.format_number(parsed_phone, phonenumbers.PhoneNumberFormat.INTERNATIONAL) except Exception as e: logger.error(e) international_phone = '+' + loaded_tags['vm_from'] # Get the existing contact attributes from the call and append the standard vars for voicemail to the attributes try: queue_arn = loaded_tags['vm_queue_arn'] split_1 = queue_arn.split('instance/')[1] instance_id = split_1.split('/queue')[0] contact_attributes = connect_client.get_contact_attributes( InstanceId = instance_id, InitialContactId = contact_id ) json_attributes = contact_attributes['Attributes'] json_attributes.update({'entity_name':entity_name,'transcript_contents':transcript_contents,'customer_phone':international_phone,'presigned_url':raw_url}) contact_attributes = json.dumps(contact_attributes['Attributes']) except Exception as e: logger.error(e) logger.error('Record {0} Result: Failed to extract attributes'.format(loop_counter)) contact_attributes = 'UNKNOWN' ##### BEGIN MOD FOR UNIVERSAL USE ##### # set the mode vmx_mode = json_attributes['vmx_mode'] ## SCV Mode if vmx_mode == 'SCV': logger.info('Beginning Voicemail to Salesforce Case') # Perform the salesforce login try: sf = Salesforce() except Exception as e: logger.error(e) logger.error('Record {0} Result: Failed to authenticate with Salesforce'.format(loop_counter)) continue # Create a case in Salesforce try: if loaded_tags['vm_queue_type'] == 'agent': data = { 'Subject': vm_prefix + ' voicemail for: ' + entity_name + ', from : ' + international_phone, 'Description': 'Voicemail transcript: ' + transcript_contents, 'Status': 'New', 'Priority': loaded_tags['vm_priority'], 'Origin': 'Phone', 'OwnerId': sf_agent_id, os.environ['sf_case_vm_attributes']: contact_attributes, os.environ['sf_case_vm_phone_field']: international_phone, os.environ['sf_case_vm_field']: sf_formatted_url } else: data = { 'Subject': vm_prefix + ' voicemail for: ' + entity_name + ', from : ' + international_phone, 'Description': 'Voicemail transcript: ' + transcript_contents, 'Status': 'New', 'Priority': loaded_tags['vm_priority'], 'Origin': 'Phone', os.environ['sf_case_vm_attributes']: contact_attributes, os.environ['sf_case_vm_phone_field']: international_phone, os.environ['sf_case_vm_field']: sf_formatted_url } logger.debug(data) response = sf.create(sobject='Case', data=data) logger.info('Record {0} Result: Case created [{1}]'.format(loop_counter, response)) sf_case = response except Exception as e: logger.error(e) logger.error('Record {0} Result: Failed to create case'.format(loop_counter)) continue # EMAIL Mode elif vmx_mode == 'EMAIL': logger.info('Beginning Voicemail to Email') ses_client = boto3.client('sesv2') # Extract the data to pass and the email attributes to use from the contact data template_data = json.dumps(json_attributes) email_template = json_attributes['email_template'] email_from = json_attributes['email_from'] try: send_email = ses_client.send_email( FromEmailAddress=email_from, Destination={ 'ToAddresses': [ target_email, ], }, Content={ 'Template': { 'TemplateName': email_template, 'TemplateData': template_data } } ) continue except Exception as e: logger.error(e) logger.error('Record {0} Failed to send email.'.format(loop_counter)) continue elif 'vmx_mode == 'TASK': logger.info('Beginning Voicemail to Task') try: create_task = connect_client.start_task_contact( InstanceId=instance_id, PreviousContactId=contact_id, ContactFlowId=json_attributes['task_flow'], Attributes=json_attributes, Name='Voicemail', References={ 'Click link below to play voicemail': { 'Value': raw_url, 'Type': 'URL' } }, Description=transcript_contents ) continue except Exception as e: logger.error(e) logger.error('Record {0} Failed to create task.'.format(loop_counter)) continue else: logger.error('INVALID CONFIGURATION') continue # Delete the transcription try: transcript_delete = transcript_object.delete() except Exception as e: logger.error(e) logger.error('Record {0} Failed to delete transcript'.format(loop_counter)) logger.debug('Record {0} Result: Success!'.format(loop_counter)) # Clear the vm_flag for this contact try: # Grab instance ID queue_arn = loaded_tags['vm_queue_arn'] split_1 = queue_arn.split('instance/')[1] instance_id = split_1.split('/queue')[0] # Do the update update_flag = connect_client.update_contact_attributes( InitialContactId=contact_id, InstanceId=instance_id, Attributes={ 'vm_flag': '0' } ) except Exception as e: logger.error(e) logger.error('Record {0} Failed to change vm_flag'.format(loop_counter)) return { 'status': 'complete', 'result': '{0} records processed'.format(loop_counter) }