Various Telnyx activity enhancements
This commit is contained in:
parent
c7b0b2d497
commit
3eaefab72f
135
src/activities/Elsa.Activities.Telnyx/Activities/SpeakAndWait.cs
Normal file
135
src/activities/Elsa.Activities.Telnyx/Activities/SpeakAndWait.cs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
using Elsa.Activities.ControlFlow;
|
||||
using Elsa.Activities.Telnyx.Webhooks.Payloads.Call;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Builders;
|
||||
using Elsa.Design;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Services;
|
||||
|
||||
namespace Elsa.Activities.Telnyx.Activities
|
||||
{
|
||||
[Action(
|
||||
Category = Constants.Category,
|
||||
Description = "Convert text to speech and play it back on the call. When done speaking, control is returned to the workflow.",
|
||||
Outcomes = new[] {OutcomeNames.Done, TelnyxOutcomeNames.CallIsNoLongerActive},
|
||||
DisplayName = "Speak Text And Wait"
|
||||
)]
|
||||
public class SpeakAndWait : CompositeActivity
|
||||
{
|
||||
[ActivityInput(
|
||||
Label = "Call Control ID",
|
||||
Hint = "Unique identifier and token for controlling the call",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? CallControlId
|
||||
{
|
||||
get => GetState<string>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "The language you want spoken.",
|
||||
UIHint = ActivityInputUIHints.Dropdown,
|
||||
Options = new[] {"en-US", "en-AU", "nl-NL", "es-ES", "ru-RU"},
|
||||
DefaultValue = "en-US",
|
||||
SupportedSyntaxes = new[] {SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string Language
|
||||
{
|
||||
get => GetState<string>(() => "en-US");
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "The gender of the voice used to speak back the text.",
|
||||
UIHint = ActivityInputUIHints.Dropdown,
|
||||
Options = new[] {"female", "male"},
|
||||
DefaultValue = "female",
|
||||
SupportedSyntaxes = new[] {SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string Voice
|
||||
{
|
||||
get => GetState<string>(() => "female");
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityInput(Hint = "The text or SSML to be converted into speech. There is a 5,000 character limit.", SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public string Payload
|
||||
{
|
||||
get => GetState<string>()!;
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "The type of the provided payload. The payload can either be plain text, or Speech Synthesis Markup Language (SSML).",
|
||||
UIHint = ActivityInputUIHints.Dropdown,
|
||||
Options = new[] {"", "text", "ssml"},
|
||||
SupportedSyntaxes = new[] {SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? PayloadType
|
||||
{
|
||||
get => GetState<string>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "This parameter impacts speech quality, language options and payload types. When using `basic`, only the `en-US` language and payload type `text` are allowed.",
|
||||
UIHint = ActivityInputUIHints.Dropdown,
|
||||
Options = new[] {"", "basic", "premium"},
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] {SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? ServiceLevel
|
||||
{
|
||||
get => GetState<string>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "Use this field to add state to every subsequent webhook. It must be a valid Base-64 encoded string.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? ClientState
|
||||
{
|
||||
get => GetState<string>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityInput(
|
||||
Label = "Command ID",
|
||||
Hint = "Use this field to avoid duplicate commands. Telnyx will ignore commands with the same Command ID.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? CommandId
|
||||
{
|
||||
get => GetState<string>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
public override void Build(ICompositeActivityBuilder builder)
|
||||
{
|
||||
builder
|
||||
.StartWith<SpeakText>(speakText => speakText
|
||||
.WithLanguage(() => Language)
|
||||
.WithPayload(() => Payload)
|
||||
.WithPayloadType(() => PayloadType)
|
||||
.WithVoice(() => Voice)
|
||||
.WithClientState(() => ClientState)
|
||||
.WithCommandId(() => CommandId)
|
||||
.WithServiceLevel(() => ServiceLevel)
|
||||
.WithCallControlId(() => CallControlId)
|
||||
, speakText =>
|
||||
{
|
||||
speakText
|
||||
.When(OutcomeNames.Done)
|
||||
.ThenTypeNamed(nameof(CallSpeakEnded))
|
||||
.Finish(OutcomeNames.Done);
|
||||
|
||||
speakText.When(TelnyxOutcomeNames.CallIsNoLongerActive).Finish(TelnyxOutcomeNames.CallIsNoLongerActive);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Activities.Telnyx.Client.Models;
|
||||
using Elsa.Activities.Telnyx.Client.Services;
|
||||
using Elsa.Activities.Telnyx.Extensions;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Builders;
|
||||
using Elsa.Design;
|
||||
using Elsa.Exceptions;
|
||||
using Elsa.Expressions;
|
||||
|
|
@ -36,17 +38,19 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
Hint = "The language you want spoken.",
|
||||
UIHint = ActivityInputUIHints.Dropdown,
|
||||
Options = new[] { "en-US", "en-AU", "nl-NL", "es-ES", "ru-RU" },
|
||||
DefaultValue = "en-US",
|
||||
SupportedSyntaxes = new[] { SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
)]
|
||||
public string Language { get; set; } = default!;
|
||||
public string Language { get; set; } = "en-US";
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "The gender of the voice used to speak back the text.",
|
||||
UIHint = ActivityInputUIHints.Dropdown,
|
||||
Options = new[] { "female", "male" },
|
||||
DefaultValue = "female",
|
||||
SupportedSyntaxes = new[] { SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
)]
|
||||
public string Voice { get; set; } = default!;
|
||||
public string Voice { get; set; } = "female";
|
||||
|
||||
[ActivityInput(Hint = "The text or SSML to be converted into speech. There is a 5,000 character limit.", SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public string Payload { get; set; } = default!;
|
||||
|
|
@ -114,4 +118,55 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
|
||||
private static string? EmptyToNull(string? value) => value is "" ? null : value;
|
||||
}
|
||||
|
||||
public static class SpeakTextExtensions
|
||||
{
|
||||
public static ISetupActivity<SpeakText> WithCallControlId(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, ValueTask<string?>> value) => setup.Set(x => x.CallControlId, value);
|
||||
public static ISetupActivity<SpeakText> WithCallControlId(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, string?> value) => setup.Set(x => x.CallControlId, value);
|
||||
public static ISetupActivity<SpeakText> WithCallControlId(this ISetupActivity<SpeakText> setup, Func<ValueTask<string?>> value) => setup.Set(x => x.CallControlId, value);
|
||||
public static ISetupActivity<SpeakText> WithCallControlId(this ISetupActivity<SpeakText> setup, Func<string?> value) => setup.Set(x => x.CallControlId, value);
|
||||
public static ISetupActivity<SpeakText> WithCallControlId(this ISetupActivity<SpeakText> setup, string? value) => setup.Set(x => x.CallControlId, value);
|
||||
|
||||
public static ISetupActivity<SpeakText> WithLanguage(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, ValueTask<string>> value) => setup.Set(x => x.Language, value!);
|
||||
public static ISetupActivity<SpeakText> WithLanguage(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, string> value) => setup.Set(x => x.Language, value);
|
||||
public static ISetupActivity<SpeakText> WithLanguage(this ISetupActivity<SpeakText> setup, Func<ValueTask<string>> value) => setup.Set(x => x.Language, value!);
|
||||
public static ISetupActivity<SpeakText> WithLanguage(this ISetupActivity<SpeakText> setup, Func<string> value) => setup.Set(x => x.Language, value);
|
||||
public static ISetupActivity<SpeakText> WithLanguage(this ISetupActivity<SpeakText> setup, string value) => setup.Set(x => x.Language, value);
|
||||
|
||||
public static ISetupActivity<SpeakText> WithVoice(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, ValueTask<string>> value) => setup.Set(x => x.Voice, value!);
|
||||
public static ISetupActivity<SpeakText> WithVoice(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, string> value) => setup.Set(x => x.Voice, value);
|
||||
public static ISetupActivity<SpeakText> WithVoice(this ISetupActivity<SpeakText> setup, Func<ValueTask<string>> value) => setup.Set(x => x.Voice, value!);
|
||||
public static ISetupActivity<SpeakText> WithVoice(this ISetupActivity<SpeakText> setup, Func<string> value) => setup.Set(x => x.Voice, value);
|
||||
public static ISetupActivity<SpeakText> WithVoice(this ISetupActivity<SpeakText> setup, string value) => setup.Set(x => x.Voice, value);
|
||||
|
||||
public static ISetupActivity<SpeakText> WithPayload(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, ValueTask<string>> value) => setup.Set(x => x.Payload, value!);
|
||||
public static ISetupActivity<SpeakText> WithPayload(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, string> value) => setup.Set(x => x.Payload, value);
|
||||
public static ISetupActivity<SpeakText> WithPayload(this ISetupActivity<SpeakText> setup, Func<ValueTask<string>> value) => setup.Set(x => x.Payload, value!);
|
||||
public static ISetupActivity<SpeakText> WithPayload(this ISetupActivity<SpeakText> setup, Func<string> value) => setup.Set(x => x.Payload, value);
|
||||
public static ISetupActivity<SpeakText> WithPayload(this ISetupActivity<SpeakText> setup, string value) => setup.Set(x => x.Payload, value);
|
||||
|
||||
public static ISetupActivity<SpeakText> WithPayloadType(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, ValueTask<string?>> value) => setup.Set(x => x.PayloadType, value);
|
||||
public static ISetupActivity<SpeakText> WithPayloadType(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, string?> value) => setup.Set(x => x.PayloadType, value);
|
||||
public static ISetupActivity<SpeakText> WithPayloadType(this ISetupActivity<SpeakText> setup, Func<ValueTask<string?>> value) => setup.Set(x => x.PayloadType, value);
|
||||
public static ISetupActivity<SpeakText> WithPayloadType(this ISetupActivity<SpeakText> setup, Func<string?> value) => setup.Set(x => x.PayloadType, value);
|
||||
public static ISetupActivity<SpeakText> WithPayloadType(this ISetupActivity<SpeakText> setup, string? value) => setup.Set(x => x.PayloadType, value);
|
||||
|
||||
public static ISetupActivity<SpeakText> WithServiceLevel(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, ValueTask<string?>> value) => setup.Set(x => x.ServiceLevel, value);
|
||||
public static ISetupActivity<SpeakText> WithServiceLevel(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, string?> value) => setup.Set(x => x.ServiceLevel, value);
|
||||
public static ISetupActivity<SpeakText> WithServiceLevel(this ISetupActivity<SpeakText> setup, Func<ValueTask<string?>> value) => setup.Set(x => x.ServiceLevel, value);
|
||||
public static ISetupActivity<SpeakText> WithServiceLevel(this ISetupActivity<SpeakText> setup, Func<string?> value) => setup.Set(x => x.ServiceLevel, value);
|
||||
public static ISetupActivity<SpeakText> WithServiceLevel(this ISetupActivity<SpeakText> setup, string? value) => setup.Set(x => x.ServiceLevel, value);
|
||||
|
||||
public static ISetupActivity<SpeakText> WithClientState(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, ValueTask<string?>> value) => setup.Set(x => x.ClientState, value);
|
||||
public static ISetupActivity<SpeakText> WithClientState(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, string?> value) => setup.Set(x => x.ClientState, value);
|
||||
public static ISetupActivity<SpeakText> WithClientState(this ISetupActivity<SpeakText> setup, Func<ValueTask<string?>> value) => setup.Set(x => x.ClientState, value);
|
||||
public static ISetupActivity<SpeakText> WithClientState(this ISetupActivity<SpeakText> setup, Func<string?> value) => setup.Set(x => x.ClientState, value);
|
||||
public static ISetupActivity<SpeakText> WithClientState(this ISetupActivity<SpeakText> setup, string? value) => setup.Set(x => x.ClientState, value);
|
||||
|
||||
public static ISetupActivity<SpeakText> WithCommandId(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, ValueTask<string?>> value) => setup.Set(x => x.CommandId, value);
|
||||
public static ISetupActivity<SpeakText> WithCommandId(this ISetupActivity<SpeakText> setup, Func<ActivityExecutionContext, string?> value) => setup.Set(x => x.CommandId, value);
|
||||
public static ISetupActivity<SpeakText> WithCommandId(this ISetupActivity<SpeakText> setup, Func<ValueTask<string?>> value) => setup.Set(x => x.CommandId, value);
|
||||
public static ISetupActivity<SpeakText> WithCommandId(this ISetupActivity<SpeakText> setup, Func<string?> value) => setup.Set(x => x.CommandId, value);
|
||||
public static ISetupActivity<SpeakText> WithCommandId(this ISetupActivity<SpeakText> setup, string? value) => setup.Set(x => x.CommandId, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
using System.Threading.Tasks;
|
||||
using Elsa.Activities.Telnyx.Client.Models;
|
||||
using Elsa.Activities.Telnyx.Client.Services;
|
||||
using Elsa.Activities.Telnyx.Extensions;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Design;
|
||||
using Elsa.Exceptions;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Activities.Telnyx.Activities
|
||||
{
|
||||
[Action(
|
||||
Category = Constants.Category,
|
||||
Description = "Stop recording the call.",
|
||||
Outcomes = new[] { OutcomeNames.Done, TelnyxOutcomeNames.CallIsNoLongerActive },
|
||||
DisplayName = "Stop Recording"
|
||||
)]
|
||||
public class StopRecording : Activity
|
||||
{
|
||||
private readonly ITelnyxClient _telnyxClient;
|
||||
public StopRecording(ITelnyxClient telnyxClient) => _telnyxClient = telnyxClient;
|
||||
|
||||
[ActivityInput(
|
||||
Label = "Call Control ID",
|
||||
Hint = "Unique identifier and token for controlling the call",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
)]
|
||||
public string? CallControlId { get; set; } = default!;
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "Use this field to add state to every subsequent webhook. It must be a valid Base-64 encoded string.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
)]
|
||||
public string? ClientState { get; set; }
|
||||
|
||||
[ActivityInput(
|
||||
Label = "Command ID",
|
||||
Hint = "Use this field to avoid duplicate commands. Telnyx will ignore commands with the same Command ID.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
)]
|
||||
public string? CommandId { get; set; }
|
||||
|
||||
protected override async ValueTask<IActivityExecutionResult> OnExecuteAsync(ActivityExecutionContext context)
|
||||
{
|
||||
var request = new StopRecordingRequest(
|
||||
EmptyToNull(ClientState),
|
||||
EmptyToNull(CommandId)
|
||||
);
|
||||
|
||||
var callControlId = context.GetCallControlId(CallControlId);
|
||||
|
||||
try
|
||||
{
|
||||
await _telnyxClient.Calls.StopRecordingAsync(callControlId, request, context.CancellationToken);
|
||||
return Done();
|
||||
}
|
||||
catch (ApiException e)
|
||||
{
|
||||
if (await e.CallIsNoLongerActiveAsync())
|
||||
return Outcome(TelnyxOutcomeNames.CallIsNoLongerActive);
|
||||
|
||||
throw new WorkflowException(e.Content ?? e.Message, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static string? EmptyToNull(string? value) => value is "" ? null : value;
|
||||
}
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
|
||||
Model = webhookModel;
|
||||
Payload = webhookModel.Data.Payload;
|
||||
return Done();
|
||||
return Done(webhookModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -81,7 +81,12 @@ namespace Elsa.Activities.Telnyx.Client.Models
|
|||
string? CommandId,
|
||||
bool? PlayBeep
|
||||
);
|
||||
|
||||
|
||||
public record StopRecordingRequest(
|
||||
string? ClientState,
|
||||
string? CommandId
|
||||
);
|
||||
|
||||
public record SpeakTextRequest(
|
||||
string Language,
|
||||
string Voice,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ namespace Elsa.Activities.Telnyx.Client.Services
|
|||
[Post("/v2/calls/{callControlId}/actions/record_start")]
|
||||
Task StartRecordingAsync(string callControlId, [Body]StartRecordingRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
[Post("/v2/calls/{callControlId}/actions/record_stop")]
|
||||
Task StopRecordingAsync(string callControlId, [Body]StopRecordingRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
[Post("/v2/calls/{callControlId}/actions/speak")]
|
||||
Task SpeakTextAsync(string callControlId, [Body]SpeakTextRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue