I am trying to do something that I don't think is a common scenario using Google's DialogFlow api. I am writing an IVR that services inmates in prison.
Dialogueflow appears to assume that the mic is always on when receiving an incoming call. But when a call comes from a person housed in prison, they are using one of the prison system call systems which 'speaks' a pre-recorded message asking the receiver to press an 'accept,' 'reject,' or 'block,' digit before the mic on the caller's phone will be enabled and speech from the caller can occur.
I have set up the parameters for the 'Default Welcome Intent' with a few examples of these pre-recorded messages that are consistent with what the prison phone system will play for the receiver. It looks something like this:
"Hello, you have received a free call from Bob Jones, an inmate at Massachusetts Department of Corrections. You will not be charged for this free call. To accept this free call, press 1. To reject this free call, press 2. To permanently block this number from any future calls, press 3."
What I want the Default Welcome Intent to do is listen to this message, capture the accept digit to press and then 'press' it so that the caller's mic is enabled and then a true dialogue can be presented (main menu for the IVR, response capture etc).
I think that I would deliver back this dtmf tone through a 'custom payload' but the scenario for playing a tone doesn't seem to be an expected/available response.
The payload defines the result to be delivered as a json string and doesn't very much like what I'm defining.
{ "dtmf": {$param.accept-digit}} (syntax error message when this json is defined as the payload)
Does anyone familiar with Dialogueflow know how I might do this?
I'm not sure if this is possible with Dialogflow, but you can write a simple app for that using Dasha.
Sample DSL (DashaScript) code:
start node root {
do {
#connectSafe($phone); //accept incoming call
}
transitions {
accept: goto accept on #messageHasIntent(["press_one_to_accept"]); //listen to the message and use conversational AI to understand that it says "To accept this free call, press 1"
}
}
node accept {
do {
#sendDTMF("1"); //make selection by sending DTMF code
}
}
Then you can design the rest of your conversation flow also using Dasha.
If you need any help, feel free to join our dev community or drop me a line at vlad#dasha.ai.
Related
I am using libwidevinecdm.so from chrome to handle DRM protected data. I am currently successfully setting the widevine server certificate I get from the license server. I can also create a session with the pssh box of the media im trying to decode. So far everything is successful (all promises resolve fine).
(session is created like this: _cdm->CreateSessionAndGenerateRequest(promise_id, cdm::SessionType::kTemporary, cdm::InitDataType::kCenc, pssh_box.data(), static_cast<uint32_t>(pssh_box.size()));)
I am then getting a session message of type kLicenseRequest which I am forwarding to the respective license server. The license server responds with a valid response and the same amount of data as I can see in the browser when using Chrome. I am then passing this to my session like this:
_cdm->UpdateSession(promise_id, session_id.data(), static_cast<uint32_t>(session_id.size()),
license_response.data(), static_cast<uint32_t>(license_response.size()));
The problem now is that this promise never resolves. It keeps posting the kLicenseRequest message over and over again to my session without ever returning. Does this mean my response is wrong? Or is this something else?
Br
Yanick
The issue is caused by the fact, that everything in CreateSessionAndGenerateRequest is done synchronous - that means by the time CreateSessionAndGenerateRequest returns your promise will always be resolved.
The CDM will emit the kLicenseRequest inside CreateSessionAndGenerateRequest and it doesn't do so in a "fire & forget" fashion, but the function waits there until you have returned from the cdm::Host_10::OnSessionMessage. Since my implementation of OnSessionMessage was creating a synchronous HTTP Request to the license server before - also synchronously - calling the UpdateSession the entire chain ended up to be blocking.
So ultimately I was calling UpdateSession while still being inside CreateSessionAndGenerateRequest and I assume the CDM cannot handle this and reacts by creating a new session with the given ID and generating a request again, which of course triggered another UpdateSession and so on.
Ultimately the simplest way to break the cycle was to make something asynchronous. I decided to launch a separate thread when receiving kLicenseRequest, wait for a few milliseconds to make sure that CreateSessionAndGenerateRequest has time to finish (not sure if that is really required) and then issue the request to the license server.
The only change I had to do was adding the surrounding std::thread:
void WidevineSession::forward_license_request(const std::vector<uint8_t> &data) {
std::thread{
[=]() {
std::this_thread::sleep_for(std::chrono::milliseconds{100});
net::HttpRequest request{"POST", _license_server_url};
request.add_header("Authorization", fmt::format("Bearer {}", _access_token))
.byte_body(data);
const auto response = _client.execute(request);
if (response.status_code() != 200) {
log->error("Widevine license request not accepted by license server: {} {} ({})", response.status_code(), response.status_text(), utils::bytes_to_utf8(response.body()));
throw std::runtime_error{"Error requesting widevine license"};
}
log->info("Successfully requested widevine license from license server");
_adapter->update_session(this, _session_id, response.body());
}
}.detach();
}
Short summary of what I tried to do and what it's actually doing.
In my project I have two simple nodes: one for listening and publishing, and another for speaking and subscribing. I named them listeningNode and speakingNode, respectively.
The task I wanted to achieve was pretty simple, I would have the user say "remember me" which would be recognized as a keyword and be published to voiceCommandCallback method in the speaking node so my robot could say "Okay, please say your name". Then, back at the listening node, on top of publishing that keyphrase it will also call the method recognize_from_mic_with_dict() which as you can guess will run using a dictionary of names.
This recognize_from_mic_with_dict() method will be listening for a name and will attempt to publish that name to namesCallback() in the listening node and this is where I check if what got published was an actual name or if it was just gibberish, in which case I would kindly ask the user to repeat his/her name and subscribe once again to recognize_from_mic_with_dict() so it could listen once more.
This sounds more complicated that it probably has to be but it's the only way I could think of achieving this "mode switching". The problem is that if it hears gibberish it will say "I'm sorry, I did not quite hear that. Please repeat that!" and I would like to know if there is a way to make the listening node ignore anything that the robot says because it's attempting to recognize names from its own sentence.
you can cast it as a feedback control problem.
given that :
u is the user speech signal
r is the output signal of the robot speaker,
h the feedback path function,
s=h*r the feedback signal; * refers to convolution
y = s + u = h*r + u the input signal of the microphone
the problem is to estimate ĥ and therefore ŝ (r is already known),
so an estimation of the user speech signal is given by û = y - ŝ = y - ĥ * r
I'm working on a project in C++ to backup and restore email on Microsoft Exchange servers, I'm trying to write automated tests for the restore function. Right now I can create test users, databases, and mailboxes, and can send email between users through the Exchange Admin Powershell. However, Exchange doesn't have commandlets to view or delete emails (as far as I can tell). Is there a way to do that with straight Exchange commandlets?
I haven't found a way, so instead I'm looking for an IMAP API that I can add to the project to enable viewing and deleting emails. Free would be ideal, but it can't be licensed with GPL. Is there an IMAP API for C++ that doesn't have GPL? Is there an avenue to programatically view and delete emails I haven't tried yet?
EDIT: Honestly I'm not too fussy on how it gets done, I just need a way to do it. I'm open to any suggestions.
https://technet.microsoft.com/en-us/library/ff459253(v=exchg.150).aspx
Search-Mailbox can delete messages.
https://technet.microsoft.com/en-us/library/ee633455(v=exchg.150).aspx
ExportMailboxRequest and ImportMailboxRequest cmdlets do most of the heavy lifting for importing and exporting data.
Why do you need to read messages? Powershell can also do client side scripts using Outlook library commands.
EDIT
Put a 'magic phrase' in your test email. "MagicRainbowUnicorn".
Delete a message
Search-Mailbox -Identity "TestMailbox" -SearchQuery 'MagicRainbowUnicorn' -DeleteContent
Test for message
Switch ((Search-Mailbox -Identity "TestMailbox" -SearchQuery 'MagicRainbowUnicorn').count) {
0 { "No Results Found" }
1 { "One Result" }
default { "More than One, or some other strange Result" }
}
I don't have enough reputation to comment, but could you consume Exchange Web Services with C++? I wrote a few programs in C# that use EWS for monitoring mailboxes. I had the ability to view and delete messages from Exchange.
[Edit]
This is a sample of what I used in C#, if you decide to use that instead of C++. Or maybe it'll help steer you in a good direction.
using Microsoft.Exchange.WebServices.Data;
ExchangeService svc = new ExchangeService(ExchangeVersion.Exchange2010);
svc.Credentials = new WebCredentials("user#domain.com", "password");
svc.AutodiscoverUrl("user#domain.com");
// loop through messages in Inbox
foreach (EmailMessage msg in svc.FindItems(WellKnownFolderName.Inbox, new ItemView(int.MaxValue)))
{
// do stuff with message
}
i'm studying this source base. Basically this is an Anim server client for Symbian 3rd edition for the purpose of grabbing input events without consuming them in a reliable way.
If you spot this line of the server, here it is basically setting the RProperty value (apparently to an increasing counter); it seems no actual processing of the input is done.
inside this client line, the client is supposed to be receiving the notification data, but it only calls Attach.
my understanding is that Attach is only required to be called once, but is not clear in the client what event is triggered every time the server sets the RProperty
How (and where) is the client supposed to access the RProperty value?
After Attaching the client will somewhere Subscribe to the property where it passes a TRequestStatus reference. The server will signal the request status property via the kernel when the asynchronous event has happened (in your case the property was changed). If your example source code is implemented in the right way, you will find an active object (AO; CActive derived class) hanging around and the iStatus of this AO will be passed to the RProperty API. In this case the RunL function of the AO will be called when the property has been changed.
It is essential in Symbian to understand the active object framework and quite few people do it actually. Unfortunately I did not find a really good description online (they are explained quite well in Symbian OS Internals book) but this page at least gives you a quick example.
Example
In the ConstructL of your CMyActive subclass of CActive:
CKeyEventsClient* iClient;
RProperty iProperty;
// ...
void CMyActive::ConstructL()
{
RProcess myProcess;
TSecureId propertyCategory = myProcess.SecureId();
// avoid interference with other properties by defining the category
// as a secure ID of your process (perhaps it's the only allowed value)
TUint propertyKey = 1; // whatever you want
iClient = CKeyEventsClient::NewL(propertyCategory, propertyKey, ...);
iClient->OpenNotificationPropertyL(&iProperty);
// ...
CActiveScheduler::Add(this);
iProperty.Subscribe(iStatus);
SetActive();
}
Your RunL will be called when the property has been changed:
void CMyActive::RunL()
{
if (iStatus.Int() != KErrCancel) User::LeaveIfError(iStatus.Int());
// forward the error to RunError
// "To ensure that the subscriber does not miss updates, it should
// re-issue a subscription request before retrieving the current value
// and acting on it." (from docs)
iProperty.Subscribe(iStatus);
TInt value; // this type is passed to RProperty::Define() in the client
TInt err = iProperty.Get(value);
if (err != KErrNotFound) User::LeaveIfError(err);
SetActive();
}
I have been using this code to display IMAP4 messages:
void DisplayMessageL( const TMsvId &aId )
{
// 1. construct the client MTM
TMsvEntry indexEntry;
TMsvId serviceId;
User::LeaveIfError( iMsvSession->GetEntry(aId, serviceId, indexEntry));
CBaseMtm* mtm = iClientReg->NewMtmL(indexEntry.iMtm);
CleanupStack::PushL(mtm);
// 2. construct the user interface MTM
CBaseMtmUi* uiMtm = iUiReg->NewMtmUiL(*mtm);
CleanupStack::PushL(uiMtm);
// 3. display the message
uiMtm->BaseMtm().SwitchCurrentEntryL(indexEntry.Id());
CMsvOperationWait* waiter=CMsvOperationWait::NewLC();
waiter->Start(); //we use synchronous waiter
CMsvOperation* op = uiMtm->OpenL(waiter->iStatus);
CleanupStack::PushL(op);
CActiveScheduler::Start();
// 4. cleanup for example even members
CleanupStack::PopAndDestroy(4); // op,waiter, mtm, uimtm
}
However, in case when user attempts to download a remote message (i.e. one of the emails previously not retrieved from the mail server), and then cancels the request, my code remains blocked, and it never receives information that the action was canceled.
My question is:
what is the workaround for the above, so the application is not stuck?
can anyone provide a working example for asynchronous call for opening remote messages which do not panic and crash the application?
Asynchronous calls for POP3, SMTP and local IMAP4 messages work perfectly, but remote IMAP4 messages create this issue.
I am testing these examples for S60 5th edition.
Thank you all in advance.
First of all, I would retry removing CMsvOperationWait and deal with the open request asynchronously - i.e. have an active object waiting for the CMsvOperation to complete.
CMsvOperationWait is nothing more than a convenience to make an asynch operation appear synchronous and my suspicion is that this is culprit - in the case of download->show message, there are two asynch operations chained.