def bestPhoneticMatch(searchstr, choices, maxdistance): #-------------------------------------------------------------------------- # finds the best phonetic match for "searchstr" amongst a number of # strings stored in the array 'choices' # This is optimized for German names only. # if the best match is still > maxdistance, no result is returned. # to retrurn the best match irrepective of distance, use axdistancce = -1 # # The distance is calculated by calculating the levinsthein distance # between the phonetic encoding using "Kölner Phonetic #-------------------------------------------------------------------------- searchphon = encode_cgnph(searchstr) if maxdistance < 0: maxdistance = len(searchphon) mindistance = maxdistance bestmatch = "" searchphon = encode_cgnph(searchstr) for checkstring in choices: checkphon = encode_cgnph(checkstring) d = levenshtein(searchphon, checkphon) myask_log.debug( 9, "phonetic Dist : " + str(d) + " = " + searchstr + "(" + searchphon + ") - " + checkstring + "(" + checkphon + ")") if d < mindistance: mindistance = d bestmatch = checkstring elif d == mindistance: # calculate the smaller levinstein distance on the orthography if (levenshtein(searchstr, checkstring) < levenshtein( searchstr, bestmatch)): bestmatch = checkstring myask_log.debug(9, "BEST match: '" + bestmatch + "'") return bestmatch
def WriteCorpusToFile(corpus, outputfile): #-------------------------------------------------------------------------- # writes all utternaces of the corpus to 'outputfile' # If 'outputfile' is empty, prints to STDOUT # returns number of samples generated #-------------------------------------------------------------------------- samplecount = 0 if outputfile == "": # print to STDOUT instead for intent in corpus: intent_sentences = corpus[intent] for i in range(len(intent_sentences)): line = intent + " " + intent_sentences[i] print line samplecount += 1 else: myask_log.debug( 5, "Writing sample utterances to file '" + outputfile + "'") fout = open(outputfile, 'w+') for intent in corpus: intent_sentences = corpus[intent] for i in range(len(intent_sentences)): line = intent + " " + intent_sentences[i] fout.write(line + "\n") samplecount += 1 fout.close() return samplecount
def store_session_slots(intent, slotlist, slots): # Stores selected information from the current state in the session cookie # This info will be available next time # intent: name of the active intent ("" if none) # slotlist: list of slotnames, for which the infor shall be stored # slots current slot values #------------------------------------------------------------------------------- myask_log.debug(3, "storing session attributes for intent "+str(intent)) session_attributes = {} if intent != "": session_attributes['prev_intent'] = intent for slotname in slotlist: if slotname in slots: val = slots[slotname] slottype = type(val) if isinstance(val, datetime): session_attributes[slotname] = "DATE:"+val.strftime('%Y-%m-%d') elif isinstance(val, date): session_attributes[slotname] = "DATE:"+val.strftime('%Y-%m-%d') elif slottype == list: # todo: print/read sequence session_attributes[slotname] = str(slots[slotname]) elif slottype == int: session_attributes[slotname] = str(slots[slotname]) else: session_attributes[slotname] = str(slots[slotname]) if slotname+".literal" in slots: session_attributes[slotname+".literal"] = slots[slotname+".literal"] return session_attributes
def _touchProfile(self, userid): response = self._table.update_item( Key={'UserID': userid}, UpdateExpression="set NumQueries = NumQueries + :val, LastQuery = :t", ExpressionAttributeValues = { ':val': decimal.Decimal(1), ':t' : get_date_str() }, ReturnValues="UPDATED_NEW") myask_log.debug(5, "Updating UserProfileTimeStamps: " + str(response)) return True
def AddNonterminalRule(nonterminal, ntrule, non_terminal_list): myask_log.debug( 5, "adding non-terminal '" + nonterminal + "' Rule: '" + ntrule + "'") nt_elements = ntrule.split("|") for counter in range(len(nt_elements)): nt_elements[counter] = nt_elements[counter].strip(" ") if nonterminal in non_terminal_list: non_terminal_list[nonterminal].append(nt_elements) else: non_terminal_list[nonterminal] = nt_elements return True
def FetchUserProfile(self, userid): #----------------------------------------------------------------------- # returns the "profile" part of a given user profile # if the user profile does not exist, profile is {} #----------------------------------------------------------------------- if self._table == "": myask_log.error("fetchUserProfile: attempted without valid table") return {} try: response = self._table.get_item(Key={'UserID': userid}) except ClientError as e: myask_log.error("fetchUserProfile: Error: "+e.response['Error']['Message']) return {} else: if 'Item' in response: if 'Item' in response and 'Profile' in response['Item']: profile = response['Item']['Profile'] if 'debuguser' in response['Item']: myask_log.debug(5, "DEBUGUSER: '******'Item']['debuguser']) +"'") profile['debuguser'] = response['Item']['debuguser'] myask_log.debug(5,"fetchUserProfile: User profile found:"+ str(userid)) # update access log for this user profile self._touchProfile(userid) return profile else : myask_log.debug(5,"fetchUserProfile: Invalid response format: "+ str(response)) return {} else: myask_log.debug(5,"fetchUserProfile: User profile NOT found:"+ str(userid)) return {}
def SetDbType(dbtype, resource=""): global DBTYPE global DBRESOURCE myask_log.debug(3, "myadk_dynamodb.SetDbType: dbtype='"+dbtype+"' resource='"+resource+"'") DBRESOURCE = resource if dbtype == "online": # use dynamo online db DBTYPE = "online" return True elif dbtype == "offline": # use dynamo db installed locally DBTYPE = "offline" return True else: myask_log.error("myadk_dynamodb.SetDbType: invalid dbtype '"+dbtype+"'") return False
def main(): outputfile = "" parser = argparse.ArgumentParser() parser.add_argument("-v", "--verbosity", type=int, help="define output verbosity") parser.add_argument( "-out", "--outputfile", type=str, help="Use local database on the given port on localhost") parser.add_argument("inputfile", help="grammar file as input") args = parser.parse_args() if args.verbosity: myask_log.SetDebugLevel(args.verbosity) if args.inputfile: inputfile = args.inputfile else: inputfile = "input" if args.outputfile: outputfile = args.outputfile else: outputfile = "" myask_log.debug(3, "input: " + inputfile) myask_log.debug(3, "output: " + outputfile) corpus = createSampleUtterancesFromGrammar(inputfile) if outputfile == "": for intent in corpus: intent_sentences = corpus[intent] for i in range(len(intent_sentences)): line = intent + " " + intent_sentences[i] print line else: fout = open(outputfile, 'w+') for intent in corpus: intent_sentences = corpus[intent] for i in range(len(intent_sentences)): line = intent + " " + intent_sentences[i] fout.write(line + "\n") fout.close()
def UpdateUserProfile(self, userid, profile): #----------------------------------------------------------------------- # Updates an existing user profile with the information in "profile" # If the user profile does not exist or cannot beupdated, returns False #----------------------------------------------------------------------- try: response = self._table.update_item( Key={'UserID': userid}, UpdateExpression="set Profile = :p", ExpressionAttributeValues = {':p': profile}, ReturnValues="UPDATED_NEW") except ClientError as e: myask_log.error("UpdateUserProfile: Error: "+e.response['Error']['Message']) return False else: myask_log.debug(2, "UpdateUserProfile: " + str(response)) return True
def GetStatistics(self, userid): created = "" num_queries = -1 last_query = "" if self._table == "": myask_log.error("GetStatistics: attempted without valid table") try: response = self._table.get_item(Key={'UserID': userid}) except ClientError as e: myask_log.error("GetStatistics: Error: "+e.response['Error']['Message']) else: if 'Item' in response: if 'Created' in response['Item']: created = response['Item']['Created'] if 'NumQueries' in response['Item']: num_queries = response['Item']['NumQueries'] if 'LastQuery' in response['Item']: last_query = response['Item']['LastQuery'] else: myask_log.debug(5,"GetStatistics: User profile NOT found:"+ str(userid)) return [created,num_queries,last_query]
def CreateNewTable(tablename): dynamodb = _getDynamoDB() table = dynamodb.create_table( TableName= tablename, KeySchema=[ { 'AttributeName': 'UserID', 'KeyType': 'HASH' #Partition key } ], AttributeDefinitions=[ { 'AttributeName': 'UserID', 'AttributeType': 'S' } ], ProvisionedThroughput={ 'ReadCapacityUnits': 5, 'WriteCapacityUnits': 5 }) table_status = table.table_status myask_log.debug(0, "Created table '"+tablename+"'. Table status:" + table_status) return table_status
def createSampleUtterancesFromGrammar(inputfile): #--------------------------------------------------------------------------- # reads a generation grammar from 'iputfile' and returns # an array of sample utterances created from that grammar #--------------------------------------------------------------------------- input_utterances = {} non_terminal_list = {} # fin = codecs.open(inputfile, "r", "utf-8") fin = open(inputfile, "r") content = fin.readlines() # -------------------------------------------------------------------------- # 1st step: parse input file # parse the input file and create # a dictionary of non-terminals (non_terminal_list) # a list of input utterances (input_utterances) # -------------------------------------------------------------------------- linecount = 0 myask_log.debug(3, "---->>>Parsing input file" + inputfile) for line in content: linecount += 1 line = StripComments(line) if re.match("^\s*$", line): continue blocks = re.match("^\s*(.*)\s*::=\s*(.*)$", line) if blocks: leftside = blocks.group(1) leftside = leftside.strip() rightside = blocks.group(2) rightside = rightside.strip() else: myask_log.error("Invalid Syntax in line '" + line + "'") return () if re.match("<.*>", leftside): # non terminal rule found myask_log.debug( 7, "NON-TERMINAL '" + leftside + "' found in line " + str(linecount)) AddNonterminalRule(leftside, rightside, non_terminal_list) else: AddIntentRule(leftside, rightside, input_utterances) myask_log.debug(3, "---->>>Parsing done. " + str(linecount) + " lines read") fin.close() # -------------------------------------------------------------------------- # 1nd step: create all possible output sentence # loop over all input utterances # For each inout utterance, create variants for all possible (combinations of) # non-terminal symbols and optional phrases # -------------------------------------------------------------------------- training_corpus = {} linecount = 0 for intent in input_utterances: training_corpus[intent] = [] for input_sentence in input_utterances[intent]: linecount += 1 myask_log.debug( 3, "Processing line (" + intent + ") '" + str(input_sentence) + "'") input_words = input_sentence.split(" ") line_alternatives = ProcessLine(input_words, non_terminal_list) for training_sentence in line_alternatives: myask_log.debug(5, "-> " + training_sentence) training_corpus[intent].extend(line_alternatives) return training_corpus
def parse_slots(intent, session, continue_session, input_locale, appdef): #--------------------------------------------------------------------------- # parse the slots from the intent structure # and combine it with the session attributes if requested # PARAMETERS: # - intent: Alexa intent structure including 'slots' data # - session: Alexa session structure, including 'attributes' data # - continue_session: If True,session_attributes are used # - input_locale: used to set locale and language correctly # - appdef # RETURN: # data structure with all application slots. # slots are provided as canonicals with an additional SLOTNAME.literal field #--------------------------------------------------------------------------- slots = {} if input_locale in ["de-DE", "deu_deu"] : lang = "de-DE" utc_offset = 1 else: myask_log.error("Unsupported input locale '"+ input_locale +"'") lang = input_locale utc_offset = 0 slots['lang'] = lang slots['utc_offset'] = utc_offset if continue_session == True: if 'attributes' in session: myask_log.debug(3, "SESSION_ATTRIBUTES: "+ str(session) ) session_attributes = session['attributes'] for sessionslot in session_attributes: if re.match("DATE:\d\d\d\d-\d+-\d+$", session_attributes[sessionslot]): tmp_str= session_attributes[sessionslot] slots[sessionslot] = datetime.strptime(tmp_str, "DATE:%Y-%m-%d").date() else: slots[sessionslot] = session_attributes[sessionslot] else: myask_log.error("SESSION_ATTRIBUTES: ERROR NO ATTRIBUTES FOUND \n"+ str(session) +"\nEND_SESSION_ATTRIBUTES") if 'slots' in intent: for inputslot in intent['slots']: if 'value' not in intent['slots'][inputslot]: continue if appdef.isApplicationSlot(inputslot): literal = intent['slots'][inputslot]['value'] if appdef.getSlottype(inputslot) == "MY_RELATIVE_DATE": canonical_date = appdef.GetSlotCanonical(inputslot,literal, strict=True) (slots[inputslot],slots[inputslot+'.duration']) = readMyRelativeDate(canonical_date) slots[inputslot+'.literal'] = literal elif appdef.getSlottype(inputslot) == "MY_YEARS": canonical_date = appdef.GetSlotCanonical(inputslot,literal, strict=True) (slots[inputslot],slots[inputslot+'.duration']) = readMyYear(canonical_date) slots[inputslot+'.literal'] = literal elif appdef.getSlottype(inputslot) == "AMAZON.DATE": (slots[inputslot],slots[inputslot+'.duration']) = readAmazonDate(literal) slots[inputslot+'.literal'] = literal elif appdef.getSlottype(inputslot) == "AMAZON.NUMBER": slots[inputslot] = literal elif appdef.getSlottype(inputslot) == "AMAZON.DE_FIRST_NAME": slots[inputslot] = literal else: slots[inputslot] = appdef.GetSlotCanonical(inputslot,literal, strict=True) slots[inputslot+".literal"] = literal else: myask_log.debug(2, "No slots section found") myask_log.debug(5, "SLOTS: "+ str(slots)) return slots
def PrintNonTerminals(non_terminal_list): myask_log.debug(5, "non-terminals:") for nt in non_terminal_list: myask_log.debug(5, "'" + nt + "' =") for alternative in non_terminal_list[nt]: myask_log.debug(5, " '" + alternative + "'")
def main(): # parse command line options parser = argparse.ArgumentParser() parser.add_argument("-v", "--verbosity", type=int, help="define output verbosity") group = parser.add_mutually_exclusive_group() group.add_argument("-create", "--create_table", action="store_true", help="Creates new database table") group.add_argument("-scan", "--scan_items", action="store_true", help="Prints summary of complete scan of profiles") group.add_argument("-get", "--get_item", type=str, help="Returns profile for given user ID") group.add_argument("-stat", "--item_statistics", type=str, help="Returns access statistics for given user ID") group.add_argument("-add", "--add_item", type=str, help="Add item with given ID to the database") group.add_argument("-upd", "--update_item", type=str, help="Update item with given ID in the database") group.add_argument("-del", "--delete_item", type=str, help="Delete item with given ID from the database") parser.add_argument("-profile", "--Profile_JSON_FILE", type=str, help="JSON file with user profile structure") parser.add_argument("-offline", "--offline_port", type=int, help="Use local database on the given port on localhost") parser.add_argument("table", help="database table name") args = parser.parse_args() if args.table: tablename = args.table else: tablename = "TABLE" if args.verbosity: myask_log.SetDebugLevel(args.verbosity) if args.offline_port: offline_endpoint = "http://localhost:"+str(args.offline_port) SetDbType("offline", offline_endpoint) if args.create_table: CreateNewTable(tablename) else: databasetable = dynamoDB(tablename) if args.scan_items: myask_log.debug(5, "Printing statistics") databasetable.ScanAllProfiles(["source"]) elif args.get_item: user_id = str(args.get_item) myask_log.debug(5, "Fetching item '"+user_id+"'") profile = databasetable.FetchUserProfile(user_id) print("Profile for user "+user_id+":") print(profile) elif args.item_statistics: user_id = str(args.item_statistics) (created,num_queries,last_query) = databasetable.GetStatistics(user_id) print ("Created : "+created) print ("Last Query : "+last_query) print ("Num queries: "+str(num_queries)) elif args.add_item: user_id = str(args.add_item) myask_log.debug(5, "Adding new item '"+str(user_id)+"'") if args.Profile_JSON_FILE: profile = readJsonProfileFromFile(args.Profile_JSON_FILE) else: profile = {} databasetable.CreateNewUserProfile(user_id, profile) elif args.update_item: user_id = str(args.update_item) myask_log.debug(5, "Updating item '"+str(user_id)+"'") if args.Profile_JSON_FILE: profile = readJsonProfileFromFile(args.Profile_JSON_FILE) else: profile = {} databasetable.UpdateUserProfile(user_id, profile) elif args.delete_item: user_id = str(args.delete_item) myask_log.debug(5, "Deleting item '"+user_id+"'") databasetable.DeleteUserProfile(user_id) else: myask_log.error("Missing command") parser.print_help()
def getRandomResponse(self, intentlist): #----------------------------------------------------------------------- # returns a random input for one of the intents in the intent list # if the intentlist is emty any intent can be TestActionsReturned # the response consists of a data structure that represents the # 'intents' part of a Alexa resonse, e.g. # "intent": { # "name": "NextBus", # "slots": { # "Destination": { # "name": "Destination", # "value": "elisenbrunnen" # }, # "Buslinie": { # "name": "Buslinie" # }, # } # } # select random slot resulstructure = {} if len(intentlist ) == 0 or intentlist[0] == "*": # select from all slots intentname = random.choice(self._intentdef.keys()) else: # select from the list intentname = random.choice(intentlist) myask_log.debug(5, "Intent: " + intentname) resulstructure["name"] = intentname if intentname not in self._intentdef: myask_log.error("Invalid random intent name '" + intentname + "'") return resulstructure slotlist = self._intentdef[intentname] slotstructure = {} #now loop over all slots forr this intent and decide if we assign a value and which one for slotname in slotlist: slotstructure[slotname] = {} slotstructure[slotname]['name'] = slotname # decide if we assign a value to this slot or not if random.choice([True, False]) == False: # no value for this slot # append it as empty value myask_log.debug(5, "Slot '" + slotname + "' does not get a value") else: # we want to get a random value for this slot # append it as em slottype = self.getSlottype(slotname) if str(slottype).startswith("AMAZON"): # Amazon internal slot if slottype == "AMAZON.NUMBER": slotvalue = 47 literal = str(slotvalue) elif slottype == "AMAZON.DATE": slotvalue = datetime.today() literal = slotvalue.strftime('%Y-%m-%d') elif slottype == "AMAZON.DE_REGION": literal = random.choice(["nrw", "bayern"]) elif slottype == "AMAZON.DE_FIRST_NAME": literal = random.choice([ "Katharina", "Konstantin", "Karina", "?", "friedhelm" ]) else: myask_log.error("_getRandomRespons: Built-in type " + str(slottype) + " not yet handled") literal = "UNKNOWN_AMAZON_TYPE" else: # custom type if slottype not in self._slottypedefs: myask_log.error( "_getRandomRespons: no slot definition found for slot " + str(slottype)) literal = "UNKNOWN_USER_TYPE" else: slotvalue_list = self._slottypedefs[slottype] slotvalue = random.choice(slotvalue_list) # ok, we got the vlaue (literal,canonicals, let's pick a literal literal_list = slotvalue[1] literal = unicode(random.choice(literal_list)) slotstructure[slotname]['value'] = literal myask_log.debug( 5, "Using value' " + literal + "' for slot '" + slotname + "'") resulstructure["slots"] = slotstructure return resulstructure
def GenerateOneTimeCode(self,userid): #----------------------------------------------------------------------- # Creates a one-time passcode (6-digit number) that allows to # access the user profile on dynamodb. # The function stores the code in the dynamodb database. # A Web service uses the one-time code to access the database. # Once the code has been used, the web client should remove it from # the database #----------------------------------------------------------------------- myask_log.debug(10, "GenerateOneTimeCode: called for user '"+userid+"'") # check if user profile entry exists if self._table == "": myask_log.error("GetStatistics: attempted without valid table") try: response = self._table.get_item(Key={'UserID': userid}) except ClientError as e: myask_log.error("GetStatistics: Error: "+e.response['Error']['Message']) else: if 'Item' in response: # profile exists myask_log.debug(10, "GenerateOneTimeCode: Item found for user '"+userid+"'") if 'access_code' in response['Item']: existing_code = response['Item']['access_code'] myask_log.debug(10, "GenerateOneTimeCode: Existing code "+str(existing_code)+" found for user '"+userid+"' reusing") if existing_code != "": return existing_code else: # profile does not exist myask_log.debug(10, "GenerateOneTimeCode: Creating new user entry") self.CreateNewUserProfile(userid, {}) #now create a random code that is not yet used count = 1 # just to have something with len >0 while (count != 0): code = random.randint(100000,999999) myask_log.debug(9, "Checking if code is unique: "+str(code)) # check if code number is already in use response = self._table.query( IndexName='access_code-index', KeyConditionExpression=Key('access_code').eq(str(code)) ) if 'Count' in response: count = response['Count'] else: count = 0 # store code number in user profile try: response = self._table.update_item( Key={'UserID': userid}, UpdateExpression="set access_code = :p, code_created = :t", ExpressionAttributeValues = { ':p': str(code), ':t' : get_date_str() }, ReturnValues="UPDATED_NEW") except ClientError as e: myask_log.error("UpdateUserProfile: Error: "+e.response['Error']['Message']) return 0 else: myask_log.debug(2, "Added code: " + str(code)+ " to user profile") return code
def main(): parser = argparse.ArgumentParser() parser.add_argument("-v", "--verbosity", type=int, help="define output verbosity") parser.add_argument("-out", "--outputfile_root", type=str, help="basename for output files") parser.add_argument("inputfile", help="grammar file as input") args = parser.parse_args() if args.verbosity: myask_log.SetDebugLevel(args.verbosity) if args.inputfile: inputfile = args.inputfile else: inputfile = "input.py" # dummy, we will never get here if inputfile.endswith('.py'): inputfile = inputfile[:-3] else: myask_log.error( "application definition file muyst end with #.py'. Got " + inputfile + "'") return if args.outputfile_root: output_root = args.outputfile_root else: output_root = "" # now import the application definition from that file try: appdef_module = __import__(inputfile) except ImportError: # Display error message myask_log.error("Could not import appdef file '" + inputfile + "'") else: myask_log.debug( 3, "Application definition importet from '" + inputfile + ".py'") myask_log.debug(5, "Initializing application definition") appdef = applicationdef(appdef_module.APPNAME, appdef_module.APPID, appdef_module.INTENTS, appdef_module.SLOTS, appdef_module.SLOTTYPES) myask_log.debug(5, "Creating ASK intent structure") intent_json = appdef.CreateIntentDef() if output_root == "": # print to standard outpt print( "=======BEGIN INTENT DEF=====================================\n\n" ) print intent_json print( "\n=======END INTENT DEF=====================================\n\n" ) else: intentfile = output_root + "_intentstruct_generated.js" myask_log.debug( 3, "Writing intent structure to file '" + intentfile + "'") intentout = open(intentfile, 'w+') intentout.write(intent_json) intentout.close() typeinfo = appdef.GetAllSlotLiterals() if output_root == "": # print to standard outpt print( "=======BEGIN CUSTOM_TYPE DEFINITIONS========================\n\n" ) for (slottype, slotliterals) in typeinfo: print("\n--- " + slottype + " ---") for literal in slotliterals: print literal print( "\n=======END CUSTOM_TYPE DEFINITIONS========================\n\n" ) else: typefile = output_root + "_customtypes_generated.txt" myask_log.debug( 3, "Writing custom data type definitions to file '" + typefile + "'") typeout = open(typefile, 'w+') for (slottype, slotliterals) in typeinfo: typeout.write("\n--- " + slottype + " ---\n") for literal in slotliterals: typeout.write(literal.encode('utf8') + "\n") typeout.close() myask_log.debug(3, "Done")
def TestEvent(event, handlerfunction, expected_result_state=""): #-------------------------------------------------------------------------- # tests a single input event (JSON structure) using the handler function # 'event': input event (output of Alexa NLU) # 'handlerfunction' pointer to lambda handler function # # The function calls the lambda event handler 'handlerfunction' with # the specified input 'event' and analyzes the output # The function updates the global variables # - g_total_count # - g_passed_count # - g_failed_count # - g_total_with_errors # - g_total_with_warnings # - g_total_ok #-------------------------------------------------------------------------- global g_total_count global g_passed_count global g_failed_count global g_total_with_errors global g_total_with_warnings global g_total_ok global g_correct_final_states global g_incorrect_final_states context = {} g_total_count += 1 returnjson = handlerfunction(event, context, True) myask_log.debug(1, "RESULT: " + str(returnjson)) speech_output = "ERROR" if 'response' in returnjson and 'outputSpeech' in returnjson['response']: if 'type' in returnjson['response']['outputSpeech']: if returnjson['response']['outputSpeech'][ 'type'] == "SSML" and 'ssml' in returnjson['response'][ 'outputSpeech']: speech_output = returnjson['response']['outputSpeech']['ssml'] elif returnjson['response']['outputSpeech'][ 'type'] == "PlainText" and 'text' in returnjson[ 'response']['outputSpeech']: speech_output = returnjson['response']['outputSpeech']['text'] print("<<<<< " + speech_output) print("------\n" + returnjson['response']['card']['content'] + "\n-----") g_passed_count += 1 final_state = myask_log.GetDialogState() if (expected_result_state != ""): if final_state == expected_result_state: print("Final State: " + final_state + "--> OK") g_correct_final_states += 1 else: print("Final State: '" + final_state + "'--> ERROR (expected '" + expected_result_state + "')") g_incorrect_final_states += 1 else: print("Final State: " + final_state + " (no expected state given)") [errors, warnings] = myask_log.GetErrorCounters() if errors > 0: g_total_with_errors += 1 elif warnings > 0: g_total_with_warnings += 1 else: g_total_ok += 1 else: print("!!!ERROR") g_failed_count += 1