photon pun2 unity playfab email and password auth - unity3d

i want to make email auth with playfab and photon istead of custom id auth shown in photon quickstart guide playfab. i tried this script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Realtime;
using Photon.Pun;
using PlayFab;
using PlayFab.ClientModels;
using TMPro;
public class pfauth : MonoBehaviour
{
#region objects
[Header (" register ")]
public TMP_InputField user;
public TMP_InputField email;
public TMP_InputField pass;
public GameObject regpanel;
[Header(" login ")]
public TMP_InputField luser;
public TMP_InputField lpass;
public GameObject loginpanel;
[Header(" Other gameobjects ")]
public TMP_Text message;
public bool IsAuthenticated = false;
public GameObject prpo;
public float sec;
private string _playFabPlayerIdCache;
LoginWithPlayFabRequest loginrequest;
#endregion
public void Start() //set the loginpanel as disable at start
{
loginpanel.SetActive(false);
regpanel.SetActive(true);
}
public void login()
{
loginrequest = new LoginWithPlayFabRequest();
loginrequest.Username = luser.text;
loginrequest.Password = lpass.text;
PlayFabClientAPI.LoginWithPlayFab(loginrequest, \\in this line how can i call requestphotontoken result => {
//if account found
message.text = "welcome back" + user.text + "loging in...";
StartCoroutine("waitforempty"); //hide the text after few seconds
IsAuthenticated = true;
Debug.Log("logged in");
}, error => {
message.text = "Sorry! Failed to login(" + error.ErrorMessage + ")";
StartCoroutine("waitforempty"); //hide the text after few seconds
Debug.Log(error.ErrorDetails);
IsAuthenticated = false;
}, null);
}
public void register()
{
RegisterPlayFabUserRequest request = new RegisterPlayFabUserRequest();
request.Email = email.text;
request.Password = pass.text;
request.Username = user.text;
PlayFabClientAPI.RegisterPlayFabUser(request, \\in this line how can i call requestphotontoken result =>
{
message.text = "Your account has been created!";
StartCoroutine("waitforempty"); //hide the text after few seconds
prpo.SetActive(true);
}, error =>
{
message.text = "Sorry! Failed to create your account(" + error.ErrorMessage + ")";
StartCoroutine("waitforempty"); //hide the text after few seconds
});
}
public void regpan()
{
loginpanel.SetActive(false);
regpanel.SetActive(true);
}
public void logbak()
{
loginpanel.SetActive(true);
regpanel.SetActive(false);
}
IEnumerator waitforempty() //hide the text after few seconds
{
yield return new WaitForSeconds(sec);
message.text = " ";
}
private void RequestPhotonToken(LoginResult obj)
{
LogMessage("PlayFab authenticated. Requesting photon token...");
//We can player PlayFabId. This will come in handy during next step
_playFabPlayerIdCache = obj.PlayFabId;
PlayFabClientAPI.GetPhotonAuthenticationToken(new GetPhotonAuthenticationTokenRequest()
{
PhotonApplicationId = PhotonNetwork.PhotonServerSettings.AppSettings.AppIdRealtime
}, AuthenticateWithPhoton, OnPlayFabError);
}
/*
* Step 3
* This is the final and the simplest step. We create new AuthenticationValues instance.
* This class describes how to authenticate a players inside Photon environment.
*/
private void AuthenticateWithPhoton(GetPhotonAuthenticationTokenResult obj)
{
LogMessage("Photon token acquired: " + obj.PhotonCustomAuthenticationToken + " Authentication complete.");
//We set AuthType to custom, meaning we bring our own, PlayFab authentication procedure.
var customAuth = new AuthenticationValues { AuthType = CustomAuthenticationType.Custom };
//We add "username" parameter. Do not let it confuse you: PlayFab is expecting this parameter to contain player PlayFab ID (!) and not username.
customAuth.AddAuthParameter("username", _playFabPlayerIdCache); // expected by PlayFab custom auth service
//We add "token" parameter. PlayFab expects it to contain Photon Authentication Token issues to your during previous step.
customAuth.AddAuthParameter("token", "");
//We finally tell Photon to use this authentication parameters throughout the entire application.
PhotonNetwork.AuthValues = customAuth;
Debug.Log(PhotonNetwork.ConnectUsingSettings().ToString());
}
private void OnPlayFabError(PlayFabError obj)
{
LogMessage(obj.GenerateErrorReport());
}
public void LogMessage(string message)
{
Debug.Log("PlayFab + Photon Example: " + message);
}
}
but in the "PlayFabClientAPI.LoginWithPlayFab(loginrequest, \in this line how can i call requestphotontoken" result line in both login and register void when i try to call RequestPhotonToken i shows this error-
Cannot convert methord group to function
please help
Photon PUN 2
Playfab latest

Related

How would I get a Texture in the project and send it over to discord using a webhook? Unity

What I am trying to do is take a texture(any texture) from unity and use a webhook from discord to send it to discord.
This is what I have so far keep in mind I started coding not long ago so I'm not very familiar with this;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class SendMessage : MonoBehaviour
{
public string Message, Subject;
public string webhook;
public Texture2D screenshot;
// Start is called before the first frame update
void Start()
{
}
IEnumerator SendWebHook(string link, string message, System.Action<bool> action)
{
WWWForm form = new WWWForm();
form.AddField("content", message + screenshot.EncodeToPNG());
using (UnityWebRequest www = UnityWebRequest.Post(link, form))
{
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
action(false);
}
else
{
action(true);
}
}
}
public void send()
{
StartCoroutine(SendWebHook(webhook, Subject + Message, (success) =>
{
if(success)
{
Debug.Log("good");
}
}));
}
}

Read Events from EventHub in Unity3D and HoloLens

We are trying to show events from an Azure EventHub in our HoloLens application. When we run our project in Unity 3D, it works and paint the data from the events.
But when we deploy the same solution on the HoloLens, we don't receive events and also we don't receive any error.
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Microsoft.MixedReality.Toolkit.UI;
using TMPro;
using System;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using Azure.Messaging.EventHubs;
using Azure.Messaging.EventHubs.Processor;
using Azure.Storage.Blobs;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Microsoft.MixedReality.Toolkit.Examples.Demos
{
[AddComponentMenu("Scripts/MRTK/Examples/SliderLunarLander")]
public class Manager : MonoBehaviour
{
[SerializeField]
public Animator helice2;
public TextMeshPro textovelocidad;
public EventProcessorClient processor;
public BlobContainerClient storageClient;
private const string storageConnectionString = "XXXX";
private const string blobContainerName = "XXXX";
private const string eventHubsConnectionString = "XXXX";
private const string consumerGroup = "hololens";
private const string EventHubName = "XXXX";
private float? speedValue;
private string errorText = string.Empty;
private CancellationToken cancellationToken;
async void Start()
{
errorText = "Init EventReader...";
storageClient = new BlobContainerClient(storageConnectionString, blobContainerName);
var clientOptions = new EventProcessorClientOptions()
{
ConnectionOptions = new EventHubConnectionOptions ()
{
TransportType = EventHubsTransportType.AmqpWebSockets
}
};
processor = new EventProcessorClient
(
storageClient,
consumerGroup,
eventHubsConnectionString,
clientOptions
);
processor.ProcessEventAsync += processEventHandler;
processor.ProcessErrorAsync += processErrorHandler;
errorText = "Start EventReader...";
await processor.StartProcessingAsync();
try
{
//The processor performs its work in the background; block until cancellation
//to allow processing to take place.
errorText = "Infinite Loop...";
await Task.Delay(Timeout.Infinite);
}
catch (TaskCanceledException tcex)
{
//This is expected when the delay is canceled.
textoError.text = tcex.Message;
}
//Debug.Log("Device client initialited...");
}
public void OnSliderUpdated(SliderEventData eventData)
{
helice2.speed = eventData.NewValue;
}
async void OnDestroy()
{
try
{
await processor.StopProcessingAsync();
}
finally
{
//To prevent leaks, the handlers should be removed when processing is complete.
processor.ProcessEventAsync -= processEventHandler;
processor.ProcessErrorAsync -= processErrorHandler;
}
}
private void Update()
{
if (speedValue != null)
{
helice2.speed = float.Parse(speedValue.ToString());
}
textovelocidad.text = (helice2.speed).ToString("F2") + " r.p.m.";
textovelocidad.text += " | " + infoText;
textoError.text = errorText;
}
async Task processEventHandler(ProcessEventArgs eventArgs)
{
try
{
// Write the body of the event to the console window
//Console.WriteLine("\tRecevied event: {0}", Encoding.UTF8.GetString(eventArgs.Data.Body.ToArray()));
infoText = " Event Received ";
string json = Encoding.UTF8.GetString(eventArgs.Data.Body.ToArray());
var deviceTurbine = JsonSerializer.Deserialize<DeviceTurbine>(json);
if (deviceTurbine != null)
{
speedValue = deviceTurbine.speed;
}
// Update checkpoint in the blob storage so that the app receives only new events the next time it's run
await eventArgs.UpdateCheckpointAsync(eventArgs.CancellationToken);
}
catch (Exception ex)
{
// Handle the exception from handler code
// Debug.LogError(ex.Message);
errorText = ex.Message;
}
}
Task processErrorHandler(ProcessErrorEventArgs eventArgs)
{
try
{
// Write details about the error to the console window
//Console.WriteLine($"\tPartition '{ eventArgs.PartitionId}': an unhandled exception was encountered. This was not expected to happen.");
//Console.WriteLine(eventArgs.Exception.Message);
errorText = eventArgs.Exception.Message;
}
catch
{
// Handle the exception from handler code
errorText = eventArgs.Exception.Message;
}
return Task.CompletedTask;
}
}
class DeviceTurbine
{
private float _speed;
private DateTime _timestamp;
private string _deviceId;
public float speed
{
get; set;
}
public DateTime timestamp
{
get;set;
}
public string deviceId
{
get; set;
}
}
}

How to Integrate Huawei Account kit

Currently I'm using Huawei Plugin From EvilMindDev.
Below is AccountManager script.
using HuaweiMobileServices.Id;
using HuaweiMobileServices.Utils;
using System;
using UnityEngine;
namespace HmsPlugin
{
public class AccountManager : MonoBehaviour
{
public static AccountManager GetInstance(string name = "AccountManager") => GameObject.Find(name).GetComponent<AccountManager>();
private static HuaweiIdAuthService DefaultAuthService
{
get
{
Debug.Log("[HMS]: GET AUTH");
var authParams = new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM).SetIdToken().CreateParams();
Debug.Log("[HMS]: AUTHPARAMS AUTHSERVICE" + authParams);
var result = HuaweiIdAuthManager.GetService(authParams);
Debug.Log("[HMS]: RESULT AUTHSERVICE"+ result);
return result;
}
}
public AuthHuaweiId HuaweiId { get; private set; }
public Action<AuthHuaweiId> OnSignInSuccess { get; set; }
public Action<HMSException> OnSignInFailed { get; set; }
private HuaweiIdAuthService authService;
// Start is called before the first frame update
void Awake()
{
Debug.Log("[HMS]: AWAKE AUTHSERVICE");
authService = DefaultAuthService;
Debug.Log("DefaultAuthService : "+DefaultAuthService);
Debug.Log("authService : "+authService);
}
public void SignIn()
{
Debug.Log("[HMS]: Sign in " + authService);
authService.StartSignIn((authId) =>
{
HuaweiId = authId;
Debug.Log("HuaweiId : "+HuaweiId);
OnSignInSuccess?.Invoke(authId);
}, (error) =>
{
HuaweiId = null;
OnSignInFailed?.Invoke(error);
});
}
public void SignOut()
{
Debug.Log("authService.SignOut");
authService.SignOut();
HuaweiId = null;
}
}
}
Below is AccountSignIn script.
using HuaweiMobileServices.Id;
using HuaweiMobileServices.Utils;
using UnityEngine;
using UnityEngine.UI;
using HmsPlugin;
public class AccountSignIn : MonoBehaviour
{
private const string NOT_LOGGED_IN = "No user logged in";
private const string LOGGED_IN = "{0} is logged in";
private const string LOGIN_ERROR = "Error or cancelled login";
private Text loggedInUser;
private AccountManager accountManager;
// Start is called before the first frame update
void Start()
{
loggedInUser = GameObject.Find("LoggedUserText").GetComponent<Text>();
loggedInUser.text = NOT_LOGGED_IN;
//accountManager = AccountManager.GetInstance();
accountManager = GetComponent<AccountManager>();
accountManager.OnSignInSuccess = OnLoginSuccess;
accountManager.OnSignInFailed = OnLoginFailure;
LogIn();
}
public void LogIn()
{
accountManager.SignIn();
}
public void LogOut()
{
accountManager.SignOut();
loggedInUser.text = NOT_LOGGED_IN;
}
public void OnLoginSuccess(AuthHuaweiId authHuaweiId)
{
loggedInUser.text = string.Format(LOGGED_IN, authHuaweiId.DisplayName);
}
public void OnLoginFailure(HMSException error)
{
loggedInUser.text = LOGIN_ERROR;
}
}
Everytime I try to SignIn it will give me this error.
This is HuaweiIdAuthService.
Even if I try the demo provided will give me the same error.
If I try debug using Android Studio it will still give me the same error.
public void SignIn()
{
Debug.Log("[HMS]: Sign in " + authService);
authService.StartSignIn((authId) =>
{
HuaweiId = authId;
Debug.Log("HuaweiId : "+HuaweiId);
OnSignInSuccess?.Invoke(authId);
}, (error) =>
{
HuaweiId = null;
OnSignInFailed?.Invoke(error);
});
}
the authService doesn't return anything. Where can I get that from ?
It is a null pointer. Please check for unassigned objects. If you cannot find anything, please delete project and install again cause sometimes these kind of things happening.
This plugin have 2 branch for Unity 2019 and Unity 2018.
You should activate Account Kit API in Huawei Appgallery
Check configuration AndroidManifest file
Check Agconnect-service.json file

Getting Same response to any query in Watson Assistant V2 : Watson-Unity-SDK

I just got to a point where I could set-up the Watson Assistant V2 with Unity and trying to converse with an Assistant I created with a single Skill. I need further help to get the assistant set up to work with my Unity app.
In V1 of the assistant, it was possible to target a workspace and also the response was returning the intent, nodes visited so on. My queries were correctly processed and the responses were identical to the one on the "try it" application in the IBM cloud dashboard.
In the new version though, I am getting the same response for any query I send to the assistant. How can I target the right skill or rather pass correct settings to the assistant to get the correct responses?
IMAGE - Unity log showing assistant responses
[IMAGE - Assistant trial on dashboard][2]
The code I'm using to send queries and get responses is:
IEnumerator TokenExample()
{
// Create IAM token options and supply the apikey. IamUrl is the URL used to get the
// authorization token using the IamApiKey. It defaults to https://iam.bluemix.net/identity/token
TokenOptions iamTokenOptions = new TokenOptions()
{
IamApiKey = "API KEY",
IamUrl = "https://iam.bluemix.net/identity/token"
};
// Create credentials using the IAM token options
_credentials = new Credentials(iamTokenOptions, "https://gateway-fra.watsonplatform.net/assistant/api");
while (!_credentials.HasIamTokenData())
yield return null;
_assistant = new Assistant(_credentials);
_assistant.VersionDate = "2018-11-01";
Debug.Log(_assistant.GetServiceID()); // returns "AssitantV2"
}
public void PingAssistantV2() // triggered from a button press in UI
{
_assistant.CreateSession(OnCreateSession, OnFail, AssistantID); // Assistant ID is entered through the Inspector
}
public void OnCreateSession(SessionResponse response, Dictionary<string, object> customData)
{
Log.Debug("ExampleAssistantV2.OnMessage()", "Assistant: Create Session Response: {0}", customData["json"].ToString());
string _si = response.SessionId;
Debug.Log("SessionID: " +_si);
MessageInput mi = new MessageInput();
mi.Text = Query.textComponent.text; // get user query from an input field in unity UI
MessageRequest messageRequest = new MessageRequest()
{
Input = mi
};
Debug.LogFormat("<b> Query Sent: {0} </b>", Query.textComponent.text);
if (response.SessionId != null ) _assistant.Message(OnMessage, OnFail, AssistantID, _si, messageRequest);
}
private void OnMessage(MessageResponse AssistantResponse, Dictionary<string, object> customData)
{
Log.Debug("ExampleAssistant.OnMessage()", "Response: {0}", customData["json"].ToString());
Debug.LogFormat("<b> SUCCESS </b>");
Debug.Log(customData["json"].ToString());
// Convert resp to fsdata
fsData fsdata = null;
fsResult r = _serializer.TrySerialize(AssistantResponse.GetType(), AssistantResponse, out fsdata);
if (!r.Succeeded)
throw new WatsonException(r.FormattedMessages);
// Convert fsdata to MessageResponse
IBM.WatsonDeveloperCloud.Assistant.v2.MessageResponse messageResponse = new IBM.WatsonDeveloperCloud.Assistant.v2.MessageResponse();
object obj = messageResponse;
r = _serializer.TryDeserialize(fsdata, obj.GetType(), ref obj);
if (!r.Succeeded)
throw new WatsonException(r.FormattedMessages);
Response.text = AssistantResponse.Output.Generic.First().Text; // send response to unity UI text box
}
private void OnFail(RESTConnector.Error error, Dictionary<string, object> customData)
{
Log.Debug("OnFail()", "Failed: {0}", error.ToString());
Debug.LogFormat("<b> Failed </b>");
Debug.Log(error.ToString());
}
EDIT to address #Taj's comment
The Issue persists even with the sample for assitant V2 in the SDK:
Wrong Unity Responses v/s appropriate responses in dashboardtrail
The code adopted from the example included in the SDK:
/**
* Copyright 2018 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using IBM.Watson.DeveloperCloud.Connection;
using IBM.Watson.DeveloperCloud.Logging;
using IBM.Watson.DeveloperCloud.Utilities;
using IBM.WatsonDeveloperCloud.Assistant.v2;
using UnityEngine;
using TMPro;
namespace IBM.Watson.DeveloperCloud.Services.Assistant.v2
{
public class ExampleAssistantV2 : MonoBehaviour
{
#region PLEASE SET THESE VARIABLES IN THE INSPECTOR
[Space(10)]
[Tooltip("The service URL (optional). This defaults to \"https://gateway.watsonplatform.net/assistant/api\"")]
[SerializeField]
private string _serviceUrl;
[Tooltip("The assistantId to run the example.")]
[SerializeField]
private string _assistantId;
[Tooltip("The version date with which you would like to use the service in the form YYYY-MM-DD.")]
[SerializeField]
private string _versionDate;
[Header("CF Authentication")]
[Tooltip("The authentication username.")]
[SerializeField]
private string _username;
[Tooltip("The authentication password.")]
[SerializeField]
private string _password;
[Header("IAM Authentication")]
[Tooltip("The IAM apikey.")]
[SerializeField]
private string _iamApikey;
[Tooltip("The IAM url used to authenticate the apikey (optional). This defaults to \"https://iam.bluemix.net/identity/token\".")]
[SerializeField]
private string _iamUrl;
#endregion
private Assistant _service;
private bool _createSessionTested = false;
private bool _messageTested = false;
private bool _deleteSessionTested = false;
private string _sessionId;
public TMP_InputField query;
public TextMeshProUGUI response;
private void Start()
{
LogSystem.InstallDefaultReactors();
Runnable.Run(CreateService());
}
private IEnumerator CreateService()
{
// Create credential and instantiate service
Credentials credentials = null;
if (!string.IsNullOrEmpty(_username) && !string.IsNullOrEmpty(_password))
{
// Authenticate using username and password
credentials = new Credentials(_username, _password, _serviceUrl);
}
else if (!string.IsNullOrEmpty(_iamApikey))
{
// Authenticate using iamApikey
TokenOptions tokenOptions = new TokenOptions()
{
IamApiKey = _iamApikey,
IamUrl = _iamUrl
};
credentials = new Credentials(tokenOptions, _serviceUrl);
// Wait for tokendata
while (!credentials.HasIamTokenData())
yield return null;
}
else
{
throw new WatsonException("Please provide either username and password or IAM apikey to authenticate the service.");
}
_service = new Assistant(credentials);
_service.VersionDate = _versionDate;
Runnable.Run(SessionCreate());
}
private IEnumerator SessionCreate()
{
Log.Debug("ExampleAssistantV2.Examples()", "Attempting to CreateSession");
_service.CreateSession(OnCreateSession, OnFail, _assistantId);
while (!_createSessionTested)
{
yield return null;
}
}
private IEnumerator Examples()
{
Log.Debug("ExampleAssistantV2.Examples()", "Attempting to Message");
MessageInput mi = new MessageInput(); // construct a messgae input
mi.Text = query.textComponent.text;
MessageRequest messageRequest = new MessageRequest() // construct a message request
{
Input = mi
};
Log.Debug("ExampleAssistantV2.OnDeleteSession()", "<b>Query: </b> <b>{0}</b>", messageRequest.Input.Text);
_service.Message(OnMessage, OnFail, _assistantId, _sessionId,messageRequest); // send a message request
while (!_messageTested)
{
yield return null;
}
//Log.Debug("ExampleAssistantV2.Examples()", "Attempting to DeleteSession");
//_service.DeleteSession(OnDeleteSession, OnFail, _assistantId, _sessionId);
//while (!_deleteSessionTested)
//{
// yield return null;
//}
//Log.Debug("ExampleAssistantV2.Examples()", "Assistant examples complete.");
}
private void OnDeleteSession(object response, Dictionary<string, object> customData)
{
Log.Debug("ExampleAssistantV2.OnDeleteSession()", "Session deleted.");
_createSessionTested = true;
}
private void OnMessage(MessageResponse _response, Dictionary<string, object> customData)
{
_messageTested = true;
response.text = _response.Output.Generic.First().Text; // trying to get response
Log.Debug("ExampleAssistantV2.OnDeleteSession()", "<b>RESPONSE: </b> <b>{0}</b>", response.text);
}
private void OnCreateSession(SessionResponse response, Dictionary<string, object> customData)
{
Log.Debug("ExampleAssistantV2.OnCreateSession()", "Session: <b>{0}</b>", response.SessionId);
_sessionId = response.SessionId;
_createSessionTested = true;
}
private void OnFail(RESTConnector.Error error, Dictionary<string, object> customData)
{
Log.Debug("ExampleAssistantV2.OnFail()", "Call failed: {0}: {1}", error.ErrorCode, error.ErrorMessage);
}
public void PingAssitant ()
{
Runnable.Run(Examples());
}
}
}
I can see from your log that you have a new sessionId each time you message. You do not need to create a session each time you send a message. The session should persist during the conversation. I moved the call to CreateSession to your TokenExample() and call PingAssistantV2() once you have a sessionId.
string _si = "";
IEnumerator TokenExample()
{
// Create IAM token options and supply the apikey. IamUrl is the URL used to get the
// authorization token using the IamApiKey. It defaults to https://iam.bluemix.net/identity/token
TokenOptions iamTokenOptions = new TokenOptions()
{
IamApiKey = "API KEY",
IamUrl = "https://iam.bluemix.net/identity/token"
};
// Create credentials using the IAM token options
_credentials = new Credentials(iamTokenOptions, "https://gateway-fra.watsonplatform.net/assistant/api");
while (!_credentials.HasIamTokenData())
yield return null;
_assistant = new Assistant(_credentials);
_assistant.VersionDate = "2018-11-01";
Debug.Log(_assistant.GetServiceID()); // returns "AssitantV2"
_assistant.CreateSession(OnCreateSession, OnFail, AssistantID); // Assistant ID is entered through the Inspector
}
public void PingAssistantV2() // triggered from a button press in UI
{
MessageInput mi = new MessageInput();
mi.Text = Query.textComponent.text; // get user query from an input field in unity UI
MessageRequest messageRequest = new MessageRequest()
{
Input = mi
};
Debug.LogFormat("<b> Query Sent: {0} </b>", Query.textComponent.text);
if (response.SessionId != null ) _assistant.Message(OnMessage, OnFail, AssistantID, _si, messageRequest);
}
public void OnCreateSession(SessionResponse response, Dictionary<string, object> customData)
{
Log.Debug("ExampleAssistantV2.OnMessage()", "Assistant: Create Session Response: {0}", customData["json"].ToString());
_si = response.SessionId;
Debug.Log("SessionID: " +_si);
PingAssistantV2();
}
private void OnMessage(MessageResponse AssistantResponse, Dictionary<string, object> customData)
{
Log.Debug("ExampleAssistant.OnMessage()", "Response: {0}", customData["json"].ToString());
Debug.LogFormat("<b> SUCCESS </b>");
Debug.Log(customData["json"].ToString());
// Convert resp to fsdata
fsData fsdata = null;
fsResult r = _serializer.TrySerialize(AssistantResponse.GetType(), AssistantResponse, out fsdata);
if (!r.Succeeded)
throw new WatsonException(r.FormattedMessages);
// Convert fsdata to MessageResponse
IBM.WatsonDeveloperCloud.Assistant.v2.MessageResponse messageResponse = new IBM.WatsonDeveloperCloud.Assistant.v2.MessageResponse();
object obj = messageResponse;
r = _serializer.TryDeserialize(fsdata, obj.GetType(), ref obj);
if (!r.Succeeded)
throw new WatsonException(r.FormattedMessages);
Response.text = AssistantResponse.Output.Generic.First().Text; // send response to unity UI text box
}
private void OnFail(RESTConnector.Error error, Dictionary<string, object> customData)
{
Log.Debug("OnFail()", "Failed: {0}", error.ToString());
Debug.LogFormat("<b> Failed </b>");
Debug.Log(error.ToString());
}
#taj your develop branch at https://github.com/watson-developer-cloud/unity-sdk/archive/develop.zip is now working! Thank you for your commitment towards sorting this out. I do not have sufficient rep to upvote your answer but ya, Kudos!
Working Code as provided by #taj on the WDC Slack channel:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using IBM.Watson.DeveloperCloud.Connection;
using IBM.Watson.DeveloperCloud.Logging;
using IBM.Watson.DeveloperCloud.Utilities;
using IBM.WatsonDeveloperCloud.Assistant.v2;
using UnityEngine;
using TMPro;
namespace IBM.Watson.DeveloperCloud.Services.Assistant.v2
{
public class ExampleAssistantV2b : MonoBehaviour
{
#region PLEASE SET THESE VARIABLES IN THE INSPECTOR
[Space(10)]
[Tooltip("The service URL (optional). This defaults to \"https://gateway.watsonplatform.net/assistant/api\"")]
[SerializeField]
private string _serviceUrl;
[Tooltip("The assistantId to run the example.")]
[SerializeField]
private string _assistantId;
[Tooltip("The version date with which you would like to use the service in the form YYYY-MM-DD.")]
[SerializeField]
private string _versionDate;
[Header("CF Authentication")]
[Tooltip("The authentication username.")]
[SerializeField]
private string _username;
[Tooltip("The authentication password.")]
[SerializeField]
private string _password;
[Header("IAM Authentication")]
[Tooltip("The IAM apikey.")]
[SerializeField]
private string _iamApikey;
[Tooltip("The IAM url used to authenticate the apikey (optional). This defaults to \"https://iam.bluemix.net/identity/token\".")]
[SerializeField]
private string _iamUrl;
#endregion
private Assistant _service;
private string _sessionId;
public TMP_InputField query;
public TextMeshProUGUI response;
public List<string> testQueryList;
public int queryNum = 0;
private void Start()
{
LogSystem.InstallDefaultReactors();
testQueryList = new List<string>()
{
"",
"What are your hours?",
"Are you open on Christmas?",
"I would like to make an appointment",
"Friday at 12pm",
"yes"
};
Runnable.Run(CreateService());
}
private IEnumerator CreateService()
{
// Create credential and instantiate service
Credentials credentials = null;
if (!string.IsNullOrEmpty(_username) && !string.IsNullOrEmpty(_password))
{
// Authenticate using username and password
credentials = new Credentials(_username, _password, _serviceUrl);
}
else if (!string.IsNullOrEmpty(_iamApikey))
{
// Authenticate using iamApikey
TokenOptions tokenOptions = new TokenOptions()
{
IamApiKey = _iamApikey,
IamUrl = _iamUrl
};
credentials = new Credentials(tokenOptions, _serviceUrl);
// Wait for tokendata
while (!credentials.HasIamTokenData())
yield return null;
}
else
{
throw new WatsonException("Please provide either username and password or IAM apikey to authenticate the service.");
}
_service = new Assistant(credentials);
_service.VersionDate = _versionDate;
SessionCreate();
}
private void SessionCreate()
{
Log.Debug("ExampleAssistantV2.Examples()", "Attempting to CreateSession");
_service.CreateSession(OnCreateSession, OnFail, _assistantId);
}
private void Examples()
{
Log.Debug("ExampleAssistantV2.Examples()", "Attempting to Message");
MessageInput mi = new MessageInput(); // construct a messgae input
//mi.Text = query.textComponent.text;
mi.Text = testQueryList[queryNum];
MessageRequest messageRequest = new MessageRequest() // construct a message request
{
Input = mi
};
Log.Debug("ExampleAssistantV2.OnDeleteSession()", "<b>Query: </b> <b>{0}</b>", messageRequest.Input.Text);
_service.Message(OnMessage, OnFail, _assistantId, _sessionId, messageRequest); // send a message request
}
private void OnMessage(MessageResponse _response, Dictionary<string, object> customData)
{
//response.text = _response.Output.Generic[0].Text; // trying to get response
string assistantResponse = _response.Output.Generic[0].Text; // trying to get response
Log.Debug("ExampleAssistantV2.OnDeleteSession()", "<b>RESPONSE: </b> <b>{0}</b>", assistantResponse);
queryNum++;
}
private void OnCreateSession(SessionResponse response, Dictionary<string, object> customData)
{
Log.Debug("ExampleAssistantV2.OnCreateSession()", "Session: <b>{0}</b>", response.SessionId);
_sessionId = response.SessionId;
}
private void OnFail(RESTConnector.Error error, Dictionary<string, object> customData)
{
Log.Debug("ExampleAssistantV2.OnFail()", "Call failed: {0}: {1}", error.ErrorCode, error.ErrorMessage);
}
public void PingAssitant()
{
Examples();
}
}
}

UCMA Generic QuestionAnswer activity

I am working on a UCMA 3.0 workflow application and am attempting to generate queries into our client management system allowing end users to obtain data about specific clients via voice or instant message. I was wondering anyone knows how to create a generic questionanswer activity using UCMA that allows generic input. I know that I can set up expected inputs and grammars, but with the bi-capitalization options, and the likelihood that an end user would know the exact client name (or client number for that matter), I would prefer to allow the user to enter part of the name and then search the database for a list of names that might meet the criteria. Does anyone know of a way, and have sample code that might allow me to do this if it is possible?
I had the same problem and had to write a custom activity to capture generic input from a user. This needs some work to make it production ready. Note the classy catching of system.exception in multiple places, as well as throwing an exception if input isn't received within the timeout period instead of reprompting the user. Also no regex on the user input...
The InstanceDependencyProperty is something else that was frustrating about Workflow. Without using InstanceDependencyProperties you won't be able to retrieve any results after the activity is completed.
Hope this helps!
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using Microsoft.Rtc.Collaboration;
using Microsoft.Rtc.Workflow.Activities;
using Microsoft.Rtc.Workflow.Common;
namespace ActivityLibrary
{
public partial class CaptureIMInput : Activity, IInstanceDependencyContainer
{
#region Private member variables
private CallProvider _callProvider;
private Timer _maximumTimer;
private string _imText;
private bool messageReceived = false;
private bool _maximumTimerElapsed = false;
#endregion
public CaptureIMInput()
{
InitializeComponent();
_instanceDependencyProperties = new Dictionary<string, object>();
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
try
{
this._callProvider = Utilities.GetCallProviderFromParent<InstantMessagingCall>(this);
InstantMessagingCall call = (InstantMessagingCall)this._callProvider.Call;
try
{
if (call.State == CallState.Established)
{
call.Flow.EndSendInstantMessage(call.Flow.BeginSendInstantMessage(MainPrompt, null, null));
_maximumTimer = new Timer(new TimerCallback(OnMaximumTimerFired), null, MaximumPrompt, new TimeSpan(0, 0, 0, 0, -1));
call.Flow.MessageReceived += this.InstantMessagingFlow_MessageReceived;
while (!messageReceived)
{
if (_maximumTimerElapsed)
throw new TimeoutException("User input was not detected within alloted time");
}
if (!string.IsNullOrEmpty(_imText))
{
IMText = _imText;
{
this.Stop();
return ActivityExecutionStatus.Closed;
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
catch (Exception ex)
{
throw ex;
}
return ActivityExecutionStatus.Closed;
}
protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext)
{
this.Stop(); //Clean up timer
return ActivityExecutionStatus.Canceling;
}
private void Stop()
{
if (_maximumTimer != null)
{
_maximumTimer.Dispose();
_maximumTimer = null;
}
}
private void InstantMessagingFlow_MessageReceived(object sender, InstantMessageReceivedEventArgs e)
{
//Can't set dependencyproperties directly from sub-thread
_imText = e.TextBody;
//Mark bool so main while loop exits
messageReceived = true;
}
//Callback to
private void OnMaximumTimerFired(object state)
{
_maximumTimerElapsed = true;
}
#region InstanceDependency dictionary
private Dictionary<string, object> _instanceDependencyProperties;
[Browsable(false)]
public Dictionary<string, object> InstanceDependencyProperties
{
get { return _instanceDependencyProperties; }
}
#endregion
#region Maximum Prompt Timeout
[NonSerialized]
private static readonly InstanceDependencyProperty MaximumPromptProperty = InstanceDependencyProperty.Register("MaximumPrompt", typeof(TimeSpan), typeof(CaptureIMInput), new TimeSpan(0, 0, 30));
[TypeConverter(typeof(TimeSpanConverter))]
public TimeSpan MaximumPrompt
{
get
{
if (base.DesignMode)
return (TimeSpan)InstanceDependencyHelper.GetValue<CaptureIMInput>(this, MaximumPromptProperty);
else
return (TimeSpan)InstanceDependencyHelper.GetValue<CaptureIMInput>(this, this.WorkflowInstanceId, MaximumPromptProperty);
}
set
{
if (base.DesignMode)
InstanceDependencyHelper.SetValue<CaptureIMInput>(this, MaximumPromptProperty, value);
else
InstanceDependencyHelper.SetValue<CaptureIMInput>(this, this.WorkflowInstanceId, MaximumPromptProperty, value);
}
}
#endregion
#region MainPrompt
public static DependencyProperty MainPromptProperty =
DependencyProperty.Register("MainPrompt", typeof(string), typeof(CaptureIMInput));
[ValidationOption(ValidationOption.Required)]
public string MainPrompt
{
get
{
return (string)base.GetValue(MainPromptProperty);
}
set
{
base.SetValue(MainPromptProperty, value);
}
}
#endregion
#region Instant Message Text
public static InstanceDependencyProperty IMTextProperty =
InstanceDependencyProperty.Register("IMText",
typeof(string),
typeof(CaptureIMInput));
[Description("InstantMessaging Text from user")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string IMText
{
get
{
if (base.DesignMode) return ((string)InstanceDependencyHelper.GetValue<CaptureIMInput>(this, CaptureIMInput.IMTextProperty));
else return ((string)(InstanceDependencyHelper.GetValue<CaptureIMInput>(this, this.WorkflowInstanceId, CaptureIMInput.IMTextProperty)));
}
set
{
if (base.DesignMode) InstanceDependencyHelper.SetValue<CaptureIMInput>(this, CaptureIMInput.IMTextProperty, value);
else InstanceDependencyHelper.SetValue<CaptureIMInput>(this, this.WorkflowInstanceId, CaptureIMInput.IMTextProperty, value);
}
}
#endregion
}
}