EVG Connector

The eva Voice Gateway

The eva-evg-connector is an IVR integration channel with eva.

In this guide we will see how to set up a project using the eva-evg-connector.

For more information on how to create flows in eva and what each of the IVR commands is that we will see below, please refer to the following eva documentation.

Versions

Note that eva-evg-connector is a peer dependency of eva. This change allows greater flexibility of choosing the right version of the eva-evg-connector client version for eva version.

eva-evg-connectoreva

1.x.x

4.3.x - current

Requirements

For building and running the application you need:

Dependencies

The external dependencies of this project are:

Environment Variables

To change the default value of some project settings just set the following environment variables:

Redis

spring.cache.redis.time-to-live=1800000
spring.cache.type=${CACHETYPE}
spring.redis.host=${REDIS_HOST}
spring.redis.port=${REDIS_PORT}
spring.redis.password=${REDIS_PWD}
spring.redis.ssl=${REDIS_SSL}

The default value of the spring.cache.redis.time-to-live property is 1800000, if you don't want to change the value, this property is not required.

Getting Started

First, we’ll start by creating a Spring Boot web project and adding the eva-evg-connector dependency to our pom.xml file:

<dependency>
    <groupId>com.everis.eva</groupId>
    <artifactId>eva-evg-connector</artifactId>
    <version>1.0.0</version>
</dependency>

It is a maven project with Spring Boot Web, to create a project using Spring see the website: https://start.spring.io/

To download the dependency, configure your settings.xml as follows:

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <servers>
        <server>
            <id>artifact-registry-evg</id>
            <configuration>
                <httpConfiguration>
                    <get>
                        <usePreemptive>true</usePreemptive>
                    </get>
                    <head>
                        <usePreemptive>true</usePreemptive>
                    </head>
                    <put>
                        <params>
                            <property>
                                <name>http.protocol.expect-continue</name>
                                <value>false</value>
                            </property>
                        </params>
                    </put>
                </httpConfiguration>
            </configuration>
            <username>_json_key_base64</username>
            <password>ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIsCiAgInByb2plY3RfaWQiOiAiY2FsbS1wcmVtaXNlLTE2ODQyMCIsCiAgInByaXZhdGVfa2V5X2lkIjogIjQ4NTYxY2MxYzViODdhMDgwZmYwODgwOTQ0ZDcwMTEzNmZmMDY1MTIiLAogICJwcml2YXRlX2tleSI6ICItLS0tLUJFR0lOIFBSSVZBVEUgS0VZLS0tLS1cbk1JSUV2QUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktZd2dnU2lBZ0VBQW9JQkFRRFV4OWJjaE9lYVJISzBcbmcxcVNXaXdWeVZ1dDVRdkpHaUhjdTdYUW1rdGxpbjVLVmx3VkpaYUptVU1sQVpaNnZsZTVMTDBWMmh1TlhFdFJcbmlvZTVZWWFYRVhjRU5vek16dGNsbWVUcHBmdFJEWjZMUWF2b2Q0cWtxUS9nQVlTNXVHY3Y0SmNQZWFYNG91ZHJcbjNTZ1g3Ymdhd2hyZHoyYnRUdDJvVFdzMXc4K2lBc1ErRUQreUpqSFFBdVRQMnNVUjV4Ty95WGxVV1lnaEJyQ1RcbnJ5VVVFZnpQbnJLSTdoUUZsclMrMXo4WGxZb0kza2Npc1JkcVN0RGhlY1dVV2lqd2pBTkxrQklOWlZKV3kwTzBcbmF5L1RhME1ReFR0dU9WU1J2ZnZRV2VYMWhFVCtIOGZiTE5KWXNXNUhsTEx0eE1vem5WWHlxb05MNUhGY0R2emhcblZaWW1RMStmQWdNQkFBRUNnZ0VBRHpSVWN4K0FHVExvNjJNemRwL0E1TEdsdm5CT2ZrbEN3QzRkbU5GZHI5ek1cbmwyMUNXVFI5WkVteVZaT2VlQmpmMWRpUGpsOHVkdFJ3Z1Z3ZnhLeG1YS2NmMVFvODEybTBUL2lHTmZmcFZHcGZcbnVOMnhkZ1FNd1NWZmdBYzd2N1dna2ZnL2N4aWpObmdWaDB5ZlQ4NXB5R2UwV2NNM1BKL1ZFUEN2UjRFOWRmc1JcblE1OVUxVW1LQkNyVmRPZjIxb0kvdXZjMk1wVTZ6UmZyeDJJVytmNkhvaDVjanFZTUdqTjRjT3JtN1hXVDFmMXBcblhRdFpOUURsWFVpOGJ5NkRjYklYUWxaSlN3L1ZvdmdCL0pSTjgyWU5uVHhiSmpubkx1SS9FQUc1bHNpZmpRMlFcbkF6Y2x3ak84Q2dnREluaEhqemRqOFZzZVZCT2dIeUI3SXJaUHI3d253UUtCZ1FEdTM0b1JPTnRldjZObDhOcjFcbmtVT3dmNkRLSiswektkWDdKN2tuTnIrYXdyTXFjd3ZUcE9GYWZCOFg4Z0F3THNKa2hXdUw1aFZtS2tvL0szdzRcbldtcGF2Vm9JSWJPakZ3bkJuQXVsYkhlcC9lSXdLQlExQksxTzhyc3BDL1YwelpqVDFBMHJjVzJGTkRYbWE4TnJcbnRERnN1bHhka3B6cnduYy80bENBdGppd1lRS0JnUURrQ1dCOTdJL256R0NBQ0lXemZOeU9HTTErSmtiNVlmZkFcbi9vYnlHMWIreSt3MGpqbVEvd3RBaStYcXFxckRpMjVwU1RZZGtISzdWbm53eXphdXorSk5uM1Ntdk9TbVMydE5cbmVYK1p1WTBuVEdXZW53ZGMxOU1SMzlGOWF1SzArOUszYW1OVVpNQkRFWUpFbFEraW80N3hid1c3ZjFZTldVWFZcbm85QVhQVFlQL3dLQmdGTnBvY2ZUeDk2MUlyVEZQMkNEQWxVT3JESUxjU3Z0anZndDdkekFwSFhCU1Zrb1pWZlpcbmVvdmpUZVJKc0VFakF1U2hKbVhxeVV3c3RsS0t0OHpoM2NPajNWMTdqMFFERm5nU0tvcndiblRnMyt3YkFydGtcbno3UUMxTkpIaDhYcXlWUW05eFpWZkg0SU5rNHBFVXQ1MTh4MDR5NFZ0VkFxVHdQeTNsT2p6ZlhoQW9HQWVjRkhcbjgvUkxJY2pOL1k2UFZMWm1UTGlSZjdtUVM3Y3pRYWlsQkwvMFF6YytkeEU1UzJIaDhDVENMZm5TRTNadkRXZzVcbnJLOWprd01wT0poSUtpNTA5bDBkTzZtL3E4cTVFRFMvSEtVbDZNV3h2Ry9NenBXdDdPMUVQV0xFaVQycjFLTEpcblJsWkZFWXBYczZhaklvT1IzdmNZYUhRa3podk1YYldKZGQ4STdxRUNnWUFQTW0xVFRmQVR5NmJ3RXVaUnhYVktcbjRkU2NteTF3VVo1bGNobGgxNTd4bUNML1A0UDR6VGRtVThkUkhpenVydjFtUk5HaGRTOTJZckxyS2c4ZDJDVS9cbnAwZi8vU296UlltWVk2MDZYSUZ0S3BzbVdHdmg1ZmpRNnB4YjZmdlJDMHArMmdaV0V0YWowWVIwaDVLVGNVR2FcbnJxU2FzbzQxaXZ3UXptVHpNcnRaeUE9PVxuLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLVxuIiwKICAiY2xpZW50X2VtYWlsIjogInNhLWV2Zy1hcnRpZmFjdC1yZWdpc3RyeS1yZEBjYWxtLXByZW1pc2UtMTY4NDIwLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwKICAiY2xpZW50X2lkIjogIjExNzg0NzcwMDQ2MDQ4ODI0NTg1OCIsCiAgImF1dGhfdXJpIjogImh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi9hdXRoIiwKICAidG9rZW5fdXJpIjogImh0dHBzOi8vb2F1dGgyLmdvb2dsZWFwaXMuY29tL3Rva2VuIiwKICAiYXV0aF9wcm92aWRlcl94NTA5X2NlcnRfdXJsIjogImh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL29hdXRoMi92MS9jZXJ0cyIsCiAgImNsaWVudF94NTA5X2NlcnRfdXJsIjogImh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3JvYm90L3YxL21ldGFkYXRhL3g1MDkvc2EtZXZnLWFydGlmYWN0LXJlZ2lzdHJ5LXJkJTQwY2FsbS1wcmVtaXNlLTE2ODQyMC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIKfQ==</password>
        </server>
    </servers>
    <profiles>
        <profile>
            <id>artifact-eva</id>
            <repositories>
                 <repository>
                    <id>artifact-registry-evg</id>
                    <url>https://us-east1-maven.pkg.dev/calm-premise-168420/eva-evg</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
                <repository>
                    <id>repo1</id>
                    <url>https://repo1.maven.org/maven2/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
                <repository>
                    <id>Sonatype Repository</id>
                    <url>https://oss.sonatype.org/content/repositories/releases/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
                <repository>
                    <id>Spring Plugins Repository</id>
                    <url>https://repo.spring.io/plugins-release/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
                <repository>
                    <id>Spring Lib M Repository</id>
                    <url>https://repo.spring.io/libs-milestone/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
                <repository>
                    <id>Hortonworks Repository</id>
                    <url>https://repo.hortonworks.com/content/repositories/releases/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
                <repository>
                    <id>Atlassian Repository</id>
                    <url>https://maven.atlassian.com/content/repositories/atlassian-public/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
                <repository>
                    <id>JCenter</id>
                    <url>https://jcenter.bintray.com/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
                <repository>
                    <id>JBossEA Repository</id>
                    <url>https://repository.jboss.org/nexus/content/repositories/ea/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
                <repository>
                    <id>Spring Lib Release Repository</id>
                    <url>https://repo.spring.io/libs-release/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
                <repository>
                    <id>Apache Releases Repository</id>
                    <url>https://repository.apache.org/content/repositories/releases/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
            </repositories>
            <pluginRepositories>
                <pluginRepository>
                    <id>repo1</id>
                    <name>repo1</name>
                    <url>https://repo1.maven.org/maven2/</url>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </pluginRepository>
                <pluginRepository>
                    <id>spring-snapshots</id>
                    <name>Spring Snapshots</name>
                    <url>https://repo.spring.io/snapshot</url>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </pluginRepository>
            </pluginRepositories>
        </profile>
    </profiles>
    <activeProfiles>
        <activeProfile>artifact-eva</activeProfile>
    </activeProfiles>
</settings>

How to Include Evg Connector

To include the evg-connector in your project, use the @EnableEvgConnector annotation in your project's main class

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.everis.eva.evgconnector.annotation.EnableEvgConnector;

@EnableEvgConnector
@SpringBootApplication
public class EvgDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(EvgDemoApplication.class, args);
	}

}

Quickstart

To give an example of the connector's usage, we will create a class called DemoService and have it extend the EvgConnectorBase class.

The ConversationRequest object is used when calling the eva. What parameters to pass and what will be sent to the eva will be further detailed down this article.

In this example we are making a call to eva in order to execute a Welcome Flow. To know how to configure the eva call see the documentation Conversation API and for more about the authentication of the Conversation API see item Client Credentials Authorization.

This results in the execution of a flow, getting the response from the eva, and generating commands in the IVR based on the eva's response.

import java.util.List;

import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;

import com.everis.eva.evgconnector.properties.EvgSettings;
import com.everis.eva.evgconnector.properties.conversation.ConversationAuthProperties;
import com.everis.eva.evgconnector.properties.provider.MicrosoftProvider;
import com.everis.eva.evgconnector.service.EvgConnectorBase;
import com.everis.eva.evgconnector.service.commands.EvgCommand;
import com.everis.eva.evgconnector.service.conversation.ConversationRequest;
import com.everis.eva.evgconnector.service.conversation.ConversationResponse;
import com.everis.eva.evgconnector.service.evg.Evg;

@Service
public class DemoService extends EvgConnectorBase {

    private final EvgSettings evgSettings;

    public DemoService(EvgSettings evgSettings) {
        this.evgSettings = evgSettings;
    }

    @Override
    public Evg start(Evg evg) {

        String evaConversationAPIURL = "https://api-<your_eva_instance_label>.eva.bot/eva-broker/org/<your_org_uuid>/env/<your_env_uuid>/bot/<your_bot_uuid>/channel/<your_channel_uuid>/v1/conversations";

        ConversationRequest conversationRequest = createConversationRequest(evg);
        conversationRequest.getContext().put("dnis", evg.getTelcoData().getDnis());

        HttpHeaders headers = new HttpHeaders();
        headers.add("LOCALE", "<your_bot_locale>");
        headers.add("OS", "evg");
        headers.add("API-KEY", "<your_api_key>");
        headers.add("USER-REF", evg.getTelcoData().getAni());
        headers.add("BUSINESS-KEY", evg.getTelcoData().getAni());

        ConversationAuthProperties conversationAuthProperties = ConversationAuthProperties.builder()
                .keycloakUrl(
                        "https://keycloak-<your_eva_admin_label>.eva.bot/auth/realms/<your_realm_name>/protocol/openid-connect/token")
                .clientId("<your_client_id>")
                .secret("<your_secret>")
                .build();

        ConversationResponse conversationResponse = callEva(evg, evaConversationAPIURL,
                conversationRequest,
                headers, conversationAuthProperties);

        MicrosoftProvider microsoftProvider = MicrosoftProvider.builder()
                .region("<your_region>")
                .subscriptionKey("<your_subscription_key>")
                .language("<your_bot_locale>")
                .build();

        evgSettings.setMicrosoftProvider(microsoftProvider);

        List<EvgCommand> commands = createCommands(evg, conversationResponse);
        return createResponse(evg, commands, evgSettings.getFetch());
    }
}

Testing the Connector

The evg (IVR) to process a call will consume the endpoint that the evg connector provides.

The following is a simple example of a request.

Sample JSON

{
    "evgCallStatus": "INIT",
    "telcoData": {
        "ani": "<your_ani>",
        "dnis": "<your_dnis>",
        "sipCallId": "sip-call-id",
        "originIp": "ip-example",
        "customerSipDomain": "@exemple.com.br"
    },
    "context": {
    }
}

Use this JSON to test your implementation.

Conversation service

Below is the endpoint documentation for the API request mentioned on the previous section:

MethodPOST

URL

/conversations

Type

application/json

Request body and Response body

NameTypeRequiredDescription

evgCallStatus

Yes

An enumeration that represents the status of the call.

telcoData

Yes

Contains call data such as the number making and receiving the call.

context

JSON Object

Yes

Helper object that can be used to keep the state of the call, in it we can store data that will be kept during the call, for example, the sessionCode of the eva.

commandList

Yes, unless when evgCallStatus is INIT

A list of commands that will be executed in IVR.

fetch

No

Defines IVR behavior when it needs to fetch a page, URL or JSON.

EvgCallStatus

NameDescription

INIT

Indicates the initial state of the call. The first request being made.

CONTINUE

Indicates a call in progress.

USER_DISCONNECTED

This status indicates that the user disconnected the call.

IVR_DISCONNECTED

This status indicates that the IVR disconnected the call.

TRANSFERRED

This status indicates that the IVR disconnected the call.

ERROR

Indicates a error state.

TelcoData

NameTypeDescription

ani

String

Calling number.

dnis

String

Incoming number.

sipCallId

String

It is a unique call id generated by the SBC.

originIp

String

Call source address (SBC address).

customerSipDomain

String

It is the domain that identifies the provider.

EvgCommand

NameTypeDescription

commandOrder

int

Orders the execution of commands.

commandType

It is an enumeration that represents the type of command that will be executed.

result

Result of commands executed.

EvgCommandEnum

NameDescription

PLAY_AUDIO

It is a type of audio media playback, the supported types are: WAV or FLAC.

PLAY_TTS

It is the type that indicates sanitization of a text.

PLAY_SILENCE

It is the reproduction of silence.

VOICE_MENU

Enables the user to interact in the call through voice.

DTMF_MENU

Enables the user to interact in the call through the cell phone keypad.

DTMF_VOICE_MENU

Enables the user to interact in the call through voice and the cell phone keypad.

TRANSFER

Indicates that the call will be transfer.

HANGUP

Indicates that the call will be terminate.

EvgCommandResult

NameTypeDescription

status

Enumeration that indicates the execution status of the requested command.

message

String

Contains the details of the execution.

digits

String

User input, the value is filled when the user uses the cell phone keyboard.

transcription

String

User input, the value is filled when the user speak.

EvgResultEnum

NameDescription

SUCCESS

Indicates a successful queuing of the audio file or a successful queuing of the TTS synthesizer request command.

ERROR

Informs that an error status occurred in the command. More details should be looked for in the error message.

FILLED

This enumeration indicates that the client's response to the menu (either voice or DTMF) successfully met the criteria configured therein. (e.g.: correct number of DTMF digits or successful transcription)

DISCONNECT

This status tells you that the customer disconnected the call while processing the call. Usually occurs during menus or transfer requests.

NO_INPUT

This enumeration indicates that the customer's response to the menu (either voice or DTMF) did not meet the criteria configured therein because he did not type any DTMF option or because he did not speak any words or phrases.

NO_MATCH

This enumeration indicates that the client's response to the menu (either voice or DTMF) did not meet the criteria set there because he did not type a valid DTMF length (but did type some DTMF) or because he did not speak any words or phrases that could be transcribed (But noise was detected).

Fetch

NameTypeDescription

fetchTimeout

Long

The default amount of time in milliseconds the IVR will wait for a page/json fetch.

fetchAudio

String

The path to the default audio file to be used during IVR platform fetch events.

fetchAudioDelay

Long

The default value for the fetch audio delay. This is the amount of time in milliseconds the IVR will wait while transitioning and fetching resources before it starts playing the fetch audio.

fetchAudioMinimum

Long

The minimum time in milliseconds to play a fetch audio source, once started, even if the fetch result arrives in the meantime. The idea is that once the user does begin to hear a fetch audio, it should not be stopped too quickly.

fetchAudioInterval

Long

Controls the time interval between fetch audio loops. The default value is 0. A value of -1 is valid and will prevent the audio loop.