1

I'm trying to get the context variables that I made in Watson Conversation Dialogs in my Unity project. I am able to get the whole JSON dialog to show up in Unity, get the intents, entities and output text from the json file. So instead of getting the output:{ text[] out of the json file, I'm trying to get the context:{ variable:value out of the JSON file but I can't get my head around how.

This is the JSON file for the welcome dialog node where i want to read the destination_city variable out of to set it equal to an Unity variable/string.

{
   "context": {
     "date": null,
     "time": null,
     "hotel": null,
     "DateEnd": null,
     "DateBegin": null,
     "PeriodDate": null,
     "numberKids": null,
     "roomsHotel": null,
     "PeriodNumber": null,
     "numberAdults": 0,
     "departure_city": null,
     "transportation": null,
     "destination_city": "London",
     "kidDiscountRepeat": null
   },
   "output": {
     "text": {
       "values": [
         "Hello, this is the Watson Travel agency."
       ],
       "selection_policy": "sequential"
     }
   }
 }

And this is part of the code I have in Unity to get a response from Watson conversation and show the whole JSON file for that dialog node:

void HandleMessageCallback (object resp, Dictionary customData) 
{ object _tempContext = null; (resp as Dictionary ).TryGetValue("context", out _tempContext);

     if (_tempContext != null)
         conversationContext = _tempContext as Dictionary<string, object>;

     Dictionary<string, object> dict = Json.Deserialize(customData["json"].ToString()) as Dictionary<string, object>;

     // load output --> text;answer from Json node
     Dictionary <string, object> output = dict["output"] as Dictionary<string, object>;
     List<object> text = output["text"] as List<object>;
     string answer = text[0].ToString();
     Debug.Log("WATSON | Conversation output: \n" + answer);

     //======== Load $ context variable attempts =============================
     Debug.Log("JSON INFO: " + customData["json"].ToString());
     //=====================================

     if (conversationOutputField != null)
     {
         conversationOutputField.text = answer;
     }
  • `text[0]` should be `values`, if you want what is inside, you should probably try `text[0][0]` which should give you `"Hello, this is the Watson Travel agency."`. You should also look into `Foreach` since you are making everything an `ICollection`, you won't have to hassle yourself with managing indices. Also, I never see `conversationOutputField` being initialized anywhere, what is it's value ? – Antry Mar 14 '18 at 13:30
  • Thank you for your help, but I already can acces and show the "Hello, this is the Watson Travel agency" part. What I'm trying to acces is the destination city: "London" part. – grunter-hokage Mar 15 '18 at 10:50
  • You already have `dict` you should be able to access if with `var myCity = dict["context"]["destination_city"] as Dictionary;` – Antry Mar 15 '18 at 10:55
  • That doesn't work. I get the error: cannot apply indexing with [] to an expression of type 'object' – grunter-hokage Mar 15 '18 at 11:03
  • Oh i'm sorry I went too fast x) Yeah it's `var context = dict["context"] as Dictionary` you should then be able to access it with `context["destination_city"]` – Antry Mar 15 '18 at 11:08
  • got it working ? – Antry Mar 15 '18 at 11:33
  • No, I get an Nullreference error now. So I think it can't find the destination_city variable in it. I've added these lines: `var context = dict["context"] as Dictionary; Debug.Log("city: "+ context["destination_city"]);` – grunter-hokage Mar 15 '18 at 12:14
  • Hmm try keeping it as `Dictionary;` . I know we are really not far, but i'm at work without unity and am doing it all by head :| but I think you should look into the unity [JsonUtility](https://docs.unity3d.com/Manual/JSONSerialization.html) which lets you serialize to and from json, so you can create C# classes who represent how you want your data, and you can swap to either access it as a Class in C# or make into Json. – Antry Mar 15 '18 at 12:56
  • No problem, I appreciate the help and will take a look at it and try to work with it. Thank you! – grunter-hokage Mar 15 '18 at 12:58
  • I'm glad I can help, but even if you get it working the way you are doing it currently, it really feels heavy and not scalable, so it'd be better if you were able to create class models for it :P It'll also simplify your life so much once you need to access them – Antry Mar 15 '18 at 13:00
  • You are probable right. This is my first time trying to connect Watson conversation Service to Unity and to work with REST Api's and JSON, so I'm still trying to find my way in it and will do my best to optimize it. And keeping it as `Dictionary;` helped, I get the desired result now! So can you post that block of code as the answer, so I can accept it as the answer? :) – grunter-hokage Mar 15 '18 at 13:05
  • Ok, give me a minute ! and If you have any difficulty implementing it at any level whatsoever, [@Programmer made a very good post detailing all the types of operations](https://stackoverflow.com/a/36244111/5873815) you might need/come across – Antry Mar 15 '18 at 13:06
  • I have updated my Answer with most of the information I had gathered aswell as a small explenation wrapping the Unity JsonSerialization Examples – Antry Mar 15 '18 at 13:34

1 Answers1

2

Solution 1 : Keeping your code

Taking your current code, you should be able to access your context with

var context = dict["context"] as Dictionary<string, object>

Now that you have your context, you can access it's content in the same way

var mycity = context["destination_city"]

Conclusion 1

Even though this does work, if you are setting up a solution where you are going to manipulate/access Json, I highly advise making models of your data to serialize to and from, for this, check out Unity's JsonUtility (Json Serialization)

Solution 2 : Serialize C# Objects to and from Json

Let's take Unity's Manual example:

Data Model Class

First, we create a Model class of the Json information that we want, in this case, we want information about our player, for this we create 3 fields, int level, float timeElapsed and string playerName.

[Serializable]
public class MyClass
{
    public int level;
    public float timeElapsed;
    public string playerName;
}

Data initialization

Here we create a new Instance of our class MyClass called myObject and manually set it's fields values (in fact, how you set the values is not really important here)

MyClass myObject = new MyClass();
myObject.level = 1;
myObject.timeElapsed = 47.5f;
myObject.playerName = "Dr Charles Francis";

Serializing your class to Json

To serialize your myObject just pass it to JsonUtility's .ToJson method as parameter

string json = JsonUtility.ToJson(myObject);

Now, we have our class's object equivalent as a Json string:

{"level":1,"timeElapsed":47.5,"playerName":"Dr Charles Francis"}

Generating Json from your class

If you want to populate your C# Object with the data from your Json, you can do so by calling JsonUtility's .FromJson<TypeOfTheClassImMappingTo> Method and passing it the json string as parameter.

myObject = JsonUtility.FromJson<MyClass>(json);

These are only basic operations and the surface of what you could do with JsonUtility's Class/Json serialization

Conclusion 2

This solution is a lot more maintainable. You can extend it to use any number of model types, and have the advantage and ease of navigation of C# objects. This is particularly interesting to create systems which will use your Data Objects.

If you have questions about Json Utility, like how to manage arrays, nested data etc.. I highly advise taking a couple of minutes to read through @Programmers Answer about JsonUtility practices.

Ressources

[Unity - Manual] JsonUtility / JsonSerialization

[StackOverflow] Serialize and Deserialize Json and Json Array in Unity

Antry
  • 448
  • 3
  • 9