Skip to content

Commit

Permalink
feat: Add mode to InputAction
Browse files Browse the repository at this point in the history
  • Loading branch information
SMadani committed Oct 16, 2024
1 parent a394707 commit e015876
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 37 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).

# [8.12.0] - 2024-10-??
- Added `network_apis` capability to Application API
- Added `mode` property to `InputAction` NCCO
- Refactored `InputAction.Builder` and added constructor validation
- Added `@JsonCreator` annotation to webhook classes' `fromJson(String)` method

# [8.11.0] - 2024-09-25
Expand Down
140 changes: 121 additions & 19 deletions src/main/java/com/vonage/client/voice/ncco/InputAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@

import com.fasterxml.jackson.annotation.JsonProperty;
import com.vonage.client.JsonableBaseObject;
import java.util.Arrays;
import java.util.Collection;
import java.util.*;

/**
* An NCCO input action which allows for the collection of digits and automatic speech recognition from a person.
Expand All @@ -32,15 +31,21 @@ public class InputAction extends JsonableBaseObject implements Action {
private Collection<String> eventUrl;
private SpeechSettings speech;
private EventMethod eventMethod;
private InputMode mode;

InputAction() {}

private InputAction(Builder builder) {
type = builder.type;
dtmf = builder.dtmf;
eventUrl = builder.eventUrl;
eventMethod = builder.eventMethod;
speech = builder.speech;
mode = builder.mode;
if ((type = builder.type).isEmpty()) {
throw new IllegalStateException("At least one input type must be specified.");
}
if ((dtmf = builder.dtmf) != null && mode == InputMode.ASYNCHRONOUS) {
throw new IllegalStateException("DTMF settings cannot be used with asynchronous mode.");
}
}

@Override
Expand Down Expand Up @@ -73,52 +78,134 @@ public SpeechSettings getSpeech() {
return speech;
}

/**
* How the input should be processed. If not set, the default is {@linkplain InputMode#SYNCHRONOUS}.
*
* @return The mode as an enum, or {@code null} if unspecified.
* @since 8.12.0
*/
@JsonProperty("mode")
public InputMode getMode() {
return mode;
}

/**
* Entrypoint for constructing an instance of this class.
*
* @return A new Builder.
*/
public static Builder builder() {
return new Builder();
}

/**
* Builder for specifying the properties of an InputAction.
*/
public static class Builder {
private final Collection<String> type = new LinkedHashSet<>(2, 1f);
private DtmfSettings dtmf;
private Collection<String> eventUrl;
private EventMethod eventMethod;
private SpeechSettings speech;
private Collection<String> type;
private InputMode mode;

private Builder() {}

/**
* @param dtmf DTMF settings object to enable DTMF input.
* Enables DTMF with the default settings.
*
* @return This builder to keep building the input action.
* @since 8.12.0
*/
public Builder dtmf() {
dtmf(null);
type.add("dtmf");
return this;
}

/**
* Enable DTMF input with the provided settings. Note that if you override any of
* the defaults, you cannot set {@linkplain #mode(InputMode)} to {@linkplain InputMode#ASYNCHRONOUS}.
*
* @param dtmf The DTMF settings object.
* @return This builder to keep building the input action.
* @since 6.0.0
*/
public Builder dtmf(DtmfSettings dtmf) {
this.dtmf = dtmf;
if ((this.dtmf = dtmf) != null) {
type.add("dtmf");
}
else {
type.remove("dtmf");
}
return this;
}

/**
* Automatic Speech Recognition (ASR) settings to enable speech input.
* Required if {@linkplain #dtmf(DtmfSettings)} is not provided.
*
* @param speech The speech settings object.
* @return This builder to keep building the input action.
* @since 6.0.0
*/
public Builder speech(SpeechSettings speech) {
if ((this.speech = speech) != null) {
type.add("speech");
}
else {
type.remove("speech");
}
return this;
}

/**
* @param eventUrl Vonage sends the digits pressed by the callee to this URL after timeOut pause in activity or
* when # is pressed.
* Vonage sends the digits pressed by the callee to this URL after timeOut pause inactivity or when
* {@code #} is pressed.
*
* @param eventUrl The URL wrapped in a singleton collection to send the event metadata to.
*
* @return This builder to keep building the input action.
* @deprecated This will be removed in a future release. Use {@link #eventUrl(String)} instead.
*/
@Deprecated
public Builder eventUrl(Collection<String> eventUrl) {
this.eventUrl = eventUrl;
return this;
}

/**
* @param eventUrl Vonage sends the digits pressed by the callee to this URL after timeOut pause in activity or
* when # is pressed.
* Vonage sends the digits pressed by the callee to this URL after timeOut pause inactivity or when
* {@code #} is pressed.
*
* @param eventUrl The URL to send the event metadata to.
*
* @return This builder to keep building the input action.
* @deprecated This will be removed in a future release. Use {@link #eventUrl(String)} instead.
*/
@Deprecated
public Builder eventUrl(String... eventUrl) {
return eventUrl(Arrays.asList(eventUrl));
}

/**
* @param eventMethod The HTTP method used to send event information to event_url The default value is POST.
* Vonage sends the digits pressed by the callee to this URL after timeOut pause inactivity or when
* {@code #} is pressed.
*
* @param eventUrl The URL to send the event metadata to.
*
* @return This builder to keep building the input action.
*
* @since 8.12.0
*/
public Builder eventUrl(String eventUrl) {
return eventUrl(Collections.singletonList(eventUrl));
}

/**
* The HTTP method used to send event information to event_url The default value is POST.
*
* @param eventMethod The HTTP method to use for the event as an enum.
*
* @return This builder to keep building the input action.
*/
Expand All @@ -128,22 +215,37 @@ public Builder eventMethod(EventMethod eventMethod) {
}

/**
* @param speech Automatic speech recognition settings object to enable speech input. Required if dtmf is not provided.
* How the input should be processed. If not set, the default is {@linkplain InputMode#SYNCHRONOUS}.
* If set to {@linkplain InputMode#ASYNCHRONOUS}, use {@link #dtmf()} instead of {@link #dtmf(DtmfSettings)}.
*
* @param mode The DTMF processing mode as an enum.
* @return This builder to keep building the input action.
* @since 6.0.0
* @since 8.12.0
*/
public Builder speech(SpeechSettings speech) {
this.speech = speech;
public Builder mode(InputMode mode) {
this.mode = mode;
return this;
}

/**
* @param type Acceptable input type, can be set as [ "dtmf" ] for DTMF input only, [ "speech" ] for ASR only,
* or [ "dtmf", "speech" ] for both.
* Sets the acceptable input types. From v8.12.0 onwards, you should not call this method manually;
* instead, use {@link #dtmf()} and / or {@link #speech(SpeechSettings)}. This method will be removed
* in a future release.
*
* @param type Acceptable input types as a collection. Valid values are ["dtmf"] for DTMF input only,
* ["speech"] for ASR only, or ["dtmf", "speech"] for both.
*
* @return This builder to keep building the input action.
*
* @deprecated Use {@link #dtmf(DtmfSettings)} and {@link #speech(SpeechSettings)} instead.
* The type will be set automatically based on the provided settings.
*/
@Deprecated
public Builder type(Collection<String> type) {
this.type = type;
this.type.clear();
if (type != null) {
this.type.addAll(type);
}
return this;
}

Expand Down
54 changes: 54 additions & 0 deletions src/main/java/com/vonage/client/voice/ncco/InputMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2024 Vonage
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.vonage.client.voice.ncco;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

/**
* Represents the input mode for {@link InputAction}.
*
* @since 8.12.0
*/
public enum InputMode {
/**
* Process input synchronously (the default). This is the standard behaviour if not set.
*/
SYNCHRONOUS,

/**
* Process input asynchronously. For DTMF, this means that the input is sent to the event URL webhook one digit
* at a time. Consequently, the {@link DtmfSettings} are ignored.
*/
ASYNCHRONOUS;

@JsonValue
@Override
public String toString() {
return name().toLowerCase();
}

@JsonCreator
public static InputMode fromString(String name) {
if (name == null) return null;
try {
return InputMode.valueOf(name.toUpperCase());
}
catch (IllegalArgumentException ex) {
return null;
}
}
}
4 changes: 2 additions & 2 deletions src/test/java/com/vonage/client/voice/CallTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,11 @@ public void testNccoParameterWithMultiActionNcco() {
Call call = new Call("15551234567", "25551234567", Arrays.asList(
TalkAction.builder("Hello World").build(),
RecordAction.builder().build(),
InputAction.builder().build(),
InputAction.builder().dtmf().build(),
TalkAction.builder("Goodbye").build()
));
assertEquals(
"{\"to\":[{\"number\":\"15551234567\",\"type\":\"phone\"}],\"from\":{\"number\":\"25551234567\",\"type\":\"phone\"},\"ncco\":[{\"text\":\"Hello World\",\"action\":\"talk\"},{\"action\":\"record\"},{\"action\":\"input\"},{\"text\":\"Goodbye\",\"action\":\"talk\"}]}",
"{\"to\":[{\"number\":\"15551234567\",\"type\":\"phone\"}],\"from\":{\"number\":\"25551234567\",\"type\":\"phone\"},\"ncco\":[{\"text\":\"Hello World\",\"action\":\"talk\"},{\"action\":\"record\"},{\"type\":[\"dtmf\"],\"action\":\"input\"},{\"text\":\"Goodbye\",\"action\":\"talk\"}]}",
call.toJson()
);
}
Expand Down
Loading

0 comments on commit e015876

Please sign in to comment.