Porcupine.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import argparse
  4. import os
  5. import struct
  6. import wave
  7. import configparser
  8. from datetime import datetime
  9. from threading import Thread
  10. import pvporcupine
  11. from pvrecorder import PvRecorder
  12. import platform
  13. from VoicePlay import Voice
  14. from DynLoader import DynLoaderMod as dyn
  15. class Porcupine(Thread):
  16. def __init__(self):
  17. super(Porcupine, self).__init__()
  18. config = configparser.ConfigParser()
  19. config.read('config/pico.ini')
  20. Keywords=[]
  21. Sensitivity=[]
  22. isAdmin=[]
  23. bHasKeywords = False
  24. self._model_path=""
  25. self._keyword_paths=""
  26. self._sensitivities=0.5
  27. self._lang = "de"
  28. if "lang" in config["global"]:
  29. self._lang = config["global"]["lang"]
  30. self._os = platform.system().lower()
  31. if "ApiKey" in config["PicoVoice"]:
  32. self._access_key = config["PicoVoice"]["apikey"]
  33. self._library_path = pvporcupine.LIBRARY_PATH
  34. if "model" in config["Porcupine"]:
  35. self._model_path = 'ressources/models/porcupine/' + config["Porcupine"]["model"]
  36. for k,v in config.items():
  37. if "weakword" in v and v["weakword"]!="":
  38. print(" - Weakword '"+k+"': " + v["weakword"].strip())
  39. Keywords.append('ressources/models/porcupine/' + v["weakword"].strip())
  40. bHasKeywords = True
  41. if "sensitivities" in v:
  42. Sensitivity.append(float(v["sensitivities"]))
  43. else:
  44. Sensitivity.append(float(0.5))
  45. if "admin" in v and (v["admin"]=="1" or v["admin"]=="true" or v["admin"]=="True" or v["admin"]=="TRUE"):
  46. isAdmin.append(True)
  47. else:
  48. isAdmin.append(False)
  49. if bHasKeywords == True:
  50. self._keyword_paths = Keywords
  51. self._sensitivities = Sensitivity
  52. self.isAdmin = isAdmin
  53. if "InputDeviceIndex" in config["Hardware"]:
  54. self._input_device_index = int(config["Hardware"]["InputDeviceIndex"])
  55. else:
  56. self._input_device_index = None
  57. self._output_path = None
  58. instance = None
  59. @staticmethod
  60. def getInstance():
  61. if Porcupine.instance==None:
  62. Porcupine.instance = Porcupine()
  63. return Porcupine.instance
  64. def run(self):
  65. print("Porcupine.run()")
  66. print(" - Generate Keyword List")
  67. _access_key = Porcupine.getInstance()._access_key
  68. _library_path = Porcupine.getInstance()._library_path
  69. _model_path = Porcupine.getInstance()._model_path
  70. _keyword_paths = Porcupine.getInstance()._keyword_paths
  71. _sensitivities = Porcupine.getInstance()._sensitivities
  72. _output_path = Porcupine.getInstance()._output_path
  73. __func = Porcupine.getInstance().__func
  74. _isAdmin = Porcupine.getInstance().isAdmin
  75. dynloader:dyn = dyn.getInstance()
  76. keywords = list()
  77. for x in self._keyword_paths:
  78. keyword_phrase_part = os.path.basename(x).replace('.ppn', '').split('_')
  79. if len(keyword_phrase_part) > 6:
  80. keywords.append(' '.join(keyword_phrase_part[0:-6]))
  81. else:
  82. keywords.append(keyword_phrase_part[0])
  83. porcupine = None
  84. recorder = None
  85. wav_file = None
  86. try:
  87. '''porcupine = pvporcupine.create(
  88. access_key=_access_key,
  89. library_path=_library_path,
  90. model_path=_model_path,
  91. keyword_paths=_keyword_paths,
  92. sensitivities=_sensitivities
  93. )'''
  94. porcupine = pvporcupine.create(
  95. access_key=_access_key,
  96. model_path=_model_path,
  97. keyword_paths=_keyword_paths,
  98. sensitivities=_sensitivities
  99. )
  100. recorder = PvRecorder(device_index=self._input_device_index, frame_length=porcupine.frame_length)
  101. print("Frame Length: ",porcupine.frame_length)
  102. recorder.start()
  103. if _output_path is not None:
  104. wav_file = wave.open(self._output_path, "w")
  105. wav_file.setparams((1, 2, 16000, 512, "NONE", "NONE"))
  106. print('Listening {')
  107. for keyword, sensitivity, admin in zip(keywords, _sensitivities, _isAdmin):
  108. print(keyword,str(sensitivity), admin)
  109. print('}')
  110. bRunning = True
  111. while bRunning:
  112. pcm = recorder.read()
  113. if wav_file is not None:
  114. wav_file.writeframes(struct.pack("h" * len(pcm), *pcm))
  115. result = porcupine.process(pcm)
  116. if result >= 0:
  117. #print('[%s] Detected %s' % (str(datetime.now()), keywords[result]))
  118. if(self.__func):
  119. #bRunning = False
  120. recorder.stop()
  121. dynloader.execute("WeakWord",result,keywords[result],_isAdmin[result])
  122. __func(result,keywords[result],_isAdmin[result])
  123. recorder.start()
  124. except pvporcupine.PorcupineInvalidArgumentError as e:
  125. print("One or more arguments provided to Porcupine is invalid: {\n" +
  126. "\tAcccess Key: "+_access_key+"\n" +
  127. "\tLibrary Path: "+_library_path+"\n" +
  128. "\tModel Path: "+_model_path+"\n" +
  129. "\tKeyword Paths: ['"+', '.join(_keyword_paths)+"']\n" +
  130. "\tSensitivities: ['"+', '.join([str(int) for int in _sensitivities])+"']\n" +
  131. "}")
  132. print("If all other arguments seem valid, ensure that '"+self._access_key+"' is a valid AccessKey")
  133. print("Error: "+','.join(e.args))
  134. Voice.getInstance().Say("Ausnahmefehler in Porcubine Argument")
  135. raise e
  136. except pvporcupine.PorcupineActivationError as e:
  137. print("AccessKey activation error")
  138. Voice.getInstance().Say("Ausnahmefehler in Porcubine Aktivierung")
  139. raise e
  140. except pvporcupine.PorcupineActivationLimitError as e:
  141. print("AccessKey '"+self._access_key+"' has reached it's temporary device limit")
  142. Voice.getInstance().Say("Ausnahmefehler in Porcubine Aktivierungs-Limit")
  143. raise e
  144. except pvporcupine.PorcupineActivationRefusedError as e:
  145. print("AccessKey '"+self._access_key+"' refused")
  146. Voice.getInstance().Say("Ausnahmefehler in Porcubine Aktivierung zurückgewiesen")
  147. raise e
  148. except pvporcupine.PorcupineActivationThrottledError as e:
  149. print("AccessKey '"+self._access_key+"' has been throttled")
  150. Voice.getInstance().Say("Ausnahmefehler in Porcubine Zugriff wurde gedrosselt")
  151. raise e
  152. except pvporcupine.PorcupineError as e:
  153. print("Failed to initialize Porcupine")
  154. Voice.getInstance().Say("Ausnahmefehler bei der Porcubine Initialisierung")
  155. raise e
  156. except KeyboardInterrupt:
  157. print('Stopping ...')
  158. finally:
  159. if porcupine is not None:
  160. porcupine.delete()
  161. if recorder is not None:
  162. recorder.delete()
  163. if wav_file is not None:
  164. wav_file.close()
  165. def RegisterFunc(self, func):
  166. self.__func = func
  167. @staticmethod
  168. def show_audio_devices():
  169. devices = PvRecorder.get_audio_devices()
  170. for i in range(len(devices)):
  171. print("index: "+str(i)+", device name: '"+devices[i]+"'")