def findPhoneForNumberType(self, person, numberType, language): # first check if a specific number was already requested phoneToCall = None if numberType != None: # try to find the phone that fits the numberType phoneToCall = filter(lambda x: x.label == numberType, person.phones) else: favPhones = filter( lambda y: y.favoriteVoice if hasattr(y, "favoriteVoice") else False, person.phones) if len(favPhones) == 1: phoneToCall = favPhones[0] if phoneToCall == None: # lets check if there is more than one number if len(person.phones) == 1: if numberType != None: self.say( errorNumberNotPresent.format( numberTypesLocalized[numberType][language], person.fullName)) phoneToCall = person.phones[0] else: # damn we need to ask the user which one he wants... while (phoneToCall == None): rootView = AddViews(self.refId, temporary=False, dialogPhase="Clarification", scrollToTop=False, views=[]) sayit = responses['selectNumber'][language].format( person.fullName) rootView.views.append( AssistantUtteranceView( text=sayit, speakableText=sayit, listenAfterSpeaking=True, dialogIdentifier= "ContactDataResolutionDucs#foundAmbiguousPhoneNumberForContact" )) lst = DisambiguationList( items=[], speakableSelectionResponse="OK...", listenAfterSpeaking=True, speakableText="", speakableFinalDemitter=speakableDemitter[language], speakableDemitter=", ", selectionResponse="OK...") rootView.views.append(lst) for phone in person.phones: numberType = phone.label item = ListItem() item.title = "" item.text = u"{0}: {1}".format( numberTypesLocalized[numberType][language], phone.number) item.selectionText = item.text item.speakableText = u"{0} ".format( numberTypesLocalized[numberType][language]) item.object = phone item.commands.append( SendCommands(commands=[ StartRequest( handsFree=False, utterance=numberTypesLocalized[numberType] [language]) ])) lst.items.append(item) answer = self.getResponseForRequest(rootView) if re.match(InterruptCall[language], answer, re.IGNORECASE): self.say(random.choice( InterruptCallResponse[language])) return None numberType = self.getNumberTypeForName(answer, language) if numberType != None: print numberType matches = filter(lambda x: x.label == numberType, person.phones) if len(matches) == 1: phoneToCall = matches[0] else: self.say(errorNumberTypes[language]) else: self.say(errorNumberTypes[language]) return phoneToCall
def findMailForMailType(plugin, person, mailType, language): mail = None if mailType != None: mailToWrite = filter(lambda x: x.label == mailType, person.emails) else: favMails = filter( lambda y: y.favoriteVoice if hasattr(y, "favoriteVoice") else False, person.emails) if len(favMails) == 1: mail = favMails[0] if mail == None: if len(person.emails) == 1: if mailType != None: plugin.say(text["numberNotPresent"][language].format( mailTypes[language][mailType], person.fullName)) mail = person.emails[0] else: while (mail == None): rootView = UIAddViews(plugin.refId) rootView.temporary = False rootView.dialogPhase = "Clarification" rootView.scrollToTop = False rootView.views = [] sayit = text['selectMail'][language].format(person.fullName) assistant = UIAssistantUtteranceView() assistant.text = assistant.speakableText = sayit assistant.listenAfterSpeaking = True assistant.dialogIdentifier = "ContactDataResolutionDucs#foundAmbiguousMailForContact" rootView.views.append(assistant) lst = UIDisambiguationList() lst.items = [] lst.speakableSelectionResponse = "OK..." lst.listenAfterSpeaking = True lst.speakableText = "" lst.speakableFinalDemitter = speakableDemitter[language] lst.speakableDemitter = ", " lst.selectionResponse = "OK..." rootView.views.append(lst) for email in person.emails: mailType = email.label item = UIListItem() item.title = "" item.text = u"{0}: {1}".format( mailTypes[language][mailType], email.emailAddress) item.selectionText = item.text item.speakableText = u"{0} ".format( mailTypes[language][mailType]) item.object = email item.commands = [] item.commands.append( SendCommands(commands=[ StartRequest(handsFree=False, utterance=mailTypes[language] [mailType]) ])) lst.items.append(item) answer = plugin.getResponseForRequest(rootView) answer = replaceMailType(answer, language) mailType = answer if mailType != None: matches = filter(lambda x: x.label == mailType, person.emails) if len(matches) == 1: mail = matches[0] else: plugin.say(text['errorNumberTypes'][language]) else: plugin.say(text['errorNumberTypes'][language]) return mail
def findPhoneForNumberType(plugin, person, numberType, language): number = None if numberType != None: phoneToCall = filter(lambda x: x.label == numberType, person.phones) else: favPhones = filter( lambda y: y.favoriteVoice if hasattr(y, "favoriteVoice") else False, person.phones) if len(favPhones) == 1: number = favPhones[0] if number == None: if len(person.phones) == 1: if numberType != None: plugin.say(text["numberNotPresent"][language].format( numberTypes[language][numberType], person.fullName)) number = person.phones[0] else: while (number == None): rootView = UIAddViews(plugin.refId) rootView.temporary = False rootView.dialogPhase = "Clarification" rootView.scrollToTop = False rootView.views = [] sayit = text['selectNumber'][language].format(person.fullName) assistant = UIAssistantUtteranceView() assistant.text = assistant.speakableText = sayit assistant.listenAfterSpeaking = True assistant.dialogIdentifier = "ContactDataResolutionDucs#foundAmbiguousPhoneNumberForContact" rootView.views.append(assistant) lst = UIDisambiguationList() lst.items = [] lst.speakableSelectionResponse = "OK..." lst.listenAfterSpeaking = True lst.speakableText = "" lst.speakableFinalDemitter = speakableDemitter[language] lst.speakableDemitter = ", " lst.selectionResponse = "OK..." rootView.views.append(lst) for phone in person.phones: numberType = numberTypesLocalized[phone.label][ language] if phone.label in numberTypesLocalized else phone.label item = UIListItem() item.title = "" item.text = u"{0}: {1}".format(numberType, phone.number) item.selectionText = item.text item.speakableText = u"{0} ".format(numberType) item.object = phone item.commands = [ SendCommands(commands=[ StartRequest(handsFree=False, utterance=numberType) ]) ] lst.items.append(item) answer = plugin.getResponseForRequest(rootView) answer = getNumberTypeForName(answer, language) numberType = answer if numberType != None: matches = filter(lambda x: x.label == numberType, person.phones) if len(matches) == 1: number = matches[0] else: plugin.say(text['errorNumberTypes'][language]) else: plugin.say(text['errorNumberTypes'][language]) return number
def received_plist(self, plist): self.logger.debug("Got packet with class: {0}".format(plist['class'])) self.logger.debug("packet with content:\n{0}".format( pprint.pformat(plist, width=40))) # first handle speech stuff if 'refId' in plist: # if the following holds, this packet is an answer to a request by a plugin if plist[ 'refId'] == self.plugin_lastAceId and self.current_running_plugin != None: if self.current_running_plugin.waitForResponse != None: # just forward the object to the # don't change it's refId, further requests must reference last FinishSpeech self.logger.debug("Forwarding object to plugin") self.plugin_lastAceId = None self.current_running_plugin.response = plist if plist[ 'class'] != "StartRequest" else plist['properties'][ 'utterance'] self.current_running_plugin.waitForResponse.set() return if ObjectIsCommand(plist, StartSpeechRequest) or ObjectIsCommand( plist, StartSpeechDictation): self.logger.debug("New start of speech received") startSpeech = None if ObjectIsCommand(plist, StartSpeechDictation): dictation = True startSpeech = StartSpeechDictation(plist) else: dictation = False startSpeech = StartSpeechRequest(plist) decoder = speex.Decoder() encoder = flac.Encoder() speexUsed = False if startSpeech.codec == StartSpeech.CodecSpeex_WB_Quality8Value: decoder.initialize(mode=speex.SPEEX_MODEID_WB) encoder.initialize(16000, 1, 16) speexUsed = True elif startSpeech.codec == StartSpeech.CodecSpeex_NB_Quality7Value: decoder.initialize(mode=speex.SPEEX_MODEID_NB) encoder.initialize(16000, 1, 16) speexUsed = True elif startSpeech.codec == StartSpeech.CodecPCM_Mono_16Bit_8000HzValue: encoder.initialize(8000, 1, 16) elif startSpeech.codec == StartSpeech.CodecPCM_Mono_16Bit_11025HzValue: encoder.initialize(11025, 1, 16) elif startSpeech.coded == StartSpeech.CodecPCM_Mono_16Bit_16000HzValue: encoder.initialize(16000, 1, 16) elif startSpeech.coded == StartSpeech.CodecPCM_Mono_16Bit_22050HzValue: encoder.initialize(22050, 1, 16) elif startSpeech.coded == StartSpeech.CodecPCM_Mono_16Bit_32000HzValue: encoder.initialize(32000, 1, 16) # we probably need resampling for sample rates other than 16kHz... self.speech[startSpeech.aceId] = (decoder if speexUsed else None, encoder, dictation) elif ObjectIsCommand(plist, SpeechPacket): self.logger.debug("Decoding speech packet") speechPacket = SpeechPacket(plist) if speechPacket.refId in self.speech: (decoder, encoder, dictation) = self.speech[speechPacket.refId] if decoder: pcm = decoder.decode(speechPacket.packets) else: pcm = SpeechPacket.data # <- probably data... if pcm encoder.encode(pcm) else: self.logger.debug( "Got a speech packet that did not match any current request" ) elif plist['class'] == 'StartCorrectedSpeechRequest': self.process_recognized_speech( { u'hypotheses': [{ 'confidence': 1.0, 'utterance': plist['properties']['utterance'] }] }, plist['aceId'], False) elif ObjectIsCommand(plist, FinishSpeech): self.logger.debug("End of speech received") finishSpeech = FinishSpeech(plist) if finishSpeech.refId in self.speech: (decoder, encoder, dictation) = self.speech[finishSpeech.refId] if decoder: decoder.destroy() flacBin = None if encoder: encoder.finish() flacBin = encoder.getBinary() encoder.destroy() del self.speech[finishSpeech.refId] if flacBin != None: self.logger.info("Sending flac to google for recognition") try: self.current_google_request = self.httpClient.make_google_request( flacBin, finishSpeech.refId, dictation, language=self.assistant.language, allowCurses=True) except (AttributeError, TypeError): self.logger.warning( "Unable to find language record for this assistant. Try turning Siri off and then back on." ) else: self.logger.info("There was no speech") else: self.logger.debug( "Got a finish speech packet that did not match any current request" ) elif ObjectIsCommand(plist, CancelRequest): # this is probably called when we need to kill a plugin # wait for thread to finish a send self.logger.debug("Should cancel current request") cancelRequest = CancelRequest(plist) if cancelRequest.refId in self.speech: (decoder, encoder, dictation) = self.speech[cancelRequest.refId] if decoder: decoder.destroy() if encoder: encoder.finish() encoder.destroy() del self.speech[cancelRequest.refId] if self.current_google_request != None: self.current_google_request.cancel() # if a google request is running (follow up listening..., plugin might get killed there by user) if self.current_running_plugin != None: if self.current_running_plugin.waitForResponse != None: self.current_running_plugin._abortPluginRun() self.current_running_plugin.waitForResponse.set() # if a plugin is running (processing, but not waiting for data from the device we kill it) if self.current_running_plugin != None: if self.current_running_plugin.waitForResponse == None: self.current_running_plugin._abortPluginRun() self.send_object(CancelSucceeded(cancelRequest.aceId)) elif ObjectIsCommand(plist, RollbackRequest): pass elif ObjectIsCommand(plist, SyncChunk): chunk = SyncChunk(plist) previous = self.syncAnchors[ chunk.key] if chunk.key in self.syncAnchors else None if previous != None: if previous.generation != chunk.preGen: chunkDenied = SyncChunkDenied(chunk.aceId) self.send_object(chunkDenied) return current = SyncAnchor() current.generation = chunk.postGen current.value = chunk.postGen current.validity = chunk.validity current.key = chunk.key self.syncAnchors[current.key] = current chunkAccepted = SyncChunkAccepted(chunk.aceId) chunkAccepted.current = current self.send_object(chunkAccepted) pass elif ObjectIsCommand(plist, GetSessionCertificate): getSessionCertificate = GetSessionCertificate(plist) sessionCA_DER = crypto.dump_certificate(crypto.FILETYPE_ASN1, self.server.sessionCACert) sessionCert_DER = crypto.dump_certificate(crypto.FILETYPE_ASN1, self.server.sessionCert) response = GetSessionCertificateResponse( getSessionCertificate.aceId, sessionCA_DER, sessionCert_DER) self.send_object(response) elif ObjectIsCommand(plist, CreateSessionInfoRequest): # how does a positive answer look like? createSessionInfoRequest = CreateSessionInfoRequest(plist) #success = CreateSessionInfoResponse(createSessionInfoRequest.aceId) #success.sessionInfo = biplist.Data("\x01\x02BLABLABLBALBALBALBALBALBALBALBA") #success.validityDuration = 9600 #self.send_object(success) fail = CommandFailed(createSessionInfoRequest.aceId) fail.reason = "Not authenticated" fail.errorCode = 0 self.send_object(fail) ##self.send_plist({"class":"SessionValidationFailed", "properties":{"errorCode":"UnsupportedHardwareVersion"}, "aceId": str(uuid.uuid4()), "refId":plist['aceId'], "group":"com.apple.ace.system"}) elif ObjectIsCommand(plist, CreateAssistant): createAssistant = CreateAssistant(plist) #create a new assistant helper = Assistant() helper.assistantId = str.upper(str(uuid.uuid4())) helper.language = createAssistant.language helper.activationToken = createAssistant.activationToken helper.connectionType = createAssistant.connectionType helper.validationData = createAssistant.validationData c = self.dbConnection.cursor() noError = True try: c.execute( "insert into assistants(assistantId, assistant) values (?,?)", (helper.assistantId, helper)) self.dbConnection.commit() except sqlite3.Error: noError = False c.close() if noError: self.assistant = helper assiCreatedCMD = AssistantCreated(createAssistant.aceId) assiCreatedCMD.assistantId = helper.assistantId assiCreatedCMD.speechId = str(uuid.uuid4()) self.send_object(assiCreatedCMD) else: cmdFailed = CommandFailed(createAssistant.aceId) cmdFailed.reason = "Database Error" cmdFailed.errorCode = 2 self.send_object(cmdFailed) elif ObjectIsCommand(plist, SetAssistantData): setAssistantData = SetAssistantData(plist) # fill assistant if self.assistant != None: try: c = self.dbConnection.cursor() assi_id = self.assistant.assistantId self.assistant.initializeFromPlist( setAssistantData.to_plist()) self.assistant.assistantId = assi_id #Record the user firstName and nickName try: self.assistant.firstName = self.assistant.meCards[ 0].firstName.encode("utf-8") except: self.assistant.firstName = u'' try: self.assistant.nickName = self.assistant.meCards[ 0].nickName.encode("utf-8") except: self.assistant.nickName = u'' #Done recording c.execute( "update assistants set assistant = ? where assistantId = ?", (self.assistant, self.assistant.assistantId)) self.dbConnection.commit() c.close() except: cmdFailed = CommandFailed(setAssistantData.aceId) cmdFailed.reason = "Database Error" cmdFailed.errorCode = 2 self.send_object(cmdFailed) self.logger.exception( "Database Error on setting assistant data") else: cmdFailed = CommandFailed(setAssistantData.aceId) cmdFailed.reason = "Assistant to set data not found" cmdFailed.errorCode = 2 self.send_object(cmdFailed) self.logger.warning( "Trying to set assistant data without having a valid assistant" ) elif ObjectIsCommand(plist, LoadAssistant): loadAssistant = LoadAssistant(plist) try: c = self.dbConnection.cursor() c.execute( "select assistant from assistants where assistantId = ?", (loadAssistant.assistantId, )) self.dbConnection.commit() result = c.fetchone() if result == None: self.send_object(AssistantNotFound(loadAssistant.aceId)) self.logger.warning("Assistant not found in database!!") else: self.assistant = result[0] #update assistant from LoadAssistant self.assistant.language = loadAssistant.language self.assistant.connectionType = loadAssistant.connectionType if self.assistant.language == '' or self.assistant.language == None: self.logger.error( "No language is set for this assistant") c.execute( "delete from assistants where assistantId = ?", (plist['properties']['assistantId'], )) self.dbConnection.commit() cmdFailed = CommandFailed(loadAssistant.aceId) cmdFailed.reason = "Database error Assistant not found or language settings" cmdFailed.errorCode = 2 self.send_object(cmdFailed) else: loaded = AssistantLoaded(loadAssistant.aceId) loaded.version = "20111216-32234-branches/telluride?cnxn=293552c2-8e11-4920-9131-5f5651ce244e" loaded.requestSync = 0 try: loaded.dataAnchor = self.assistant.anchor except: loaded.dataAnchor = "removed" self.send_object(loaded) c.close() except: self.send_object(AssistantNotFound(loadAssistant.aceId)) self.logger.warning("Database error on fetching assistant") elif ObjectIsCommand(plist, DestroyAssistant): destroyAssistant = DestroyAssistant(plist) try: c = self.dbConnection.cursor() c.execute("delete from assistants where assistantId = ?", (plist['properties']['assistantId'], )) self.dbConnection.commit() c.close() destroyed = AssistantDestroyed(destroyAssistant.aceId) destroyed.assistantId = destroyAssistant.assistantId self.send_object(destroyed) except: self.send_object(AssistantNotFound(destroyAssistant.aceId)) self.logger.error("Database error on deleting assistant") elif ObjectIsCommand(plist, StartRequest): startRequest = StartRequest(plist) #this should also be handeled by special plugins, so lets call the plugin handling stuff self.process_recognized_speech( { 'hypotheses': [{ 'utterance': startRequest.utterance, 'confidence': 1.0 }] }, startRequest.aceId, False) pass
def process_recognized_speech(self, googleJson, requestId, dictation): possible_matches = googleJson['hypotheses'] if len(possible_matches) > 0: best_match = possible_matches[0]['utterance'] best_match_confidence = possible_matches[0]['confidence'] self.logger.info( u"Best matching result: \"{0}\" with a confidence of {1}%". format(best_match, round(float(best_match_confidence) * 100, 2))) # construct a SpeechRecognized token = Token(best_match, 0, 0, 1000.0, True, True) interpretation = Interpretation([token]) phrase = Phrase(lowConfidence=False, interpretations=[interpretation]) recognition = Recognition([phrase]) recognized = SpeechRecognized(requestId, recognition) if not dictation: if self.current_running_plugin == None: plugin = PluginManager.getPluginForImmediateExecution( self.assistant.assistantId, best_match, self.assistant.language, (self.send_object, self.send_plist, self.assistant, self.current_location)) if plugin != None: plugin.refId = requestId plugin.connection = self self.current_running_plugin = plugin self.send_object(recognized) self.current_running_plugin.start() else: self.send_object(recognized) view = UIAddViews(requestId) errorText = SiriProtocolHandler.__not_recognized[ self.assistant. language] if self.assistant.language in SiriProtocolHandler.__not_recognized else SiriProtocolHandler.__not_recognized[ "en-US"] errorView = UIAssistantUtteranceView() errorView.text = errorText.format(best_match) errorView.speakableText = errorText.format(best_match) view.views = [errorView] websearchText = SiriProtocolHandler.__websearch[ self.assistant. language] if self.assistant.language in SiriProtocolHandler.__websearch else SiriProtocolHandler.__websearch[ "en-US"] button = UIButton() button.text = websearchText cmd = SendCommands() cmd.commands = [ StartRequest( utterance= u"^webSearchQuery^=^{0}^^webSearchConfirmation^=^Yes^" .format(best_match)) ] button.commands = [cmd] view.views.append(button) self.send_object(view) self.send_object(RequestCompleted(requestId)) elif self.current_running_plugin.waitForResponse != None: # do we need to send a speech recognized here? i.d.k self.current_running_plugin.response = best_match self.current_running_plugin.refId = requestId self.current_running_plugin.waitForResponse.set() else: self.send_object(recognized) self.send_object(RequestCompleted(requestId)) else: self.send_object(recognized) self.send_object(RequestCompleted(requestId))
def findPhoneForNumberType(self, person, numberType, language): # first check if a specific number was already requested phoneToMessage = None if numberType != None: # try to find the phone that fits the numberType listToMessage = filter(lambda x: x.label == numberType, person.phones) if len(listToMessage) == 1: phoneToMessage = listToMessage[0] else: favPhones = filter( lambda y: y.favoriteVoice if hasattr(y, "favoriteVoice") else False, person.phones) if len(favPhones) == 1: phoneToMessage = favPhones[0] if phoneToMessage == None: # lets check if there is more than one number if len(person.phones) == 1: if numberType != None: self.say( errorNumberNotPresent.format( numberTypesLocalized[numberType][language], person.fullName)) phoneToMessage = person.phones[0] else: # damn we need to ask the user which one he wants... if phoneToMessage == None: root = UIAddViews(self.refId) root.dialogPhase = root.DialogPhaseClarificationValue utterance = UIAssistantUtteranceView() utterance.dialogIdentifier = "ContactDataResolutionDucs#foundAmbiguousPhoneNumberForContact" utterance.speakableText = utterance.text = responses[ 'selectNumber'][language].format(person.fullName) utterance.listenAfterSpeaking = True root.views = [utterance] lst = UIDisambiguationList() lst.items = [] lst.speakableSelectionResponse = "" lst.listenAfterSpeaking = True lst.selectionResponse = "" root.views.append(lst) for phone in person.phones: numberType = numberTypesLocalized[phone.label][ language] if phone.label in numberTypesLocalized else phone.label item = UIListItem() item.title = "" item.text = u"{0}: {1}".format(numberType, phone.number) item.selectionText = item.text item.speakableText = u"{0}, ".format(numberType) item.object = phone item.commands = [ SendCommands(commands=[ StartRequest(handsFree=False, utterance=numberType) ]) ] lst.items.append(item) answer = self.getResponseForRequest(root) numberType = self.getNumberTypeForName(answer, language) if numberType != None: matches = filter(lambda x: x.label == numberType, person.phones) if len(matches) == 1: phoneToMessage = matches[0] else: self.say(errorNumberTypes[language]) else: self.say(errorNumberTypes[language]) return phoneToMessage