diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/ConvoAIClient.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/ConvoAIClient.java index 441c1c4..5f37f7c 100644 --- a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/ConvoAIClient.java +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/ConvoAIClient.java @@ -4,10 +4,14 @@ import io.agora.rest.core.DefaultContext; import io.agora.rest.services.convoai.req.JoinConvoAIReq; import io.agora.rest.services.convoai.req.ListConvoAIReq; +import io.agora.rest.services.convoai.req.SpeakConvoAIReq; import io.agora.rest.services.convoai.req.UpdateConvoAIReq; +import io.agora.rest.services.convoai.res.HistoryConvoAIRes; +import io.agora.rest.services.convoai.res.InterruptConvoAIRes; import io.agora.rest.services.convoai.res.JoinConvoAIRes; import io.agora.rest.services.convoai.res.ListConvoAIRes; import io.agora.rest.services.convoai.res.QueryConvoAIRes; +import io.agora.rest.services.convoai.res.SpeakConvoAIRes; import io.agora.rest.services.convoai.res.UpdateConvoAIRes; import reactor.core.publisher.Mono; @@ -18,7 +22,8 @@ public abstract class ConvoAIClient { /** * @param convoAIConfig Instance of {@link ConvoAIConfig}. * @return Returns the Conversational AI engine client instance. - * @brief Creates a Conversational AI engine client with the specified configuration. + * @brief Creates a Conversational AI engine client with the specified + * configuration. * @since v0.3.0 */ public static synchronized ConvoAIClient create(ConvoAIConfig convoAIConfig) { @@ -36,11 +41,13 @@ public static synchronized ConvoAIClient create(ConvoAIConfig convoAIConfig) { } /** - * @param request Parameters for the join request to the conversational AI engine, see {@link JoinConvoAIReq}. + * @param request Parameters for the join request to the conversational AI + * engine, see {@link JoinConvoAIReq}. * @return Returns the join response result, see {@link JoinConvoAIRes}. * @brief Creates an agent instance and joins the specified RTC channel. * @example Use this to create an agent instance in an RTC channel. - * @post After successful execution, the agent will join the specified channel. You can perform subsequent operations using the returned agent ID. + * @post After successful execution, the agent will join the specified channel. + * You can perform subsequent operations using the returned agent ID. * @since v0.3.0 */ public abstract Mono join(JoinConvoAIReq request); @@ -49,18 +56,23 @@ public static synchronized ConvoAIClient create(ConvoAIConfig convoAIConfig) { * @param agentId Agent ID * @brief Stops the specified agent instance and leaves the RTC channel. * @example Use this to stop an agent instance. - * @post After successful execution, the agent will be stopped and leave the RTC channel. - * @note Ensure the agent ID has been obtained by calling the join API before using this method. + * @post After successful execution, the agent will be stopped and leave the RTC + * channel. + * @note Ensure the agent ID has been obtained by calling the join API before + * using this method. * @since v0.3.0 */ public abstract Mono leave(String agentId); /** - * @param request Parameters for listing conversational agents, see {@link ListConvoAIReq}. - * @return Returns the list response result, see {@link ListConvoAIRes} for details. + * @param request Parameters for listing conversational agents, see + * {@link ListConvoAIReq}. + * @return Returns the list response result, see {@link ListConvoAIRes} for + * details. * @brief Retrieves a list of agents that meet the specified criteria. * @example Use this to get a list of agents that meet the specified criteria. - * @post After successful execution, a list of agents that meet the specified criteria will be retrieved. + * @post After successful execution, a list of agents that meet the specified + * criteria will be retrieved. * @since v0.3.0 */ public abstract Mono list(ListConvoAIReq request); @@ -70,22 +82,61 @@ public static synchronized ConvoAIClient create(ConvoAIConfig convoAIConfig) { * @return Returns the query response result, see {@link QueryConvoAIRes} * @brief Query the current status of the specified agent instance. * @example Use this to get the current status of the specified agent instance. - * @post After successful execution, the current running status information of the specified agent instance will be retrieved. - * @note Ensure the agent ID has been obtained by calling the join API before using this method. + * @post After successful execution, the current running status information of + * the specified agent instance will be retrieved. + * @note Ensure the agent ID has been obtained by calling the join API before + * using this method. * @since v0.3.0 */ public abstract Mono query(String agentId); /** * @param agentId Agent ID - * @param request Parameters for updating the conversational agent, see {@link UpdateConvoAIReq} for details. - * @return Returns the update response result, see {@link UpdateConvoAIRes}. + * @param request Parameters for updating the conversational agent, see + * {@link UpdateConvoAIReq} for details. + * @return Returns the update response result, see {@link UpdateConvoAIRes} + * for details. * @brief Adjusts the agent's parameters at runtime. * @example Use this to adjust the agent's parameters at runtime. * @post After successful execution, the agent's parameters will be adjusted. - * @note Ensure the agent ID has been obtained by calling the join API before using this method. + * @note Ensure the agent ID has been obtained by calling the join API before + * using this method. * @since v0.3.0 */ public abstract Mono update(String agentId, UpdateConvoAIReq request); + /** + * @brief Acquires the short-term memory of the specified agent instance + * @since v0.4.0 + * @example Use this method to acquire the short-term memory of the specified + * agent instance. + * @param agentId Agent ID. + * @return Returns the short-term memory of the specified agent instance. See + * {@link HistoryConvoAIRes} for details. + */ + public abstract Mono getHistory(String agentId); + + /** + * @brief Interrupts the specified agent instance + * @since v0.9.0 + * @example Use this method to interrupt the specified agent instance. + * @param agentId Agent ID. + * @return Returns the interrupt response result, see + * {@link InterruptConvoAIRes}. + */ + public abstract Mono interrupt(String agentId); + + /** + * @brief Speaks a custom message for the specified agent instance + * @since v0.9.0 + * @example Use this method to speak a custom message for the specified agent + * instance. + * @param agentId Agent ID. + * @param request Request body for the specified agent to speak a custom + * message. See {@link SpeakConvoAIReq} for details. + * @return Returns the response *SpeakResp. See {@link SpeakConvoAIRes} for + * details. + */ + public abstract Mono speak(String agentId, SpeakConvoAIReq request); + } diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/ConvoAIClientImpl.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/ConvoAIClientImpl.java index 9f02069..8ebaf5d 100644 --- a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/ConvoAIClientImpl.java +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/ConvoAIClientImpl.java @@ -5,10 +5,14 @@ import io.agora.rest.services.convoai.api.*; import io.agora.rest.services.convoai.req.JoinConvoAIReq; import io.agora.rest.services.convoai.req.ListConvoAIReq; +import io.agora.rest.services.convoai.req.SpeakConvoAIReq; import io.agora.rest.services.convoai.req.UpdateConvoAIReq; +import io.agora.rest.services.convoai.res.HistoryConvoAIRes; +import io.agora.rest.services.convoai.res.InterruptConvoAIRes; import io.agora.rest.services.convoai.res.JoinConvoAIRes; import io.agora.rest.services.convoai.res.ListConvoAIRes; import io.agora.rest.services.convoai.res.QueryConvoAIRes; +import io.agora.rest.services.convoai.res.SpeakConvoAIRes; import io.agora.rest.services.convoai.res.UpdateConvoAIRes; import reactor.core.publisher.Mono; @@ -24,6 +28,12 @@ public class ConvoAIClientImpl extends ConvoAIClient { private final UpdateConvoAIAPI updateConvoAIAPI; + private final HistoryConvoAIAPI historyConvoAIAPI; + + private final InterruptConvoAIAPI interruptConvoAIAPI; + + private final SpeakConvoAIAPI speakConvoAIAPI; + private final static String chineseMainlandPrefixTpl = "/cn/api/conversational-ai-agent/v2/projects/%s"; private final static String globalPrefixTpl = "/api/conversational-ai-agent/v2/projects/%s"; @@ -35,6 +45,9 @@ protected ConvoAIClientImpl(Context context, ConvoAIServiceRegionEnum serviceReg listConvoAIAPI = new ListConvoAIAPI(context, pathPrefix); queryConvoAIAPI = new QueryConvoAIAPI(context, pathPrefix); updateConvoAIAPI = new UpdateConvoAIAPI(context, pathPrefix); + historyConvoAIAPI = new HistoryConvoAIAPI(context, pathPrefix); + interruptConvoAIAPI = new InterruptConvoAIAPI(context, pathPrefix); + speakConvoAIAPI = new SpeakConvoAIAPI(context, pathPrefix); } private String getPathPrefix(Context context, ConvoAIServiceRegionEnum serviceRegionEnum) { @@ -75,4 +88,16 @@ public Mono query(String agentId) { public Mono update(String agentId, UpdateConvoAIReq request) { return updateConvoAIAPI.handle(agentId, request); } + + public Mono getHistory(String agentId) { + return historyConvoAIAPI.handle(agentId); + } + + public Mono interrupt(String agentId) { + return interruptConvoAIAPI.handle(agentId); + } + + public Mono speak(String agentId, SpeakConvoAIReq request) { + return speakConvoAIAPI.handle(agentId, request); + } } diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/ConvoAIConfig.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/ConvoAIConfig.java index 2114db3..e22a895 100644 --- a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/ConvoAIConfig.java +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/ConvoAIConfig.java @@ -113,6 +113,11 @@ public Builder domainArea(DomainArea domainArea) { return this; } + public Builder httpProperty(HttpProperty httpProperty) { + this.httpProperty = httpProperty; + return this; + } + public Builder serverRegion(ConvoAIServiceRegionEnum serverRegion) { this.serviceRegion = serverRegion; return this; diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/api/HistoryConvoAIAPI.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/api/HistoryConvoAIAPI.java new file mode 100644 index 0000000..c70a798 --- /dev/null +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/api/HistoryConvoAIAPI.java @@ -0,0 +1,22 @@ +package io.agora.rest.services.convoai.api; + +import io.agora.rest.core.Context; +import io.agora.rest.services.convoai.res.HistoryConvoAIRes; +import io.netty.handler.codec.http.HttpMethod; +import reactor.core.publisher.Mono; + +public class HistoryConvoAIAPI { + private final Context context; + + private final String pathPrefix; + + public HistoryConvoAIAPI(Context context, String pathPrefix) { + this.context = context; + this.pathPrefix = pathPrefix; + } + + public Mono handle(String agentId) { + String path = String.format("%s/agents/%s/history", pathPrefix, agentId); + return this.context.sendRequest(path, HttpMethod.GET, null, HistoryConvoAIRes.class); + } +} diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/api/InterruptConvoAIAPI.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/api/InterruptConvoAIAPI.java new file mode 100644 index 0000000..e143c4f --- /dev/null +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/api/InterruptConvoAIAPI.java @@ -0,0 +1,22 @@ +package io.agora.rest.services.convoai.api; + +import io.agora.rest.core.Context; +import io.agora.rest.services.convoai.res.InterruptConvoAIRes; +import io.netty.handler.codec.http.HttpMethod; +import reactor.core.publisher.Mono; + +public class InterruptConvoAIAPI { + private final Context context; + + private final String pathPrefix; + + public InterruptConvoAIAPI(Context context, String pathPrefix) { + this.context = context; + this.pathPrefix = pathPrefix; + } + + public Mono handle(String agentId) { + String path = String.format("%s/agents/%s/interrupt", pathPrefix, agentId); + return this.context.sendRequest(path, HttpMethod.POST, null, InterruptConvoAIRes.class); + } +} diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/api/SpeakConvoAIAPI.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/api/SpeakConvoAIAPI.java new file mode 100644 index 0000000..686014b --- /dev/null +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/api/SpeakConvoAIAPI.java @@ -0,0 +1,24 @@ +package io.agora.rest.services.convoai.api; + +import io.agora.rest.core.Context; +import io.agora.rest.services.convoai.req.SpeakConvoAIReq; +import io.agora.rest.services.convoai.res.SpeakConvoAIRes; +import io.netty.handler.codec.http.HttpMethod; +import reactor.core.publisher.Mono; + +public class SpeakConvoAIAPI { + private final Context context; + + private final String pathPrefix; + + public SpeakConvoAIAPI(Context context, String pathPrefix) { + this.context = context; + this.pathPrefix = pathPrefix; + } + + public Mono handle(String agentId, SpeakConvoAIReq request) { + String path = String.format("%s/agents/%s/speak", pathPrefix, agentId); + return this.context.sendRequest(path, HttpMethod.POST, request, SpeakConvoAIRes.class); + } + +} diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/req/JoinConvoAIReq.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/req/JoinConvoAIReq.java index 45c062f..77c9346 100644 --- a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/req/JoinConvoAIReq.java +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/req/JoinConvoAIReq.java @@ -8,7 +8,8 @@ import java.util.Map; /** - * @brief Request Body parameters for calling the Conversational AI engine join API + * @brief Request Body parameters for calling the Conversational AI engine join + * API * @since v0.3.0 */ public class JoinConvoAIReq { @@ -57,9 +58,11 @@ public void setProperties(Properties properties) { public static class Properties { /** - * Token used to join the RTC channel, i.e., the dynamic key for authentication (optional). + * Token used to join the RTC channel, i.e., the dynamic key for authentication + * (optional). *

- * If your project has enabled the App Certificate, you must pass the dynamic key in this field. + * If your project has enabled the App Certificate, you must pass the dynamic + * key in this field. */ @JsonProperty("token") private String token; @@ -73,14 +76,16 @@ public static class Properties { /** * User ID of the agent in the RTC channel (required) *

- * Filling "0" means a random assignment, but the Token needs to be modified accordingly + * Filling "0" means a random assignment, but the Token needs to be modified + * accordingly *

*/ @JsonProperty("agent_rtc_uid") private String agentRtcUId; /** - * List of user IDs that the agent subscribes to in the RTC channel, only subscribed users can interact with the agent (required) + * List of user IDs that the agent subscribes to in the RTC channel, only + * subscribed users can interact with the agent (required) *

* Passing "*" means subscribing to all users in the channel. *

@@ -101,9 +106,11 @@ public static class Properties { /** * Maximum idle time of the RTC channel (s) (optional) *

- * The time after all users specified in remote_rtc_uids leave the channel is considered idle time. + * The time after all users specified in remote_rtc_uids leave the channel is + * considered idle time. *

- * If it exceeds the set maximum value, the agent will automatically stop and exit the channel. + * If it exceeds the set maximum value, the agent will automatically stop and + * exit the channel. *

* If set to 0, the agent will only stop when manually exited. *

@@ -121,39 +128,44 @@ public static class Properties { private String agentRtmUId; /** - * Advanced feature configurations (optional), see {@link AdvancedFeatures} for details + * Advanced feature configurations (optional), see {@link AdvancedFeatures} for + * details */ @JsonProperty("advanced_features") private AdvancedFeatures advancedFeatures; /** - * Custom language model (LLM) configuration (required), see {@link LLMPayload} for details + * Custom language model (LLM) configuration (required), see {@link LLMPayload} + * for details */ @JsonProperty("llm") private LLMPayload llmPayload; /** - * Text-to-Speech (TTS) module configuration (optional), see {@link TTSPayload} for details + * Text-to-Speech (TTS) module configuration (optional), see {@link TTSPayload} + * for details */ @JsonProperty("tts") private TTSPayload ttsPayload; /** - * Voice Activity Detection (VAD) configuration (optional), see {@link VADPayload} for details + * Voice Activity Detection (VAD) configuration (optional), see + * {@link VADPayload} for details */ @JsonProperty("vad") private VADPayload vadPayload; /** - * Automatic Speech Recognition (ASR) configuration (optional), see {@link ASRPayload} for details + * Automatic Speech Recognition (ASR) configuration (optional), see + * {@link ASRPayload} for details */ @JsonProperty("asr") private ASRPayload asrPayload; - public static Builder builder() { return new Builder(); } + private Properties(Builder builder) { setToken(builder.token); setChannel(builder.channel); @@ -349,7 +361,8 @@ public Properties build() { } /** - * @brief Defines advanced feature configuration for the agent to join RTC channel + * @brief Defines advanced feature configuration for the agent to join RTC + * channel * @since v0.3.0 */ public static class AdvancedFeatures { @@ -361,7 +374,8 @@ public static class AdvancedFeatures { *

* - false: Do not enable (default) *

- * When enabled, users can interrupt the AI at any time and respond quickly, achieving natural transitions and smooth conversations. + * When enabled, users can interrupt the AI at any time and respond quickly, + * achieving natural transitions and smooth conversations. */ @JsonProperty("enable_aivad") private Boolean enableAIVad; @@ -373,7 +387,8 @@ public static class AdvancedFeatures { *

* - false: Do not enable (default) *

- * When enabled, the agent can use the capabilities provided by RTM to implement some advanced features. + * When enabled, the agent can use the capabilities provided by RTM to implement + * some advanced features. */ @JsonProperty("enable_rtm") private Boolean enableRtm; @@ -427,7 +442,8 @@ public AdvancedFeatures build() { } /** - * @brief Defines the custom language model (LLM) configuration for the agent to join the RTC channel + * @brief Defines the custom language model (LLM) configuration for the agent to + * join the RTC channel * @since v0.3.0 */ public static class LLMPayload { @@ -449,17 +465,21 @@ public static class LLMPayload { private String apiKey; /** - * A set of predefined information attached at the beginning of each LLM call, used to control LLM output (optional) + * A set of predefined information attached at the beginning of each LLM call, + * used to control LLM output (optional) *

- * Can be role settings, prompts, and answer examples, must be compatible with OpenAI protocol + * Can be role settings, prompts, and answer examples, must be compatible with + * OpenAI protocol */ @JsonProperty("system_messages") private List> systemMessages; /** - * Additional information transmitted in the LLM message body, such as the model used, maximum token limit, etc. (optional) + * Additional information transmitted in the LLM message body, such as the model + * used, maximum token limit, etc. (optional) *

- * Different LLM providers support different configurations, see their respective LLM documentation for details. + * Different LLM providers support different configurations, see their + * respective LLM documentation for details. */ @JsonProperty("params") private HashMap params; @@ -469,7 +489,8 @@ public static class LLMPayload { *

* Default value is 10 *

- * Passing 0 means no short-term memory is cached. agent and subscribed users will record entries separately. + * Passing 0 means no short-term memory is cached. agent and subscribed users + * will record entries separately. */ @JsonProperty("max_history") private Integer maxHistory; @@ -477,7 +498,9 @@ public static class LLMPayload { /** * Agent greeting message (optional) *

- * If filled, the agent will automatically send a greeting message to the first subscribed user who joins the channel when there are no users in the remote_rtc_uids list. + * If filled, the agent will automatically send a greeting message to the first + * subscribed user who joins the channel when there are no users in the + * remote_rtc_uids list. */ @JsonProperty("greeting_message") private String greetingMessage; @@ -487,7 +510,8 @@ public static class LLMPayload { *

* - ["text"]: Text only (default) *

- * - ["text", "image"]: Text and image, requires the selected LLM to support visual modality input + * - ["text", "image"]: Text and image, requires the selected LLM to support + * visual modality input */ @JsonProperty("input_modalities") private List inputModalities; @@ -495,11 +519,14 @@ public static class LLMPayload { /** * Output modalities of the LLM (optional) *

- * - ["text"]: Text only (default), the output text will be converted to speech by the TTS module and then published to the RTC channel. + * - ["text"]: Text only (default), the output text will be converted to speech + * by the TTS module and then published to the RTC channel. *

- * - ["audio"]: Audio only. The audio will be directly published to the RTC channel. + * - ["audio"]: Audio only. The audio will be directly published to the RTC + * channel. *

- * - ["text", "audio"]: Text and audio. You can write your own logic to handle the LLM output as needed. + * - ["text", "audio"]: Text and audio. You can write your own logic to handle + * the LLM output as needed. */ @JsonProperty("output_modalities") private List outputModalities; @@ -507,7 +534,8 @@ public static class LLMPayload { /** * Failure message of the agent (optional) *

- * If filled, it will be returned through the TTS module when the LLM call fails. + * If filled, it will be returned through the TTS module when the LLM call + * fails. */ @JsonProperty("failure_message") private String failureMessage; @@ -669,7 +697,8 @@ public interface TTSVendorParams { } /** - * @brief Defines the Text-to-Speech (TTS) module configuration for the agent to join the RTC channel + * @brief Defines the Text-to-Speech (TTS) module configuration for the agent to + * join the RTC channel * @since v0.3.0 */ public static class TTSPayload { @@ -794,7 +823,7 @@ public String toString() { /** * @brief Define Minimax TTS module parameters, see - * Minimax + * Minimax * @since v0.3.0 */ public static class MinimaxTTSVendorParams implements TTSVendorParams { @@ -928,7 +957,6 @@ public MinimaxTTSVendorParams build() { } } - /** * @brief Defines Minimax vendor audio setting parameters * @since v0.3.0 @@ -1105,7 +1133,8 @@ public MinimaxTTSVendorVoiceSettingParam build() { /** * @brief Define Tencent TTS module parameters, see - * Tencent + * Tencent * @since v0.3.0 */ public static class TencentTTSVendorParams implements TTSVendorParams { @@ -1306,7 +1335,7 @@ public TencentTTSVendorParams build() { /** * @brief Define Bytedance TTS module parameters, see - * Bytedance + * Bytedance * @since v0.3.0 */ public static class BytedanceTTSVendorParams implements TTSVendorParams { @@ -1682,7 +1711,8 @@ public ElevenLabsTTSVendorParams build() { } /** - * @brief Defines the Voice Activity Detection (VAD) configuration for the agent to join the RTC channel + * @brief Defines the Voice Activity Detection (VAD) configuration for the agent + * to join the RTC channel * @since v0.3.0 */ public static class VADPayload { @@ -1690,7 +1720,8 @@ public static class VADPayload { /** * Human voice duration threshold (ms), range [120, 1200] (optional) *

- * Minimum duration of continuous human voice signal to avoid false interruptions. + * Minimum duration of continuous human voice signal to avoid false + * interruptions. */ @JsonProperty("interrupt_duration_ms") private Integer interruptDurationMs; @@ -1698,7 +1729,8 @@ public static class VADPayload { /** * Prefix padding threshold (ms), range [0, 5000] (optional) *

- * Minimum duration of voice required to start a new speech segment to avoid triggering voice activity detection with very short sounds. + * Minimum duration of voice required to start a new speech segment to avoid + * triggering voice activity detection with very short sounds. */ @JsonProperty("prefix_padding_ms") private Integer prefixPaddingMs; @@ -1706,7 +1738,8 @@ public static class VADPayload { /** * Silence duration threshold (ms), range [0, 2000] (optional) *

- * Minimum duration of silence at the end of speech to ensure short pauses do not prematurely end the speech segment. + * Minimum duration of silence at the end of speech to ensure short pauses do + * not prematurely end the speech segment. */ @JsonProperty("silence_duration_ms") private Integer silenceDurationMs; @@ -1714,9 +1747,11 @@ public static class VADPayload { /** * Voice recognition sensitivity, range (0.0,1.0) (optional) *

- * Determines the level of sound in the audio signal considered as "voice activity". + * Determines the level of sound in the audio signal considered as "voice + * activity". *

- * Lower values make it easier for the agent to detect voice, while higher values may ignore faint sounds. + * Lower values make it easier for the agent to detect voice, while higher + * values may ignore faint sounds. */ @JsonProperty("threshold") private Float threshold; @@ -1800,7 +1835,8 @@ public VADPayload build() { } /** - * @brief Defines the Automatic Speech Recognition (ASR) configuration for agent to join RTC channel + * @brief Defines the Automatic Speech Recognition (ASR) configuration for agent + * to join RTC channel * @since v0.3.0 */ public static class ASRPayload { @@ -1855,7 +1891,6 @@ public static final class Builder { private Builder() { } - public Builder name(String val) { name = val; return this; diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/req/SpeakConvoAIReq.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/req/SpeakConvoAIReq.java new file mode 100644 index 0000000..8291ac1 --- /dev/null +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/req/SpeakConvoAIReq.java @@ -0,0 +1,100 @@ +package io.agora.rest.services.convoai.req; + +/** + * @brief Request Body parameters for calling the Conversational AI engine speak + * API + * @since v0.4.0 + */ +public class SpeakConvoAIReq { + + /** + * The text content to be spoken, with a maximum length of 512 bytes.(Required) + */ + private String text; + + /** + * The priority of the speech behavior, which supports the following values + * (Optional): + *

+ * - "INTERRUPT" (default): High priority, interrupt and speak. The agent will + * terminate the current interaction and speak the message directly. + *

+ * - "APPEND": Middle priority, append and speak. The agent will speak the + * message after the current interaction. + *

+ * - "IGNORE": Low priority, speak when idle. If the agent is currently + * interacting, it will directly ignore and discard the message to be spoken; + * only when the agent is not interacting will it speak the message. + */ + private String priority; + + /** + * Whether to allow the user to speak to interrupt the agent's speech + * (Optional): + *

+ * - true (default): Allow. + *

+ * - false: Disallow. + */ + private Boolean interrupt; + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String text; + private String priority; + private Boolean interrupt; + + public Builder text(String text) { + this.text = text; + return this; + } + + public Builder priority(String priority) { + this.priority = priority; + return this; + } + + public Builder interrupt(Boolean interrupt) { + this.interrupt = interrupt; + return this; + } + + public SpeakConvoAIReq build() { + return new SpeakConvoAIReq(this); + } + } + + private SpeakConvoAIReq(Builder builder) { + setText(builder.text); + setPriority(builder.priority); + setInterrupt(builder.interrupt); + } + + public void setText(String text) { + this.text = text; + } + + public void setPriority(String priority) { + this.priority = priority; + } + + public void setInterrupt(Boolean interrupt) { + this.interrupt = interrupt; + } + + public String getText() { + return text; + } + + public String getPriority() { + return priority; + } + + public Boolean getInterrupt() { + return interrupt; + } + +} diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/HistoryConvoAIRes.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/HistoryConvoAIRes.java new file mode 100644 index 0000000..ca17192 --- /dev/null +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/HistoryConvoAIRes.java @@ -0,0 +1,124 @@ +package io.agora.rest.services.convoai.res; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @brief Response returned by the Conversational AI engine getHistory API + * @since v0.4.0 + */ +public class HistoryConvoAIRes { + /** + * The agent creation timestamp + */ + @JsonProperty("start_ts") + private Long startTs; + + /** + * Unique identifier of the agent + */ + @JsonProperty("agent_id") + private String agentId; + + /** + * Only returns the running status of the agent + */ + @JsonProperty("status") + private String status; + + /** + * Agent short-term memory content + */ + @JsonProperty("contents") + private List contents; + + /** + * @brief Agent short-term memory content + * @since v0.4.0 + */ + public static class HistoryContent { + + /** + * The content of the message + */ + @JsonProperty("content") + private String content; + + /** + * The role of sending messages: + *

+ * - user: User. + *

+ * - assistant: Agent. + */ + @JsonProperty("role") + private String role; + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + @Override + public String toString() { + return "HistoryContent{" + + "content='" + content + '\'' + + ", role='" + role + '\'' + + '}'; + } + } + + public Long getStartTs() { + return startTs; + } + + public void setStartTs(Long startTs) { + this.startTs = startTs; + } + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public List getContents() { + return contents; + } + + public void setContents(List contents) { + this.contents = contents; + } + + @Override + public String toString() { + return "HistoryConvoAIRes{" + + "startTs=" + startTs + + ", agentId='" + agentId + '\'' + + ", status='" + status + '\'' + + ", contents=" + contents + + '}'; + } +} diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/InterruptConvoAIRes.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/InterruptConvoAIRes.java new file mode 100644 index 0000000..e838f69 --- /dev/null +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/InterruptConvoAIRes.java @@ -0,0 +1,60 @@ +package io.agora.rest.services.convoai.res; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @brief Response returned by the Conversational AI engine interrupt API + * @since v0.4.0 + */ +public class InterruptConvoAIRes { + /** + * Unique identifier of the agent + */ + @JsonProperty("agent_id") + private String agentId; + + /** + * The start timestamp of the agent + */ + @JsonProperty("start_ts") + private Integer startTs; + + /** + * The channel name + */ + @JsonProperty("channel") + private String channel; + + @Override + public String toString() { + return "InterruptConvoAIRes{" + + "agentId='" + agentId + '\'' + + ", startTs=" + startTs + + ", channel='" + channel + '\'' + + '}'; + } + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + public Integer getStartTs() { + return startTs; + } + + public void setStartTs(Integer startTs) { + this.startTs = startTs; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } +} diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/ListConvoAIRes.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/ListConvoAIRes.java index 91d9d81..15333fa 100644 --- a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/ListConvoAIRes.java +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/ListConvoAIRes.java @@ -49,7 +49,8 @@ public static class Data { private Integer count; /** - * List of intelligent agents that meet the conditions, for detailed information refer to {@link Agent} + * List of intelligent agents that meet the conditions, for detailed information + * refer to {@link Agent} */ @JsonProperty("list") private List list; @@ -61,6 +62,22 @@ public String toString() { ", list=" + list + '}'; } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } } /** @@ -110,6 +127,30 @@ public String toString() { ", status='" + status + '\'' + '}'; } + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + public Integer getStartTs() { + return startTs; + } + + public void setStartTs(Integer startTs) { + this.startTs = startTs; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } } /** @@ -136,5 +177,45 @@ public String toString() { ", cursor='" + cursor + '\'' + '}'; } + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public String getCursor() { + return cursor; + } + + public void setCursor(String cursor) { + this.cursor = cursor; + } + } + + public Data getData() { + return data; + } + + public void setData(Data data) { + this.data = data; + } + + public Meta getMeta() { + return meta; + } + + public void setMeta(Meta meta) { + this.meta = meta; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; } } diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/QueryConvoAIRes.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/QueryConvoAIRes.java index 935e4c7..1e2b972 100644 --- a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/QueryConvoAIRes.java +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/QueryConvoAIRes.java @@ -64,4 +64,44 @@ public String toString() { ", agentId='" + agentId + '\'' + '}'; } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Integer getStartTs() { + return startTs; + } + + public void setStartTs(Integer startTs) { + this.startTs = startTs; + } + + public Integer getStopTs() { + return stopTs; + } + + public void setStopTs(Integer stopTs) { + this.stopTs = stopTs; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } } diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/SpeakConvoAIRes.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/SpeakConvoAIRes.java new file mode 100644 index 0000000..c6ee02d --- /dev/null +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/SpeakConvoAIRes.java @@ -0,0 +1,61 @@ +package io.agora.rest.services.convoai.res; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @brief Response returned by the Conversational AI engine speak API + * @since v0.4.0 + */ +public class SpeakConvoAIRes { + /** + * Unique identifier of the agent + */ + @JsonProperty("agent_id") + private String agentId; + + /** + * The start timestamp of the agent + */ + @JsonProperty("start_ts") + private Integer startTs; + + /** + * The channel name + */ + @JsonProperty("channel") + private String channel; + + @Override + public String toString() { + return "SpeakConvoAIRes{" + + "agentId='" + agentId + '\'' + + ", startTs=" + startTs + + ", channel='" + channel + '\'' + + '}'; + } + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + public Integer getStartTs() { + return startTs; + } + + public void setStartTs(Integer startTs) { + this.startTs = startTs; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + +} diff --git a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/UpdateConvoAIRes.java b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/UpdateConvoAIRes.java index f54b723..b63312c 100644 --- a/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/UpdateConvoAIRes.java +++ b/agora-rest-client-core/src/main/java/io/agora/rest/services/convoai/res/UpdateConvoAIRes.java @@ -49,4 +49,28 @@ public String toString() { ", state='" + state + '\'' + '}'; } + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + public Integer getCreateTs() { + return createTs; + } + + public void setCreateTs(Integer createTs) { + this.createTs = createTs; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } } diff --git a/examples/convoai/src/main/java/io/agora/rest/examples/convoai/Main.java b/examples/convoai/src/main/java/io/agora/rest/examples/convoai/Main.java index c62f530..8f1795e 100644 --- a/examples/convoai/src/main/java/io/agora/rest/examples/convoai/Main.java +++ b/examples/convoai/src/main/java/io/agora/rest/examples/convoai/Main.java @@ -13,8 +13,7 @@ import java.util.concurrent.Callable; -@Command(name = "Main", mixinStandardHelpOptions = true, version = "0.1.0", - description = "Agora Conversational AI Service") +@Command(name = "Main", mixinStandardHelpOptions = true, version = "0.1.0", description = "Agora Conversational AI Service") public class Main implements Callable { private static final Logger logger = LoggerFactory.getLogger(Main.class); @@ -26,11 +25,10 @@ public class Main implements Callable { private final DomainArea domainArea = DomainArea.CN; - - @Option(names = {"-t", "--ttsVendor"}, description = "bytedance,microsoft,tencent,minimax,elevenlabs") + @Option(names = { "-t", "--ttsVendor" }, description = "bytedance,microsoft,tencent,minimax,elevenlabs") private String ttsVendor = ""; - @Option(names = {"-s", "--serviceRegion"}, description = "chineseMainland,global") + @Option(names = { "-s", "--serviceRegion" }, description = "chineseMainland,global") private String serviceRegion; public static void main(String[] args) { @@ -45,7 +43,6 @@ private void loadEnv() { password = System.getenv("BASIC_AUTH_PASSWORD"); } - @Override public Integer call() throws Exception { loadEnv(); @@ -53,33 +50,32 @@ public Integer call() throws Exception { logger.info("appId: {}, username: {}, password: {}, region: {}, ttsVendor: {}, serviceRegion: {}", appId, username, password, domainArea, ttsVendor, serviceRegion); - JoinConvoAIReq.TTSVendorEnum ttsVendorEnum= JoinConvoAIReq.TTSVendorEnum.getEnum(ttsVendor); + JoinConvoAIReq.TTSVendorEnum ttsVendorEnum = JoinConvoAIReq.TTSVendorEnum.getEnum(ttsVendor); - if (ttsVendorEnum==null) { + if (ttsVendorEnum == null) { throw new IllegalArgumentException("ttsVendor is required"); } - if (serviceRegion==null) { + if (serviceRegion == null) { throw new IllegalArgumentException("serviceRegion is required"); } ConvoAIServiceRegionEnum convoAIServiceRegionEnum; - if(serviceRegion.equals("chineseMainland")){ + if (serviceRegion.equals("chineseMainland")) { convoAIServiceRegionEnum = ConvoAIServiceRegionEnum.CHINESE_MAINLAND; - } - else if(serviceRegion.equals("global")){ + } else if (serviceRegion.equals("global")) { convoAIServiceRegionEnum = ConvoAIServiceRegionEnum.GLOBAL; - } - else{ + } else { throw new IllegalArgumentException("Invalid serviceRegion: " + serviceRegion); } - Service svc =new Service(domainArea, appId, username, password, new BasicAuthCredential(username, password), convoAIServiceRegionEnum); + Service svc = new Service(domainArea, appId, username, password, new BasicAuthCredential(username, password), + convoAIServiceRegionEnum); switch (ttsVendorEnum) { case BYTEDANCE: - if(convoAIServiceRegionEnum!=ConvoAIServiceRegionEnum.CHINESE_MAINLAND){ + if (convoAIServiceRegionEnum != ConvoAIServiceRegionEnum.CHINESE_MAINLAND) { throw new IllegalArgumentException("Bytedance TTS is only available in ChineseMainland"); } diff --git a/examples/convoai/src/main/java/io/agora/rest/examples/convoai/service/Service.java b/examples/convoai/src/main/java/io/agora/rest/examples/convoai/service/Service.java index 5f835ba..8bc6def 100644 --- a/examples/convoai/src/main/java/io/agora/rest/examples/convoai/service/Service.java +++ b/examples/convoai/src/main/java/io/agora/rest/examples/convoai/service/Service.java @@ -6,11 +6,9 @@ import io.agora.rest.services.convoai.ConvoAIServiceRegionEnum; import io.agora.rest.services.convoai.req.JoinConvoAIReq; import io.agora.rest.services.convoai.req.ListConvoAIReq; +import io.agora.rest.services.convoai.req.SpeakConvoAIReq; import io.agora.rest.services.convoai.req.UpdateConvoAIReq; -import io.agora.rest.services.convoai.res.JoinConvoAIRes; -import io.agora.rest.services.convoai.res.ListConvoAIRes; -import io.agora.rest.services.convoai.res.QueryConvoAIRes; -import io.agora.rest.services.convoai.res.UpdateConvoAIRes; +import io.agora.rest.services.convoai.res.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -165,6 +163,73 @@ public void runCustomTTS(JoinConvoAIReq.TTSVendorEnum ttsVendor, JoinConvoAIReq. } } + InterruptConvoAIRes interruptConvoAIRes; + + try { + interruptConvoAIRes = this.convoAIClient.interrupt(agentId).block(); + } catch (AgoraException e) { + logger.error("Failed to interrupt the agent,err:{}", e.getMessage()); + return; + } catch (Exception e) { + logger.error("Unknown exception,err:{}", e.getMessage()); + return; + } + + if (interruptConvoAIRes == null) { + logger.error("Failed to interrupt the agent"); + return; + } + + logger.info("Interrupt the agent successfully, interruptConvoAIRes:{}", interruptConvoAIRes); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + HistoryConvoAIRes historyConvoAIRes; + + try { + historyConvoAIRes = this.convoAIClient.getHistory(agentId).block(); + } catch (AgoraException e) { + logger.error("Failed to get the history of the agent,err:{}", e.getMessage()); + return; + } catch (Exception e) { + logger.error("Unknown exception,err:{}", e.getMessage()); + return; + } + + if (historyConvoAIRes == null) { + logger.error("Failed to get the history of the agent"); + return; + } + + logger.info("Get the history of the agent successfully, historyConvoAIRes:{}", historyConvoAIRes); + + SpeakConvoAIRes speakConvoAIRes; + + try { + speakConvoAIRes = this.convoAIClient.speak(agentId, SpeakConvoAIReq.builder() + .text("Hello,how can I help you?") + .interrupt(true) + .priority("INTERRUPT") + .build()).block(); + } catch (AgoraException e) { + logger.error("Failed to speak the agent,err:{}", e.getMessage()); + return; + } catch (Exception e) { + logger.error("Unknown exception,err:{}", e.getMessage()); + return; + } + + if (speakConvoAIRes == null) { + logger.error("Failed to speak the agent"); + return; + } + + logger.info("Speak the agent successfully, speakConvoAIRes:{}", speakConvoAIRes); + ListConvoAIRes listConvoAIRes; try { listConvoAIRes = this.convoAIClient.list(ListConvoAIReq.builder()