More servicesWindows Live
HomeHotmailSpacesOneCare
 
MSN
Sign in
 
 
Spaces home  Windows Live AgentsPhotosProfileFriendsMore Tools Explore the Spaces community

Windows Live Agents

Conversational applications for the web and IM--Official Site for Windows Live Agents
May 15

Adding a Usage Report to the Console

The standard reporting suite on the Knowledge Management Console covers the most important metrics -- Unique Users, Total Sessions, etc. However, you'll often want (or be asked) to provide additional reports based on the special needs of the customer and/or the particular tasks of the agent. This article won't cover all the details of configuring usage reports, but will hopefully demonstrate how to log a simple data point and have it show up on the console as a graph or table.
 
Before configuring usage, we should look briefly at how logging works. The agent's log is an object variable called SYS.Log -- anything written there is a candidate to show up in usage reports. This is completely separate from the User Profile: the agent may store the user's birthplace in a variable called G_USER.birthplace, but it won't show up in usage unless we also write it to, for example, SYS.Log.birthplace. It is also completely separate from the server component logs on the console.
 
So let's actually use birthplace as our example, and look at what we need to record and display that statistic.
 
Say we have a procedure called CollectBirthplaceFromUser() that takes care of collecting the user's birthplace and resolving it into a valid place name we can record.
 
procedure CollectBirthplaceFromUser()
  BIRTHPLACE = ""
  [...]
  call WriteBirthplaceToProfile(BIRTHPLACE)
  call LogBirthplace(BIRTHPLACE)
 
WriteBirthplaceToProfile assigns the value of BIRTHPLACE to G_USER.birthplace. LogBirthplace writes the same value to the SYS.Log.birthplace variable.
 
procedure LogBirthplace(BIRTHPLACE)
  SYS.Log.birthplace = BIRTHPLACE
 
Now that we're confident birthplaces are being collected and logged, let's move on to configuring Usage. We do this by editing a file at the root directory of the project, called usage_config.xml.
 
usage_config.xml controls the presentation of log data in the Usage Reports section of the console.  It's completely separate from the actual logging of data -- we can log something in the BuddyScript, for example, but not add the necessary sections in usage_config.xml for another month, at which point the data the agent has been logging for the last month will be displayed. However, the opposite is not true -- adding a section in usage_config.xml doesn't cause data to be collected.
 
There are two main parts: a "sections" element containing all the configuration options for the usage reports, and a "usagestats" element containing the variables and datapoints to be used in the sections element.
 
The sections element itself contains two subsections labeled "all_ids" and "individual_id", which correspond to views of usage statistics broken out by individual buddyid or all buddyid's combined, exposed as a drop-down list in the console. First we'll look at the all_ids section, which is somewhat simpler than the individual_id section.
 
The first section here is called Volume Summary, and contains a number of elements for reporting usage data. You can get a good idea of the syntax we'll be using later by examining this section.
 
 <section name="Volume Summary" id="volume_summary" shared-graph-type="barline" shared-graph-title="Usage">
  <element name="Total Queries" key="message_count" calc-type="normal" default-graph-state="on" graph-type="shared"/>
  <element name="Total Sessions" key="session_count" calc-type="normal" default-graph-state="on" graph-type="shared"/>
  <element name="Unique Users" key="unique_users" calc-type="normal" default-graph-state="off" graph-type="none"/>
  <element name="New Users" key="new_users" calc-type="normal" default-graph-state="off" graph-type="shared"/>
  <element name="Average Queries Per Session" key="message_count" calc-type="per" subkey="session_count" graph-type="shared"/>
  <element name="Average Sessions Per Unique User" key="session_count" calc-type="per" subkey="unique_users" graph-type="none"/>
  <element name="Average Session Length (in seconds)" key="total_session_length" calc-type="per" subkey="session_count" graph-type="shared"/>
 </section>
 
The "name" identifier is the text displayed on the console, the "key" is the datapoint, "calc-type" can be normal or something else depending on whether we want to perform some math on the number before displaying it, "subkey" is the other datapoint to use when calc-type is not normal, "default-graph-state" toggles whether a particular element shows up on the graph, "graph-type" controls what kind of graph, if any, to display the data on. In this case, multiple elements are sharing a "barline" graph -- a combination bar graph and line graph where the user selects which data goes on the bar, and which goes on the line.
 
We could add our own section for birthplace, but it turns out there is already a section for demographics, so we'll just add an element within that section:
 
  <element name="Birthplace Distribution" key='[birthplace][%]' keyName="Birthplace" valueName="Sessions" calc-type="distribution" graph-type="pie" display-type="percentage"/>     
 
This will pull all the values of SYS.Log.birthplace and display them in a pie graph, distributed by the number of sessions they occur in, along with a key. ("name", "keyName", and "valueName" are all labels and have no effect on the display of the data.) [%] represents a wildcard, meaning "all values of birthplace" -- we could choose instead to report on only [birthplace]['New York'], for example. 
 
Since there are potentially a large number of birthplaces (depending on how smart CollectBirthplaceFromUser is), it probably makes sense to dispense with the graph, and just display a table:
 
  <element name="Birthplace Distribution" key='[birthplace][%]' keyName="Birthplace" valueName="Sessions" calc-type="distribution" display-type="percentage"/>     
 
That's all we need to do for the all_ids section. For the individual_ids section, because we'll be filtering by buddyid, we need to go to the bottom of the file and add a datapoint:
 
        <var name="userBirthplace" default="">value('[birthplace]')</var>
  <datapoint buckets="+hour" key="sessions where userBirthplace=${userBirthplace};buddyid=${buddyid}">
    <filter>userBirthplace != ''</filter>
  </datapoint>
 
First we create a variable called userBirthplace, which is assigned the value of SYS.Log.birthplace. Then we create an hourly bucket for that data with a key for pulling the number of sessions within a particular buddyid where a particular birthplace was recorded. In the demographics section of the individual_id section, we'll add this:
 
  <element name="Birthplace Distribution" key='sessions where userBirthplace=%;buddyid=%var:buddyid%' keyName="Birthplace" valueName="Sessions" calc-type="distribution" display-type="percentage"/>     
 
This is similar to the element we created for the all_ids section, but birthplace (userBirthplace=%) and buddyid (buddyid=%var:buddyid%) are interpolated into their actual values, and we see only the number of sessions for a birthplace recorded for the buddyid currently selected. Now we can use the buddy dropdown on the console as a filter.
 
In practice, displaying a list of arbitrary names of places is not going to be very useful because there are many thousands of place names the user can enter. We'd probably want to constrain the list to countries, states, or other large areas, depending on the mission of the agent. Still, this example will hopefully get you started experimenting with Usage, which is the best way to learn. Chances are, usage_config.xml probably already contains most of the necessary pieces for whatever report you need to create.
May 12

New version of the Platform and SDK coming soon

Hi All,
 
I know a lot of folks have been waiting diligently for the new version of the SDK.  We have finished the product and are in the midst of deploying the platform in our data center now.  Once we get the final approval from Operations, we'll publish a link to the SDK and you'll be on your way!
 
Thanks for you patience and we look forward to you using the SDK!
 
Windows Live Agents team
April 25

BuddyScript Subpatterns

Subpatterns are much like functions in that they can be used as filters for data -- one value is passed in, evaluated, and another possibly different value is returned. That's why we can do things like this:
 
subpattern Basketball
+ (basketball|basket ball)
+ (b ball|bball) {MACRO_SYN}
+ (hoops|one on one|1 one 1) {MACRO_WEAK_SYN}
  return "basketball"
 
subpattern Baseball
+ (baseball|base ball)
+ ball {MACRO_WEAKER_SYN}
  return "baseball"
 
subpattern ASport
+ VAR=Basketball
+ VAR=Baseball
  return VAR
 
+ i like SPORT=ASport
  - I like SPORT too!
 
User: i like bball
Agent:  I like basketball too!
 
Let's look at a slightly different kind of subpattern.
 
stored variable G_DESSERTS
 
function DessertIsOnMenu(DESSERT_NAME)
   return Exist(G_DESSERTS[DESSERT_NAME])
 
subpattern Dessert
  if DessertIsOnMenu(VALUE)
    return 100
  return 0
 
The Dessert subpattern above is a BuddyScript subpattern -- a subpattern that returns its match score based on some logic defined within it.  VALUE is a special variable made available for this kind of subpattern and contains the token being evaluated -- here it is passed to the DessertIsOnMenu function, which returns true if the parameter it receives exists as a key in the G_DESSERTS object. If this is the case, the token will match to Dessert with a score of 100.
 
Using BuddyScript subpatterns enables scenarios in which you can match in a dynamic way, tightly controlling how matches are evaluated and scored.
April 23

Microsoft Partner Program

Hello Developers,

 

As we are nearing the public release of our new Visual Studio SDK and Partner on-boarding system, we wanted to make sure that we expose our developers to all the benefits from Microsoft in terms of certifications.  We realize there are a large number of Agent developers that make their business through the Agent platform and we are working closely with the rest of Windows Live Platform to get you the recognition you need with your customers.  In the future, Windows Live will have a program specifically within the Microsoft Partner Program (MSPP) and you’ll be able to fully leverage that designation.  Membership in MSPP is free with graduated levels of certification (fee and skill based).   In the past, there was a notion of “MSN Bot Certified”, but because of business and technology reasons, this designation has essentially expired and won’t be recognized by Microsoft.  Windows Live is moving forward with MSPP as the official method of partnering and we encourage you to start MSPP enrollment at your earliest convenience. 

 

We look forward to building out this developer community with you!

April 17

So, you think you know everything about Buddyscript?

So, you think you know everything about Buddyscript?

 

Well, let’s see how much of such a statement is true. Try to answer this short quiz! If you score all of them it doesn’t mean you are an expert, but you could say you are getting there ;-)

 

1-    Let’s talk about matching. Say we want to match precisely on full URLs (and only full URLs) during a conversation, which one of the following cases would be the way to go:

a)    subpattern AFullUrl /^www`.`S+`.(com|fr|org|net)$/ {minlength=3, example=”www.microsoft.com”}

b)    subpattern AFullUrl + www =Anything (com|fr|org|net) {canskip=”no”, minlength=3}

c)    subpattern AFullUrl www.=Anything.(com|fr|org|net) {canskip=”no” minlength=3}

 

2-    Nl-bricks? Only one of the following affirmations is true:

a)  “NL- bricks” along with “regular subpatterns” are processed during the “patternization” process, but “NL-bricks” have precedence over “regular subpatterns”.

b)  “NL- bricks” are the minimum expression of a meaning unit, and are “patternized” into “regular subpatterns” at compile time.

c)  “NL-bricks” are “skippable”, as opposed to “regular subpatterns” that need to have the property {canskip=”yes”}

 

3-    Defining macros in Buddyscript, only one of the following statements is true:

a)    If the code contains any line breaks, it should be placed immediately below the first line of the statement. If you want your macro to contain an empty line, add a line containing only the character “\”. The first empty line defines the end of the macro.

b)    If you want your macro to contain an empty line, add a line containing the character “\” at the end of the line before. I will add an empty line right between this and the following line. The first empty line defines the end of the macro.

c)    Macro definitions can’t contain line breaks. The first empty line defines the end of the macro.

 

4-    Only one of the following statements is true:

a)    The “always match as” statement allows you to associate a variable name with a particular subpattern throughout a group of patterns only.

b)    The “always match asstatement allows you to associate a variable name with a particular subpattern throughout a group of patterns, a package, or an entire domain.

c)    The “always match as” statement allows you to associate a variable name with a particular subpattern in a routine, or in a multi-line of code.

 

5-    What do you know about composite subpatterns? Only one of the following is true!

a)    Composite sub-patterns let you assemble multiple static subpatterns together, so that a candidate string is filtered through the first subpattern, then the result of this filtering is passed to the second one, etc.

b)    The minimum number of compositions is one, but there’s not a limit on the maximum number of compositions you can add.

c)    The default values for the properties of a composite subpattern are those of the outer-most subpattern, since it's going to be evaluated last.

 

6-    Hum, have you ever tried to create datasources? Let’s see if you know which one of the following is true:

a)    The “postprocess-block“ of a datasource is a BuddyScript routine used to set the offset and the total count of rows when the “preprocess-block” didn't return any of those values, or if the value returned is not accurate.

b)    “Expire” is a common property to the different datasource kinds. This information allows the platform to remember (cache) the result for a certain time. By default, expire is set to “now” (information is not stored). If you want the information to be cached, set it to “never”, or when the information won't be valid anymore (in 5 minutes, in 2 days, etc.)

c)    Datasources are BuddyScript tools to access external data. The external data retrieved can be accessed through many methods, including gateway calls, SQL queries, SOAP methods, datatables, etc.

 

7-    How about rephrasing rules? We want to use the property “MACRO_BEST_ONLY” when:

a)    We need to make sure the rule it’s only applied when it matches best from all of the other rephrasing rules.

b)    We want the rule to be applied only when it matches best, and no other rule can be applied after.

c)    We want to avoid matching on rules scoring lower than 80.

 

Solutions: 1-a, 2-b, 3-a, 4-b, 5-b, 6-c, 7-a

 If you failed the quiz, and you want to know more about Buddyscript, besides this blog you can browse the Windows Live Agents forum in MSDN, and of course read the documentation shipped with the platform.

View more entries