Azure notification hub Registration push variables - azure-notificationhub

I am currently using Azure notification hub(FCM) to send one-one notification to user as well as notification to group of users by using tags(5000 - 10000 users at a time) .
Now while sending notification to group , I want some personalization like:
Hi ABC<$(firstname of user1)>, here is new AAAAA for you today.
Hi XYZ<$(firstname of user2)>, here is new AAAAA for you today.
.
.
Hi ZZZ<$(firstname of user5000)>, here is new AAAAA for you today.
I read that this is possible by using push variables with native registartion /installation sdk.
Ref:https://azure.microsoft.com/en-in/blog/updates-from-notification-hubs-independent-nuget-installation-model-pmt-and-more/
But I could not find any option in registration/installation Java SDK to set these values .
Registration registration = new FcmRegistration(id, token);
registration.getTags().add(tagname);
hub.createRegistration(registration);
Installation installation = new Installation(name);
installation.setPushChannel(token);
installation.setPlatform(NotificationPlatform.Gcm);
installation.addTag(tagname);
hub.createOrUpdateInstallation(installation);
Any help is really appreciated , otherwise for group notification I have to send notification for each user via iteration and that defeats benefit of using tags and getting the job done in just 1 hub API call.

You are correct - this is exactly what ANH templates are for. You can read this blog post about them for some background knowledge. Essentially, once you've created a template you can do a template send operation that provides just the values that need to be injected. i.e. Your Installation record will have set the appropriate body:
"Hi $(firstname), here is new $(subject) for you today."
and your send operation provides the values to inject:
{
"firstname": "ABC",
"subject": "AAAAA"
}
Also, make sure to specify the correct tags to scope the audience, in this case something like "ABC" to specify the user, and "new-daily" to specify which templates should be used.
Another trick, you can skip a layer of tag management and send fewer requests by embedding the $(firstname) in the template itself.
"Hi ABC, here is new $(subject) for you today."
Because templates are stored per device, each device can have a separate name embedded in it, reducing the number of tags you need to tinker with. This would make the body you send just:
{
"subject": "AAAAA"
}
and you only need to scope with the tag "new-daily".

Looks like you're on the right track with templating. When you embed an expression into surrounding text, you're effectively doing concatenation, which requires the expression to be surrounded in { }. See documentation about template expression language using Azure Notification Hubs where it states "when using concatenation, expressions must be wrapped in curly brackets."
In your case, I think you want something along the lines of:
...
{"title":"{'Seattle Kraken vs. ' + $(opponent) + ' starting soon'}",...}
...

Thanks a lot I got it working by extending the API classes on my own in following manner as per the blog suggested.
package com.springbootazure.controller;
import java.util.Map;
import org.apache.commons.collections.map.HashedMap;
import com.google.gson.GsonBuilder;
import com.windowsazure.messaging.FcmRegistration;
public class PushRegistration extends FcmRegistration {
private static final String FCM_NATIVE_REGISTRATION1 = "<?xml version=\"1.0\" encoding=\"utf-8\"?><entry xmlns=\"http://www.w3.org/2005/Atom\"><content type=\"application/xml\"><GcmRegistrationDescription xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.microsoft.com/netservices/2010/10/servicebus/connect\">";
private static final String FCM_NATIVE_REGISTRATION2 = "<GcmRegistrationId>";
private static final String FCM_NATIVE_REGISTRATION3 = "</GcmRegistrationId></GcmRegistrationDescription></content></entry>";
private Map<String, String> pushVariables = new HashedMap();
public PushRegistration() {
super();
}
public PushRegistration(String registrationId,
String fcmRegistrationId, Map<String, String> pushVariables) {
super(registrationId, fcmRegistrationId);
this.pushVariables = pushVariables;
}
public PushRegistration(String fcmRegistrationId, Map<String, String> pushVariables) {
super(fcmRegistrationId);
this.pushVariables = pushVariables;
}
#Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result
+ ((pushVariables == null) ? 0 : pushVariables.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PushRegistration other = (PushRegistration) obj;
if (pushVariables == null) {
if (other.pushVariables != null) {
return false;
}
} else if (!pushVariables.equals(other.pushVariables)) {
return false;
}
return true;
}
protected String getPushVariablesXml() {
StringBuilder buf = new StringBuilder();
if (!tags.isEmpty()) {
buf.append("<PushVariables>");
buf.append(new GsonBuilder().disableHtmlEscaping().create().toJson(pushVariables));
buf.append("</PushVariables>");
}
return buf.toString();
}
#Override
public String getXml() {
return FCM_NATIVE_REGISTRATION1 +
getTagsXml() +
getPushVariablesXml() +
FCM_NATIVE_REGISTRATION2 +
fcmRegistrationId +
FCM_NATIVE_REGISTRATION3;
}
}
And afterwards , register a token using :
Map<String, String> pushVariables = new HashMap<>();
pushVariables.put("firstname", "Gaurav");
pushVariables.put("lastname", "Aggarwal");
Registration registration = new PushRegistration(name, token, pushVariables);
if (registration == null) {
registration = new FcmRegistration(name, token);
}
registration.getTags().add(tagname);
registration.getTags().add(category);
hub.createRegistration(registration);
And then send notification like:
Notification n = Notification.createFcmNotifiation("{\n" +
" \"notification\" : {\n" +
" \"body\" : \"{ $(firstname) + ' starting soon'}\",\n" +
" \"title\" : \"test title\"\n" +
" }\n" +
"}");
hub.sendNotification(n, tagname);

Related

On unity3d, my IBM chatbot can't recognize sequential

It is another unity watson sdk question.
I solved the first talk issue by just make fake object again..
Here is another thing.
In my chatbot I can see sequential text if there are same intents.
What line do I have to change or add to make it happen?
(another question: What line do I have to change or add to bring 'jump to' method in my unity?
using IBM.Watson.DeveloperCloud.Services.Conversation.v1;
using IBM.Watson.DeveloperCloud.Utilities;
using System;
using System.Collections.Generic;
using UnityEngine;
class Watson : MonoBehaviour{
static Credentials credentials;
static Conversation _conversation;
void Start()
{
credentials = new Credentials("xx-xx-xx-xx-xx", "xx", "https://gateway.watsonplatform.net/conversation/api");
// credentials.Url = "";
_conversation = new Conversation(credentials);
}
static Action<string, ManagerChat.Feel, bool> Act;
public static void GoMessage(string _str,Action<string, ManagerChat.Feel,bool> _act)
{
if (!_conversation.Message(OnMessage, "xx-xx-xx-xx-xx", _str))
Debug.Log("ExampleConversation Failed to message!");
Act = _act;
}
static bool GetIntent(Dictionary<string, object> respDict)
{
object intents;
respDict.TryGetValue("intents", out intents);
object intentString = new object();
object confidenceString = new object();
foreach (var intentObj in (intents as List<object>))
{
Dictionary<string, object> intentDict = intentObj as Dictionary<string, object>;
intentDict.TryGetValue("intent", out intentString);
intentDict.TryGetValue("confidence", out confidenceString);
}
string str = intentString as string;
if (str == "6사용자_마무리")
return true;
return false;
}
static string GetOutput(Dictionary<string, object> respDict)
{
object outputs;
respDict.TryGetValue("output", out outputs);
object output;
(outputs as Dictionary<string, object>).TryGetValue("text", out output);
string var = (output as List<object>)[0] as string;
return var;
}
static ManagerChat.Feel GetEntities(Dictionary<string, object> respDict)
{
object entities;
respDict.TryGetValue("entities", out entities);
List<object> entitieList = (entities as List<object>);
if(entitieList.Count == 0)
{
return ManagerChat.Feel.Normal;
}
else
{
object entitie;
(entitieList[0] as Dictionary<string, object>).TryGetValue("value", out entitie);
ManagerChat.Feel feel = ManagerChat.Feel.NONE;
string str = entitie as string;
switch (str)
{
case "Happy":
feel = ManagerChat.Feel.Happy;
break;
case "Expect":
feel = ManagerChat.Feel.Expect;
break;
case "Born":
feel = ManagerChat.Feel.Born;
break;
case "Sad":
feel = ManagerChat.Feel.Sad;
break;
case "Surprise":
feel = ManagerChat.Feel.Surprise;
break;
case "Normal":
feel = ManagerChat.Feel.Normal;
break;
default:
break;
}
return feel;
}
}
static void OnMessage(object resp, string data)
{
Dictionary<string, object> respDict = resp as Dictionary<string, object>;
bool flag = (GetIntent(respDict));
string output = (GetOutput(respDict));
ManagerChat.Feel feel = GetEntities(respDict);
// Debug.Log(resp);
// Debug.Log(data);
Act(output,feel, flag);
}
}
I don't quite follow your question about sequential texts, but I think you may be trying to do more in your application code than is needed.
I'll just give a high level pattern about how to use the sdk and see if that clears things up. Im no Unity dev, but the pattern is the same no matter the language.
You only need to give Watson the user's input text, and the existing context variables, most importantly system context, but any custom context you have created is valuable as well.
Then, Watson will return an output.text object, which you post to the user, and Watson also returns an updated system context.
Next, the user types something new, your app grabs that text, passes it to Watson along with the context object he returned last time, and the process repeats.
You should not need to do anything in your app code for jump tos, sequential text, etc., as thats all handled by Watson.
The only feature I can think of for the sequential piece is the response variations for a single dialog node. This feature means that if a user visits a specific dialog node multiple times, you will give different reponses, either in seuqential order, or random order, if there are multiple. It does require more than one input from the user, navigating to the same node multiple times. This is to give your bot some variation, most valuable for common inputs like 'hello', 'googbye', 'thanks', etc.

Watson keyword spotting unity

I have downloaded the Watson unity SDK and set it up like show in the picture and it works.
My question is how do I add keyword spotting?
I have read this question For Watson's Speech-To-Text Unity SDK, how can you specify keywords?
But I cant for example locate the SendStart function.
The Speech to Text service does not find keywords. To find keywords you would need to take the final text output and send it to the Alchemy Language service. Natural Language Understanding service is still being abstracted into the Watson Unity SDK but will eventually replace Alchemy Language.
private AlchemyAPI m_AlchemyAPI = new AlchemyAPI();
private void FindKeywords(string speechToTextFinalResponse)
{
if (!m_AlchemyAPI.ExtractKeywords(OnExtractKeywords, speechToTextFinalResponse))
Log.Debug("ExampleAlchemyLanguage", "Failed to get keywords.");
}
void OnExtractKeywords(KeywordData keywordData, string data)
{
Log.Debug("ExampleAlchemyLanguage", "GetKeywordsResult: {0}", JsonUtility.ToJson(resp));
}
EDIT 1
Natural Language Understanding has been abstracted in tot he Watson Unity SDK.
NaturalLanguageUnderstanding m_NaturalLanguageUnderstanding = new NaturalLanguageUnderstanding();
private static fsSerializer sm_Serializer = new fsSerializer();
private void FindKeywords(string speechToTextFinalResponse)
{
Parameters parameters = new Parameters()
{
text = speechToTextFinalResponse,
return_analyzed_text = true,
language = "en",
features = new Features()
{
entities = new EntitiesOptions()
{
limit = 50,
sentiment = true,
emotion = true,
},
keywords = new KeywordsOptions()
{
limit = 50,
sentiment = true,
emotion = true
}
}
if (!m_NaturalLanguageUnderstanding.Analyze(OnAnalyze, parameters))
Log.Debug("ExampleNaturalLanguageUnderstanding", "Failed to analyze.");
}
private void OnAnalyze(AnalysisResults resp, string customData)
{
fsData data = null;
sm_Serializer.TrySerialize(resp, out data).AssertSuccess();
Log.Debug("ExampleNaturalLanguageUnderstanding", "AnalysisResults: {0}", data.ToString());
}
EDIT 2
Sorry, I didn't realize Speech To Text had the ability to do keyword spotting. Thanks to Nathan for pointing that out to me! I added this functionality into a future release of Speech to Text in the Unity SDK. It will look like this for the Watson Unity SDK 1.0.0:
void Start()
{
// Create credential and instantiate service
Credentials credentials = new Credentials(_username, _password, _url);
_speechToText = new SpeechToText(credentials);
// Add keywords
List<string> keywords = new List<string>();
keywords.Add("speech");
_speechToText.KeywordsThreshold = 0.5f;
_speechToText.Keywords = keywords.ToArray();
_speechToText.Recognize(_audioClip, HandleOnRecognize);
}
private void HandleOnRecognize(SpeechRecognitionEvent result)
{
if (result != null && result.results.Length > 0)
{
foreach (var res in result.results)
{
foreach (var alt in res.alternatives)
{
string text = alt.transcript;
Log.Debug("ExampleSpeechToText", string.Format("{0} ({1}, {2:0.00})\n", text, res.final ? "Final" : "Interim", alt.confidence));
if (res.final)
_recognizeTested = true;
}
if (res.keywords_result != null && res.keywords_result.keyword != null)
{
foreach (var keyword in res.keywords_result.keyword)
{
Log.Debug("ExampleSpeechToText", "keyword: {0}, confidence: {1}, start time: {2}, end time: {3}", keyword.normalized_text, keyword.confidence, keyword.start_time, keyword.end_time);
}
}
}
}
}
Currently you can find the refactor branch here. This release is a breaking change and has all of the higher level (widgets, config, etc) functionality removed.

Configuration for loading story from String?

I have a web service posting Gherkins stories to a back-end and would like to load those stories into configuration as a string without having to save them as a file.
Can this be accomplished?
You need to implement your custoom story loader that will collect stories from the web service and pass them to JBehave.
You need also use a GherkinStoryParser to translate stories from Gherking format to JBehave format.
An example configuration might look like in the following example.
A custom story loader that retrieves stories from a map of strings:
public class MyStoryLoader implements StoryLoader {
private Map<String,String> stories;
public MyStoryLoader( Map<String,String> storiesToLoad){
this.stories = storiesToLoad;
}
public String loadStoryAsText(String storyName) {
return stories.get( storyName );
}
}
Some class that collects stories from the web service and return them as a map with unique story names and story bodies:
public class StoryCollectorFromWebService {
private final static String storyTemplate = "Feature: A story that is saved in the string\n"
+ "\n"
+ "Scenario: Read the scenario from the string\n"
+ "\n"
+ "Given There is some story named ${name} saved in the string\n"
+ "When I run this story named ${name}\n"
+ "Then I can see it's results";
// This is a method that collects stories from the Web Service and saves them in a map of strings
public Map<String,String> getStoriesFromWebService(){
Map<String,String> storiesFromWebService = new HashMap<String,String>();
String storyNames[] = {"A","B","C","ABC","Some story", "Another story"};
for(String storyName: storyNames)
storiesFromWebService.put( storyName, storyTemplate.replace("${name}", storyName));
return storiesFromWebService;
}
}
and sample configuration to run these stories using our StoryLoader and GherkinStoryParser:
public class RunAs_JUnitStories extends JUnitStories {
public RunAs_JUnitStories() {
configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
.doIgnoreFailureInView(true).useThreads(1).useStoryTimeoutInSecs(60);
}
Map<String,String> storiesFromWebService = new StoryCollectorFromWebService().getStoriesFromWebService();
#Override
protected List<String> storyPaths() {
return new ArrayList<String>( storiesFromWebService.keySet());
}
#Override
public Configuration configuration() {
Class<? extends Embeddable> embeddableClass = this.getClass();
ParameterConverters parameterConverters = new ParameterConverters();
ExamplesTableFactory examplesTableFactory = new ExamplesTableFactory(new LocalizedKeywords(), new LoadFromClasspath(embeddableClass), parameterConverters);
parameterConverters.addConverters(new DateConverter(new SimpleDateFormat("yyyy-MM-dd")),
new ExamplesTableConverter(examplesTableFactory));
return new MostUsefulConfiguration()
// Use custom story loader
.useStoryLoader(new MyStoryLoader( storiesFromWebService ))
// Use Gherkin parser
.useStoryParser( new GherkinStoryParser() )
.useStoryReporterBuilder(new StoryReporterBuilder()
.withCodeLocation(CodeLocations.codeLocationFromClass(embeddableClass))
.withDefaultFormats()
.withMultiThreading(true)
.withFormats(CONSOLE, TXT, HTML, XML))
.useParameterConverters(parameterConverters);
}
#Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new MySteps());
}
}
Here is a link to a working example: https://github.com/kordirko/TestJBB
You can try import it into Eclipse and play with it, but I apologize if something goes wrong,
It's my first project on github, I'am still learning how to do it :)

Get a scenario-by-scenario pass/fail report with JBehave

I want to generate a report from JBehave that just lists the name of each scenario and a PASS/FAIL status. Bonus points if it gives a PASS/FAIL status for a story based on the the scenario results (if all scenarios pass the story passes). Something like:
PASS: Story: Build a widget.
PASS: Scenario: Build a normal widget.
PASS: Scenario: Build a custom widget.
FAIL: Story: Test a widget.
PASS: Scenario: Test a normal widget.
FAIL: Scenario: Test a custom widget.
Text is preferred but I can work with other formats.
This post:
Additional logging JBehave
shows how to use a StoryReporter to capture pass/fail for individual steps, but going through the interface I can't see how to capture the final status of a single scenario.
A commenter later in the same post mentions that there are several view genaration examples in the source distribution. If someone can give more specific pointers to which of the examples do this that would help too.
The StoryReporter code below should do what you are looking for. It keeps track of each scenario and the pass/fail status of each step in the scenario. If any step fails, then the scenario is failed. If any scenario fails, then the story is marked as failed. At the end of the story it logs the results.
public class MyStoryReporter implements org.jbehave.core.reporters.StoryReporter {
private Story runningStory;
private boolean runningStoryStatus;
private String runningScenarioTitle;
private boolean runningScenarioStatus;
private List<ScenarioResult> scenarioList;
private Log log = LogFactory.getLog(this.getClass());
private class ScenarioResult {
public String title;
public boolean result;
public ScenarioResult(String title, boolean result) {
this.title = title;
this.result = result;
}
}
public void beforeStory(Story story, boolean b) {
runningStory = story;
runningStoryStatus = true;
scenarioList = new ArrayList<>();
}
public void afterStory(boolean b) {
String storyPrefix = runningStoryStatus ? "PASS: STORY: " : "FAIL: STORY: ";
log.info(storyPrefix + runningStory.getName() + ".");
String scenarioPrefix;
for (ScenarioResult scenario : scenarioList) {
scenarioPrefix = scenario.result ? " PASS: SCENARIO: " : " FAIL: SCENARIO: ";
log.info(scenarioPrefix + scenario.title + ".");
}
}
public void beforeScenario(String s) {
runningScenarioTitle = s;
runningScenarioStatus = true;
}
public void afterScenario() {
scenarioList.add(new ScenarioResult(runningScenarioTitle, runningScenarioStatus));
runningStoryStatus = runningStoryStatus && runningScenarioStatus;
}
public void failed(String s, Throwable throwable) {
runningScenarioStatus = false;
}

Chain multiple 2 step file uploads with Rx

I am attempting to upload multiple files from a Silverlight client directly to Amazon S3. The user chooses the files from the standard file open dialog and I want to chain the uploads so they happen serially one at a time. This can happen from multiple places in the app so I was trying to wrap it up in a nice utility class that accepts an IEnumerable of the chosen files exposes an IObservable of the files as they are uploaded so that the UI can respond accordingly as each file is finished.
It is fairly complex due to all the security requirements of both Silverlight and AmazonS3. I'll try to briefly explain my whole environment for context, but I have reproduced the issue with a small console application that I will post the code to below.
I have a 3rd party utility that handles uploading to S3 from Silverlight that exposes standard event based async methods. I create one instance of that utility per uploaded file. It creates an unsigned request string that I then post to my server to sign with my private key. That signing request happens through a service proxy class that also uses event based async methods. Once I have the signed request, I add it to the uploader instance and initiate the upload.
I've tried using Concat, but I end up with only the first file going through the process. When I use Merge, all files complete fine, but in a parallel fashion rather than serially. When I use Merge(2) all files start the first step, but then only 2 make their way through and complete.
Obviously I am missing something related to Rx since it isn't behaving like I expect.
namespace RxConcat
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Timers;
public class SignCompletedEventArgs : EventArgs
{
public string SignedRequest { get; set; }
}
public class ChainUploader
{
public IObservable<string> StartUploading(IEnumerable<string> files)
{
return files.Select(
file => from signArgs in this.Sign(file + "_request")
from uploadArgs in this.Upload(file, signArgs.EventArgs.SignedRequest)
select file).Concat();
}
private IObservable<System.Reactive.EventPattern<SignCompletedEventArgs>> Sign(string request)
{
Console.WriteLine("Signing request '" + request + "'");
var signer = new Signer();
var source = Observable.FromEventPattern<SignCompletedEventArgs>(ev => signer.SignCompleted += ev, ev => signer.SignCompleted -= ev);
signer.SignAsync(request);
return source;
}
private IObservable<System.Reactive.EventPattern<EventArgs>> Upload(string file, string signedRequest)
{
Console.WriteLine("Uploading file '" + file + "'");
var uploader = new Uploader();
var source = Observable.FromEventPattern<EventArgs>(ev => uploader.UploadCompleted += ev, ev => uploader.UploadCompleted -= ev);
uploader.UploadAsync(file, signedRequest);
return source;
}
}
public class Signer
{
public event EventHandler<SignCompletedEventArgs> SignCompleted;
public void SignAsync(string request)
{
var timer = new Timer(1000);
timer.Elapsed += (sender, args) =>
{
timer.Stop();
if (this.SignCompleted == null)
{
return;
}
this.SignCompleted(this, new SignCompletedEventArgs { SignedRequest = request + "signed" });
};
timer.Start();
}
}
public class Uploader
{
public event EventHandler<EventArgs> UploadCompleted;
public void UploadAsync(string file, string signedRequest)
{
var timer = new Timer(1000);
timer.Elapsed += (sender, args) =>
{
timer.Stop();
if (this.UploadCompleted == null)
{
return;
}
this.UploadCompleted(this, new EventArgs());
};
timer.Start();
}
}
internal class Program
{
private static void Main(string[] args)
{
var files = new[] { "foo", "bar", "baz" };
var uploader = new ChainUploader();
var token = uploader.StartUploading(files).Subscribe(file => Console.WriteLine("Upload completed for '" + file + "'"));
Console.ReadLine();
}
}
}
The base observable that is handling the 2 step upload for each file is never 'completing' which prevents the next one in the chain from starting. Add a Limit(1) to that observable prior to calling Concat() and it will working correctly.
return files.Select(file => (from signArgs in this.Sign(file + "_request")
from uploadArgs in this.Upload(file, signArgs.EventArgs.SignedRequest)
select file).Take(1)).Concat();