In this blog series we’ll have a look at an example I built in Python that uses Azure Cognitive Services and Azure Storage.

First of all what is Azure Cognitive Services?  In Microsoft’s own words is a set of API calls to embed the ability to see, hear, speak, search, understand and accelerate decision-making into your apps. Technically Personaliser does  sit under the Azure Cognitive Services umbrella but Microsoft is trying to market this as a stand alone service, it is defined as an API services that offers the ability to prioritise content, layouts and conversations through reinforcement learning. In other words is a recommendation system, like when on YouTube you watch a video and then similar ones are recommended.

This simple python application is structured like this

 

There are three python files each with a diffrent function:

  • AZStorageConnector.py takes care of handling any request to Blob Storage, from reading files (in our case images) to inserting rows in a CosmosDB table
  • ImageReader reads all images saved in the file share and pass them on to the Compuer Vision API which returns a brief description of the image that is then saved on a CosmosDB table
  • Personaliser.py supplies the image descriptions to the Personaliser API which returns the name of an image which it thinks is most likely to interest the user

 

Azure (Cognitive Services) Personaliser.

Needless to say you need to have an Azure account and subscription or you must create one for free with a trial included.

Once that’s done click here and create the resource, you need to specify:

  • Name of the resource (this can be anything you want)
  • Subscription you want to use (or pay as you go)
  • Location
  • Pricing tier
  • Resource group (It’s handy to have all resources used in this demo under the same group)

Next go to the Azure portal and access the Personaliser resrouce, from there you need the following

  • Endpoint (from the overview)
  • One of the the two keys

Before we start coding we need to create two environment variables in windows, one called PERSONALISER_KEY and another PERSONALISER_ENDPOINT which will contain, respectively, the key and the endpoint we just retrieved.

from azure.cognitiveservices.personalizer import PersonalizerClient
from azure.cognitiveservices.personalizer.models import RankableAction, RewardRequest, RankRequest
from msrest.authentication import CognitiveServicesCredentials
from AZStorageConnector import AZStorageConnector
import ast

import datetime, json, os, time, uuid

try:

    key_var_name = 'PERSONALISER_KEY'
    aZStorageConnection = AZStorageConnector()
    blobList = aZStorageConnection.blobReader()

    if not key_var_name in os.environ:
        print
        raise Exception('Please set/export the environment variable: {}'.format(key_var_name))
    personalizer_key = os.environ[key_var_name]

    # Replace <your-resource-name>: https://<your-resource-name>.api.cognitive.microsoft.com/
    endpoint_var_name = 'PERSONALISER_ENDPOINT'
    if not endpoint_var_name in os.environ:
        raise Exception('Please set/export the environment variable: {}'.format(endpoint_var_name))
    personalizer_endpoint = os.environ[endpoint_var_name]
except Exception as e:
    print("exception message:"+ str(e))
    input("Press Enter to continue...")

# Instantiate a Personalizer client
client = PersonalizerClient(personalizer_endpoint, CognitiveServicesCredentials(personalizer_key))

def get_actions():
    actions = []
    row = aZStorageConnection.tableReader()

    for  r in row:
        actions.append(RankableAction(id= r.imgDesc, features=[ast.literal_eval(r.tags)]))
    # action4 = RankableAction(id='salad', features=[{'taste':'salty', 'spice_level':'none'},{'nutritional_level': 2}])
    return actions


def get_user_preference():
    res = {}
    features = []
    row = aZStorageConnection.tableReader()

    for  r in row:
        tags = ast.literal_eval(r.tags)
        for value,key in tags.items():
            features.append(key)
    features = list(dict.fromkeys(features))
    for i in range(len(features)):
        print(str(i+1) +" - "+features[i])
    pref = input("What image feature would you prefer? Enter number\n")
    
    try:
        ppref = int(pref)
        if(ppref<=0 or ppref>len(features)):
            raise IndexError
        res['taste_preference'] = features[ppref-1]
    except (ValueError, IndexError):
        print("Entered value is invalid. Setting feature value to", features[0]+ ".")
        res['taste_preference'] = features[0]
    return res


# create the learning loop
keep_going = True
while keep_going:

    eventid = str(uuid.uuid4())

    context = [get_user_preference()]
    actions = get_actions()

    try:
        rank_request = RankRequest( actions=actions, context_features=context, event_id=eventid)
        response = client.rank(rank_request=rank_request)
    except Exception as e:
        print("exception message:"+ str(e))
        input("Press Enter to continue...")
    
    print("Personalizer service ranked the actions with the probabilities listed below:")
    
    rankedList = response.ranking
    for ranked in rankedList:
        print(ranked.id, ':',ranked.probability)

    print("Personalizer thinks you would like to have", response.reward_action_id+".")
    answer = input("Is this correct?(y/n)\n")[0]

    reward_val = "0.0"
    if(answer.lower()=='y'):
        reward_val = "1.0"
    elif(answer.lower()=='n'):
        reward_val = "0.0"
    else:
        print("Entered choice is invalid. Service assumes that you didn't like the recommended food choice.")

    client.events.reward(event_id=eventid, value=reward_val)

    br = input("Press Q to exit, any other key to continue: ")
    if(br.lower()=='q'):
        keep_going = False

#request a rank

rank_request = RankRequest( actions=actions, context_features=context, excluded_actions=['juice'], event_id=eventid)
response = client.rank(rank_request=rank_request)
print("response="+response)
input("Press Enter to continue...3")

#send a reward

reward_val = "0.0"
if(answer.lower()=='y'):
    reward_val = "1.0"
elif(answer.lower()=='n'):
    reward_val = "0.0"
else:
    print("Entered choice is invalid. Service assumes that you didn't like the recommended food choice.")

client.events.reward(event_id=eventid, value=reward_val)