├── config.json ├── hotword ├── __init__.py ├── _snowboydetect.so ├── resources │ ├── common.res │ ├── ding.wav │ ├── dong.wav │ ├── models │ │ ├── computer.umdl │ │ ├── hey_extreme.umdl │ │ ├── jarvis.umdl │ │ ├── neoya.umdl │ │ ├── smart_mirror.umdl │ │ ├── snowboy.umdl │ │ ├── subex.umdl │ │ └── view_glass.umdl │ ├── snowboy.raw │ └── snowboy.wav ├── snowboydecoder.py ├── snowboydetect.py └── try_again_detect.py ├── mouth ├── __init__.py └── play.py ├── readme.md ├── stt_tts ├── __init__.py ├── baidu.py └── baidu_tts_wav.py ├── temp └── baidu_tts.py └── tuling ├── __init__.py ├── baidu_robot.py └── tuling123.py /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "***************2b909949ba61" 3 | } 4 | -------------------------------------------------------------------------------- /hotword/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/__init__.py -------------------------------------------------------------------------------- /hotword/_snowboydetect.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/_snowboydetect.so -------------------------------------------------------------------------------- /hotword/resources/common.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/common.res -------------------------------------------------------------------------------- /hotword/resources/ding.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/ding.wav -------------------------------------------------------------------------------- /hotword/resources/dong.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/dong.wav -------------------------------------------------------------------------------- /hotword/resources/models/computer.umdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/models/computer.umdl -------------------------------------------------------------------------------- /hotword/resources/models/hey_extreme.umdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/models/hey_extreme.umdl -------------------------------------------------------------------------------- /hotword/resources/models/jarvis.umdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/models/jarvis.umdl -------------------------------------------------------------------------------- /hotword/resources/models/neoya.umdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/models/neoya.umdl -------------------------------------------------------------------------------- /hotword/resources/models/smart_mirror.umdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/models/smart_mirror.umdl -------------------------------------------------------------------------------- /hotword/resources/models/snowboy.umdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/models/snowboy.umdl -------------------------------------------------------------------------------- /hotword/resources/models/subex.umdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/models/subex.umdl -------------------------------------------------------------------------------- /hotword/resources/models/view_glass.umdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/models/view_glass.umdl -------------------------------------------------------------------------------- /hotword/resources/snowboy.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/snowboy.raw -------------------------------------------------------------------------------- /hotword/resources/snowboy.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/hotword/resources/snowboy.wav -------------------------------------------------------------------------------- /hotword/snowboydecoder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import collections 4 | import pyaudio 5 | from . import snowboydetect 6 | import time 7 | import wave 8 | import os 9 | import logging 10 | from ctypes import * 11 | from contextlib import contextmanager 12 | 13 | logging.basicConfig() 14 | logger = logging.getLogger("try_again") 15 | logger.setLevel(logging.INFO) 16 | TOP_DIR = os.path.dirname(os.path.abspath(__file__)) 17 | 18 | RESOURCE_FILE = os.path.join(TOP_DIR, "resources/common.res") 19 | DETECT_DING = os.path.join(TOP_DIR, "resources/ding.wav") 20 | DETECT_DONG = os.path.join(TOP_DIR, "resources/dong.wav") 21 | 22 | def py_error_handler(filename, line, function, err, fmt): 23 | pass 24 | 25 | ERROR_HANDLER_FUNC = CFUNCTYPE(None, c_char_p, c_int, c_char_p, c_int, c_char_p) 26 | 27 | c_error_handler = ERROR_HANDLER_FUNC(py_error_handler) 28 | 29 | @contextmanager 30 | def no_alsa_error(): 31 | try: 32 | asound = cdll.LoadLibrary('libasound.so') 33 | asound.snd_lib_error_set_handler(c_error_handler) 34 | yield 35 | asound.snd_lib_error_set_handler(None) 36 | except: 37 | yield 38 | pass 39 | 40 | class RingBuffer(object): 41 | """Ring buffer to hold audio from PortAudio""" 42 | 43 | def __init__(self, size=4096): 44 | self._buf = collections.deque(maxlen=size) 45 | 46 | def extend(self, data): 47 | """Adds data to the end of buffer""" 48 | self._buf.extend(data) 49 | 50 | def get(self): 51 | """Retrieves data from the beginning of buffer and clears it""" 52 | tmp = bytes(bytearray(self._buf)) 53 | self._buf.clear() 54 | return tmp 55 | 56 | 57 | def play_audio_file(fname=DETECT_DONG): 58 | """Simple callback function to play a wave file. By default it plays 59 | a Ding sound. 60 | 61 | :param str fname: wave file name 62 | :return: None 63 | """ 64 | ding_wav = wave.open(fname, 'rb') 65 | ding_data = ding_wav.readframes(ding_wav.getnframes()) 66 | with no_alsa_error(): 67 | audio = pyaudio.PyAudio() 68 | stream_out = audio.open( 69 | format=audio.get_format_from_width(ding_wav.getsampwidth()), 70 | channels=ding_wav.getnchannels(), 71 | rate=ding_wav.getframerate(), input=False, output=True) 72 | stream_out.start_stream() 73 | stream_out.write(ding_data) 74 | time.sleep(0.2) 75 | stream_out.stop_stream() 76 | stream_out.close() 77 | audio.terminate() 78 | 79 | 80 | class HotwordDetector(object): 81 | """ 82 | Snowboy decoder to detect whether a keyword specified by `decoder_model` 83 | exists in a microphone input stream. 84 | 85 | :param decoder_model: decoder model file path, a string or a list of strings 86 | :param resource: resource file path. 87 | :param sensitivity: decoder sensitivity, a float of a list of floats. 88 | The bigger the value, the more senstive the 89 | decoder. If an empty list is provided, then the 90 | default sensitivity in the model will be used. 91 | :param audio_gain: multiply input volume by this factor. 92 | :param apply_frontend: applies the frontend processing algorithm if True. 93 | """ 94 | 95 | def __init__(self, decoder_model, 96 | resource=RESOURCE_FILE, 97 | sensitivity=[], 98 | audio_gain=1, 99 | apply_frontend=False): 100 | 101 | tm = type(decoder_model) 102 | ts = type(sensitivity) 103 | if tm is not list: 104 | decoder_model = [decoder_model] 105 | if ts is not list: 106 | sensitivity = [sensitivity] 107 | model_str = ",".join(decoder_model) 108 | 109 | self.recordedData = [] 110 | 111 | self.detector = snowboydetect.SnowboyDetect( 112 | resource_filename=resource.encode(), model_str=model_str.encode()) 113 | self.detector.SetAudioGain(audio_gain) 114 | self.detector.ApplyFrontend(apply_frontend) 115 | self.num_hotwords = self.detector.NumHotwords() 116 | 117 | if len(decoder_model) > 1 and len(sensitivity) == 1: 118 | sensitivity = sensitivity * self.num_hotwords 119 | if len(sensitivity) != 0: 120 | assert self.num_hotwords == len(sensitivity), \ 121 | "number of hotwords in decoder_model (%d) and sensitivity " \ 122 | "(%d) does not match" % (self.num_hotwords, len(sensitivity)) 123 | sensitivity_str = ",".join([str(t) for t in sensitivity]) 124 | if len(sensitivity) != 0: 125 | self.detector.SetSensitivity(sensitivity_str.encode()) 126 | 127 | self.ring_buffer = RingBuffer(self.detector.NumChannels() * self.detector.SampleRate() * 5) 128 | 129 | def start(self, detected_callback=play_audio_file, 130 | interrupt_check=lambda: False, 131 | sleep_time=0.03, 132 | audio_recorder_callback=None, 133 | silent_count_threshold=10, 134 | recording_timeout=58): 135 | """ 136 | Start the stt_tts detector. For every `sleep_time` second it checks the 137 | audio buffer for triggering keywords. If detected, then call 138 | corresponding function in `detected_callback`, which can be a single 139 | function (single model) or a list of callback functions (multiple 140 | models). Every loop it also calls `interrupt_check` -- if it returns 141 | True, then breaks from the loop and return. 142 | 143 | :param detected_callback: a function or list of functions. The number of 144 | items must match the number of models in 145 | `decoder_model`. 146 | :param interrupt_check: a function that returns True if the main loop 147 | needs to stop. 148 | :param float sleep_time: how much time in second every loop waits. 149 | :param audio_recorder_callback: if specified, this will be called after 150 | a keyword has been spoken and after the 151 | phrase immediately after the keyword has 152 | been recorded. The function will be 153 | passed the name of the file where the 154 | phrase was recorded. 155 | :param silent_count_threshold: indicates how long silence must be heard 156 | to mark the end of a phrase that is 157 | being recorded. 158 | :param recording_timeout: limits the maximum length of a recording. 159 | :return: None 160 | """ 161 | self._running = True 162 | 163 | def audio_callback(in_data, frame_count, time_info, status): 164 | self.ring_buffer.extend(in_data) 165 | play_data = chr(0) * len(in_data) 166 | return play_data, pyaudio.paContinue 167 | 168 | with no_alsa_error(): 169 | self.audio = pyaudio.PyAudio() 170 | self.stream_in = self.audio.open( 171 | input=True, output=False, 172 | format=self.audio.get_format_from_width( 173 | self.detector.BitsPerSample() / 8), 174 | channels=self.detector.NumChannels(), 175 | rate=self.detector.SampleRate(), 176 | frames_per_buffer=2048, 177 | stream_callback=audio_callback) 178 | 179 | if interrupt_check(): 180 | logger.debug("detect stt_tts return") 181 | return 182 | 183 | tc = type(detected_callback) 184 | if tc is not list: 185 | detected_callback = [detected_callback] 186 | if len(detected_callback) == 1 and self.num_hotwords > 1: 187 | detected_callback *= self.num_hotwords 188 | 189 | assert self.num_hotwords == len(detected_callback), \ 190 | "Error: hotwords in your models (%d) do not match the number of " \ 191 | "callbacks (%d)" % (self.num_hotwords, len(detected_callback)) 192 | 193 | logger.debug("detecting...") 194 | 195 | state = "PASSIVE" 196 | while self._running is True: 197 | if interrupt_check(): 198 | logger.debug("detect stt_tts break") 199 | break 200 | data = self.ring_buffer.get() 201 | if len(data) == 0: 202 | time.sleep(sleep_time) 203 | continue 204 | 205 | status = self.detector.RunDetection(data) 206 | if status == -1: 207 | logger.warning("Error initializing streams or reading audio data") 208 | 209 | #small state machine to handle recording of phrase after keyword 210 | if state == "PASSIVE": 211 | if status > 0: # key word found 212 | self.recordedData = [] 213 | # self.recordedData.append(data) 214 | silentCount = 0 215 | recordingCount = 0 216 | message = "Keyword " + str(status) + " detected at time: " 217 | message += time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) 218 | logger.info(message) 219 | callback = detected_callback[status-1] 220 | if callback is not None: 221 | callback() 222 | if audio_recorder_callback is not None: 223 | state = "ACTIVE" 224 | continue 225 | 226 | elif state == "ACTIVE": 227 | # print('--------------------------------') 228 | stopRecording = False 229 | if recordingCount > recording_timeout: 230 | stopRecording = True 231 | elif status == -2: #silence found 232 | if silentCount > silent_count_threshold: 233 | stopRecording = True 234 | else: 235 | silentCount = silentCount + 1 236 | elif status == 0: #stt_tts found 237 | silentCount = 0 238 | 239 | if stopRecording == True: 240 | fname = self.saveMessage() 241 | flag_m = audio_recorder_callback(fname) 242 | if flag_m == 1: 243 | logger.info("进入循环对话。。。") 244 | print('recording audio...', end='', flush=True) 245 | self.recordedData = [] 246 | silentCount = 0 247 | recordingCount = 0 248 | # time.sleep(1) 249 | self.ring_buffer.get() 250 | # 我们能发现这个清空缓存的方法比睡眠有效 251 | play_audio_file() 252 | 253 | else: 254 | state = "PASSIVE" 255 | continue 256 | 257 | recordingCount = recordingCount + 1 258 | self.recordedData.append(data) 259 | 260 | logger.debug("finished.") 261 | 262 | def saveMessage(self): 263 | """ 264 | Save the message stored in self.recordedData to a timestamped file. 265 | """ 266 | filename = '../temp/output' + str(int(time.time())) + '.wav' 267 | data = b''.join(self.recordedData) 268 | 269 | #use wave to save data 270 | wf = wave.open(filename, 'wb') 271 | wf.setnchannels(1) 272 | wf.setsampwidth(self.audio.get_sample_size( 273 | self.audio.get_format_from_width( 274 | self.detector.BitsPerSample() / 8))) 275 | wf.setframerate(self.detector.SampleRate()) 276 | wf.writeframes(data) 277 | wf.close() 278 | logger.debug("finished saving: " + filename) 279 | return filename 280 | 281 | def terminate(self): 282 | """ 283 | Terminate audio stream. Users can call start() again to detect. 284 | :return: None 285 | """ 286 | self.stream_in.stop_stream() 287 | self.stream_in.close() 288 | self.audio.terminate() 289 | self._running = False 290 | -------------------------------------------------------------------------------- /hotword/snowboydetect.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 3.0.10 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | 7 | 8 | 9 | 10 | 11 | from sys import version_info as _swig_python_version_info 12 | if _swig_python_version_info >= (2, 7, 0): 13 | def swig_import_helper(): 14 | import importlib 15 | pkg = __name__.rpartition('.')[0] 16 | mname = '.'.join((pkg, '_snowboydetect')).lstrip('.') 17 | try: 18 | return importlib.import_module(mname) 19 | except ImportError: 20 | return importlib.import_module('_snowboydetect') 21 | _snowboydetect = swig_import_helper() 22 | del swig_import_helper 23 | elif _swig_python_version_info >= (2, 6, 0): 24 | def swig_import_helper(): 25 | from os.path import dirname 26 | import imp 27 | fp = None 28 | try: 29 | fp, pathname, description = imp.find_module('_snowboydetect', [dirname(__file__)]) 30 | except ImportError: 31 | import _snowboydetect 32 | return _snowboydetect 33 | if fp is not None: 34 | try: 35 | _mod = imp.load_module('_snowboydetect', fp, pathname, description) 36 | finally: 37 | fp.close() 38 | return _mod 39 | _snowboydetect = swig_import_helper() 40 | del swig_import_helper 41 | else: 42 | import _snowboydetect 43 | del _swig_python_version_info 44 | try: 45 | _swig_property = property 46 | except NameError: 47 | pass # Python < 2.2 doesn't have 'property'. 48 | 49 | try: 50 | import builtins as __builtin__ 51 | except ImportError: 52 | import builtins 53 | 54 | def _swig_setattr_nondynamic(self, class_type, name, value, static=1): 55 | if (name == "thisown"): 56 | return self.this.own(value) 57 | if (name == "this"): 58 | if type(value).__name__ == 'SwigPyObject': 59 | self.__dict__[name] = value 60 | return 61 | method = class_type.__swig_setmethods__.get(name, None) 62 | if method: 63 | return method(self, value) 64 | if (not static): 65 | if _newclass: 66 | object.__setattr__(self, name, value) 67 | else: 68 | self.__dict__[name] = value 69 | else: 70 | raise AttributeError("You cannot add attributes to %s" % self) 71 | 72 | 73 | def _swig_setattr(self, class_type, name, value): 74 | return _swig_setattr_nondynamic(self, class_type, name, value, 0) 75 | 76 | 77 | def _swig_getattr(self, class_type, name): 78 | if (name == "thisown"): 79 | return self.this.own() 80 | method = class_type.__swig_getmethods__.get(name, None) 81 | if method: 82 | return method(self) 83 | raise AttributeError("'%s' object has no attribute '%s'" % (class_type.__name__, name)) 84 | 85 | 86 | def _swig_repr(self): 87 | try: 88 | strthis = "proxy of " + self.this.__repr__() 89 | except __builtin__.Exception: 90 | strthis = "" 91 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 92 | 93 | try: 94 | _object = object 95 | _newclass = 1 96 | except __builtin__.Exception: 97 | class _object: 98 | pass 99 | _newclass = 0 100 | 101 | class SnowboyDetect(_object): 102 | __swig_setmethods__ = {} 103 | __setattr__ = lambda self, name, value: _swig_setattr(self, SnowboyDetect, name, value) 104 | __swig_getmethods__ = {} 105 | __getattr__ = lambda self, name: _swig_getattr(self, SnowboyDetect, name) 106 | __repr__ = _swig_repr 107 | 108 | def __init__(self, resource_filename, model_str): 109 | this = _snowboydetect.new_SnowboyDetect(resource_filename, model_str) 110 | try: 111 | self.this.append(this) 112 | except __builtin__.Exception: 113 | self.this = this 114 | 115 | def Reset(self): 116 | return _snowboydetect.SnowboyDetect_Reset(self) 117 | 118 | def RunDetection(self, *args): 119 | return _snowboydetect.SnowboyDetect_RunDetection(self, *args) 120 | 121 | def SetSensitivity(self, sensitivity_str): 122 | return _snowboydetect.SnowboyDetect_SetSensitivity(self, sensitivity_str) 123 | 124 | def SetHighSensitivity(self, high_sensitivity_str): 125 | return _snowboydetect.SnowboyDetect_SetHighSensitivity(self, high_sensitivity_str) 126 | 127 | def GetSensitivity(self): 128 | return _snowboydetect.SnowboyDetect_GetSensitivity(self) 129 | 130 | def SetAudioGain(self, audio_gain): 131 | return _snowboydetect.SnowboyDetect_SetAudioGain(self, audio_gain) 132 | 133 | def UpdateModel(self): 134 | return _snowboydetect.SnowboyDetect_UpdateModel(self) 135 | 136 | def NumHotwords(self): 137 | return _snowboydetect.SnowboyDetect_NumHotwords(self) 138 | 139 | def ApplyFrontend(self, apply_frontend): 140 | return _snowboydetect.SnowboyDetect_ApplyFrontend(self, apply_frontend) 141 | 142 | def SampleRate(self): 143 | return _snowboydetect.SnowboyDetect_SampleRate(self) 144 | 145 | def NumChannels(self): 146 | return _snowboydetect.SnowboyDetect_NumChannels(self) 147 | 148 | def BitsPerSample(self): 149 | return _snowboydetect.SnowboyDetect_BitsPerSample(self) 150 | __swig_destroy__ = _snowboydetect.delete_SnowboyDetect 151 | __del__ = lambda self: None 152 | SnowboyDetect_swigregister = _snowboydetect.SnowboyDetect_swigregister 153 | SnowboyDetect_swigregister(SnowboyDetect) 154 | 155 | class SnowboyVad(_object): 156 | __swig_setmethods__ = {} 157 | __setattr__ = lambda self, name, value: _swig_setattr(self, SnowboyVad, name, value) 158 | __swig_getmethods__ = {} 159 | __getattr__ = lambda self, name: _swig_getattr(self, SnowboyVad, name) 160 | __repr__ = _swig_repr 161 | 162 | def __init__(self, resource_filename): 163 | this = _snowboydetect.new_SnowboyVad(resource_filename) 164 | try: 165 | self.this.append(this) 166 | except __builtin__.Exception: 167 | self.this = this 168 | 169 | def Reset(self): 170 | return _snowboydetect.SnowboyVad_Reset(self) 171 | 172 | def RunVad(self, *args): 173 | return _snowboydetect.SnowboyVad_RunVad(self, *args) 174 | 175 | def SetAudioGain(self, audio_gain): 176 | return _snowboydetect.SnowboyVad_SetAudioGain(self, audio_gain) 177 | 178 | def ApplyFrontend(self, apply_frontend): 179 | return _snowboydetect.SnowboyVad_ApplyFrontend(self, apply_frontend) 180 | 181 | def SampleRate(self): 182 | return _snowboydetect.SnowboyVad_SampleRate(self) 183 | 184 | def NumChannels(self): 185 | return _snowboydetect.SnowboyVad_NumChannels(self) 186 | 187 | def BitsPerSample(self): 188 | return _snowboydetect.SnowboyVad_BitsPerSample(self) 189 | __swig_destroy__ = _snowboydetect.delete_SnowboyVad 190 | __del__ = lambda self: None 191 | SnowboyVad_swigregister = _snowboydetect.SnowboyVad_swigregister 192 | SnowboyVad_swigregister(SnowboyVad) 193 | 194 | # This file is compatible with both classic and new-style classes. 195 | 196 | 197 | -------------------------------------------------------------------------------- /hotword/try_again_detect.py: -------------------------------------------------------------------------------- 1 | # import sys 2 | # sys.path.append("你的Ass的目录") 3 | # print(sys.path) 4 | # 以上代码仅需在树莓派环境部署时使用 5 | 6 | from hotword import snowboydecoder 7 | import signal 8 | import os 9 | 10 | from stt_tts.baidu import rec_speak_to_text 11 | from stt_tts.baidu_tts_wav import text_to_speak 12 | from tuling.tuling123 import get_response 13 | from tuling.baidu_robot import get_result 14 | 15 | from mouth.play import play_audio_file_playsound 16 | from mouth.play import play_audio_file_change_to_mp3 17 | from mouth.play import play_audio_file_pygame 18 | from mouth.play import play_wave_pyaudio 19 | 20 | interrupted = False 21 | session_id = "" 22 | stop_key_words = ['不聊了', '你歇着吧', '我走了', '我不想聊了'] 23 | 24 | 25 | def audioRecorderCallback(fname): 26 | global session_id 27 | flag_m = 0 28 | print("converting audio to text") 29 | sentence = rec_speak_to_text(fname) 30 | if isinstance(sentence, int): 31 | if sentence == 1: 32 | robot_answer_fname = text_to_speak("网络错误,请稍后重试。") 33 | elif sentence == 0: 34 | if session_id == "": 35 | robot_answer_fname = text_to_speak("你喊我咋啥也不说呢。") 36 | else: 37 | robot_answer_fname = text_to_speak("你怎么突然不说话了呢,那我也不理你了。") 38 | session_id = "" 39 | else: 40 | flag_end = 0 41 | for one_stop_key_word in stop_key_words: 42 | if one_stop_key_word in sentence: 43 | flag_end = 1 44 | break 45 | if flag_end == 1: 46 | robot_answer_fname = text_to_speak("那拜拜咯!下回再聊,你早找我哦,我会想你的。") 47 | session_id = "" 48 | else: 49 | # robot_answer = get_response(sentence) 50 | robot_answer, session_id = get_result(sentence, session_id) 51 | robot_answer_fname = text_to_speak(robot_answer) 52 | flag_m = 1 53 | play_audio_file_playsound(robot_answer_fname) 54 | # print(fname) 55 | # print(robot_answer_fname) 56 | os.remove(fname) 57 | os.remove(robot_answer_fname) 58 | 59 | return flag_m 60 | 61 | 62 | 63 | def detectedCallback(): 64 | snowboydecoder.play_audio_file() 65 | print('recording audio...', end='', flush=True) 66 | 67 | def signal_handler(signal, frame): 68 | global interrupted 69 | interrupted = True 70 | 71 | 72 | def interrupt_callback(): 73 | global interrupted 74 | return interrupted 75 | 76 | # if len(sys.argv) == 1: 77 | # print("Error: need to specify model name") 78 | # print("Usage: python demo.py your.model") 79 | # sys.exit(-1) 80 | 81 | # model = sys.argv[1] 82 | 83 | model = "resources/models/smart_mirror.umdl" 84 | 85 | # capture SIGINT signal, e.g., Ctrl+C 86 | signal.signal(signal.SIGINT, signal_handler) 87 | 88 | detector = snowboydecoder.HotwordDetector(model, sensitivity=0.38) 89 | print('Listening... Press Ctrl+C to exit') 90 | 91 | # main loop 92 | detector.start(detected_callback=detectedCallback, 93 | audio_recorder_callback=audioRecorderCallback, 94 | interrupt_check=interrupt_callback, 95 | sleep_time=0.01) 96 | 97 | detector.terminate() 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /mouth/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/mouth/__init__.py -------------------------------------------------------------------------------- /mouth/play.py: -------------------------------------------------------------------------------- 1 | from playsound import playsound 2 | from pydub import AudioSegment 3 | import pyaudio 4 | import wave 5 | import os 6 | import time 7 | import pygame 8 | 9 | CHUNK = 1024 10 | 11 | 12 | def play_audio_file_playsound(fname): 13 | playsound(fname) 14 | 15 | 16 | def play_audio_file_pygame(fname): 17 | pygame.mixer.init() 18 | pygame.mixer.music.load(fname) 19 | pygame.mixer.music.play() 20 | while pygame.mixer.music.get_busy() == True: 21 | continue 22 | 23 | 24 | def play_wave_pyaudio(filename): 25 | wf = wave.open(filename, 'rb') 26 | 27 | p = pyaudio.PyAudio() 28 | stream = p.open(format=p.get_format_from_width(wf.getsampwidth()), 29 | channels=wf.getnchannels(), 30 | rate=wf.getframerate(), 31 | output=True) 32 | 33 | data = wf.readframes(CHUNK) 34 | 35 | while data: 36 | stream.write(data) 37 | data = wf.readframes(CHUNK) 38 | 39 | stream.stop_stream() 40 | stream.close() 41 | 42 | p.terminate() 43 | 44 | 45 | def play_audio_file_change_to_mp3(fname): 46 | song = AudioSegment.from_mp3(fname) 47 | filename = '../temp/baidu' + str(int(time.time())) + '1.mp3' 48 | song.export(filename, format="wav") 49 | play_wave_pyaudio(filename) 50 | os.remove(filename) 51 | 52 | 53 | if __name__ == "__main__": 54 | play_audio_file_playsound("../temp/baidu1564470005.mp3") -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 智能助手 Try Again 2 | 3 | ## 注意 4 | 尽量先看完整个介绍再动手,过些天会有相关的制作过程的教学 5 | 视频上传,目前还未处理完。 6 | 7 | [本项目制作的视频教程](https://www.bilibili.com/video/av61588252) 8 | 9 | ## 新的版本,可玩性更好一点 10 | 11 | dev分之 12 | 13 | ## 效果 14 | 15 | 请看视频教程第六集 16 | 17 | ###目前测试成功的运行平台 18 | 19 | 1. Ubuntu18.04 20 | 2. 树莓派3B+ 21 | 3. 理论上支持大部分Linux系统 22 | 23 | ## 思路 24 | ### 唤醒模块 25 | 26 | 使用snowboy。 27 | 28 | 1. 唤醒模块一旦唤醒,暂时就不工作。直到该次唤醒工作结束后再 29 | 继续工作 30 | 2. 唤醒之后,我们检查网络状态 31 | 32 | ### 录音模块 33 | 34 | PyAudio 35 | 36 | 1. 10s之内没有人说话就自动关闭 37 | 38 | 系统继续进入等待唤醒状态 39 | 40 | 2. 10s之后如果唤醒人继续在讲话,那么我们需要继续录音 41 | 42 | 如果录音长度超过30s,我们就暂停录音,提示你也太啰嗦了 43 | 否则我们就正常的进入下一步 44 | 45 | 3. 录制完成的音频,存储成wav,流处理的方式直接进行stt处理 46 | 47 | 录音完成之后我们的录音模块暂时就停止工作 48 | 49 | ### 语音转文字stt 50 | 51 | Baidu stt 52 | 53 | 1. 将使用百度的python的stt 54 | 2. 返回文字,我们接收文字。 55 | 3. 如果我们返回文字是空的或者其他的错误,我们提示您能再说 56 | 一遍吗,我没听清楚(自动进入录音状态)。出错后跟出错 57 | 提示,做出相应的反馈,网络错误(进入待唤醒状态) 58 | 59 | ### 对话机器人 60 | 61 | tuling123.com的对话机器人 62 | 63 | 1. 我们免费对话机器人 64 | 2. 需要上传我们文字 65 | 3. 返回他的答案 66 | 4. 返回出错,处理方式同上 67 | 68 | ### 文字转语音模块tts 69 | 70 | 百度tts模块 71 | 72 | 1. 将对话机器人,返回文字转换成语音 73 | 2. 返回语音如果出错,我们处理同上 74 | 75 | ### 播放模块 76 | 77 | PyAudio 78 | 79 | 1. 将这个语音播放出来 80 | 81 | ### 主体控制模块 82 | 83 | 1. 当对话机器人回应唤醒人的时候,是否自动进入下一轮的录音 84 | 或者,是回应完之后就进入待唤醒状态。 85 | 2. 如果加入只能家具控制,那么我们需要两种方式来做 86 | 87 | a. 我们从这个stt返回后的语句中查询对应的关键字,然后 88 | 处理。 89 | b. 使用其他的唤醒词,Again Try。 90 | 91 | ### nlp的意图匹配模块 92 | 93 | 示例: 94 | 95 | 我说:帮我把灯打开 96 | 97 | 系统(明白是我要打开我的灯,而不是和它聊天):打开灯 98 | 99 | 我不想聊了 100 | 101 | 系统要退出循环聊天 102 | 103 | 104 | 105 | 106 | ## 开始手动配置 107 | 108 | ### 唤醒模块 109 | 110 | 1.配置snowboy的编译环境 111 | 112 | sudo apt-get install python-pyaudio python3-pyaudio sox 113 | 114 | sudo pip install pyaudio 115 | 116 | sudo pip3 install pyaudio 117 | 118 | cd 你的项目根目录/ 119 | 120 | mkdir SBCompile 121 | 122 | wget http://downloads.sourceforge.net/swig/swig-3.0.10.tar.gz 123 | 124 | sudo apt-get install libpcre3 libpcre3-dev 125 | 126 | ls 127 | 128 | tar -zxvf swig-3.0.10.tar.gz 129 | 130 | cd swig-3.0.10/ 131 | 132 | ./configure --prefix=/usr --without-clisp --without-maximum-compile-warnings && make 133 | 134 | sudo make install 135 | 136 | sudo install -v -m755 -d /usr/share/doc/swig-3.0.10 137 | 138 | sudo cp -v -R Doc/* /usr/share/doc/swig-3.0.10 139 | 140 | sudo apt-get install libatlas-base-dev 141 | 142 | cd .. 143 | 144 | mkdir rec_voice 145 | 146 | cd rec_voice/ 147 | 148 | ls 149 | 150 | rec 1.wav 151 | 152 | ls 153 | 154 | 编译snowboy的准备工作结束 155 | 156 | cd .. 157 | 158 | git clone https://github.com/Kitt-AI/snowboy.git 159 | 160 | (这个是我没看明白,下面这句不用执行,把视频看下去就知道了) 161 | sudo apt-get install libmagic-dev libatlas-base-dev 162 | 163 | cd snowboy/ 164 | 165 | cd swig/ 166 | 167 | cd Python/ 168 | 169 | make 170 | 171 | cd .. 172 | 173 | cd Python3/ 174 | 175 | make 176 | 177 | exit 178 | 179 | ### 语音识别模块 180 | 181 | sudo pip3 install baidu-aip 182 | 183 | exit 184 | 185 | ### 对话模块 186 | 187 | 主要是代码 188 | 189 | ### 语音合成模块 190 | 191 | 与语音识别模块一直,主要是写几个代码 192 | 193 | ### 语音播放模块 194 | 195 | sudo pip3 install playsound 196 | 197 | ## 运行 198 | 199 | 需要更新stt_tts下的appid ak sk,理论上就可以在hotword下 200 | 的try_again_detect.py直接运行就行。实际上可能需要安装一些库 201 | 大家最好就是看看上面的过程。默认的唤醒词是smart mirror 202 | 203 | 本项目主要的目的在于给大家一个手动制作一个智能音箱的示例 204 | 如果真的想要实用,建议使用本文最后的 205 | [Wukong](https://github.com/wzpan/wukong-robot)项目 206 | 207 | 本项目还有对应的教学视频,目前还未对一些秘钥进行打码,所以暂未 208 | 上传,之后将免费给大家。 209 | 210 | 211 | ## 相关物 212 | 213 | [百度语音技术](https://ai.baidu.com/tech/speech/asr) 214 | 215 | [Snowboy](https://snowboy.kitt.ai) 216 | 217 | [Tuling123代码源](https://github.com/littlecodersh/EasierLife/blob/master/Plugins/Tuling/tuling.py) 218 | 219 | [Tuling123官网](http://www.turingapi.com/) 220 | 221 | [emotibot](http://botfactory.emotibot.com/) 222 | 223 | [Wukong](https://github.com/wzpan/wukong-robot) 224 | 225 | [百度的对话机器人](https://ai.baidu.com/docs#/UNIT-v2-service-API/top) 226 | 227 | ## 所有权声明 228 | 229 | 1. 本项目所有外部资源来源于网络,如有问题,请联系我删除。 230 | 2. 本项目仅可用于个人DIY使用,禁止用于商业目的。 231 | 3. 本项目使用后造成的后果,本人一概不负责任。 232 | 4. 本项目立项目标是在于告诉大家怎么去建立这样一个系统,如果只是想搭建一个基于树莓派 233 | 等的智能系统,建议使用文中提到的WuKong项目,该项目由腾讯工程师建立。远远强于我这个 234 | 本科生。 235 | 5. 关于捐赠,若果真的想给就在B站投个币吧,或者以下二维码 236 | 237 | ![二维码](https://github.com/Yaque/FriutShop/blob/master/show/money/zhifubao_hongbao.jpg) -------------------------------------------------------------------------------- /stt_tts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/stt_tts/__init__.py -------------------------------------------------------------------------------- /stt_tts/baidu.py: -------------------------------------------------------------------------------- 1 | from aip import AipSpeech 2 | import time 3 | 4 | """ 你的 APPID AK SK """ 5 | APP_ID = '11684493' 6 | API_KEY = 'XYShi1grKEeqssWISnhr3EupVLLliChi' 7 | # SECRET_KEY = '***************************' 8 | SECRET_KEY = '18XEgGeDdWfHKZ8lUbsZLynRzQOtwpSN' 9 | 10 | # 由于公开的秘钥不好,所以不给 11 | client = AipSpeech(APP_ID, API_KEY, SECRET_KEY) 12 | 13 | # 读取文件 14 | def get_file_content(filePath): 15 | with open(filePath, 'rb') as fp: 16 | return fp.read() 17 | 18 | # 识别本地文件 19 | def rec_speak_to_text(fname): 20 | result = 0 21 | try: 22 | sentence = client.asr(get_file_content(fname), 'wav', 16000, { 23 | 'dev_pid': 1536, 24 | }) 25 | print(sentence) 26 | if sentence['err_no'] == 0: 27 | result_list = sentence['result'] 28 | for i, one in enumerate(result_list): 29 | if i != 0: 30 | result = result + "。" + one 31 | else: 32 | result = one 33 | except: 34 | return 1 35 | return result 36 | 37 | 38 | def text_to_speak(sentence): 39 | try: 40 | result = client.synthesis(sentence, 'zh', 4, { 41 | 'vol': 6, 42 | 'spd': 6, 43 | 'pit': 5, 44 | }) 45 | filename = '../temp/baidu' + str(int(time.time())) + '.mp3' 46 | # 识别正确返回语音二进制 错误则返回dict 参照下面错误码 47 | if not isinstance(result, dict): 48 | with open(filename, 'wb') as f: 49 | f.write(result) 50 | except: 51 | return "../temp/net_error.mp3" 52 | return filename 53 | 54 | 55 | if __name__ == "__main__": 56 | # s = rec_speak_to_text("../temp/output1564468756.wav") 57 | # print(s) 58 | text_to_speak("网络错误,请稍后重试。") -------------------------------------------------------------------------------- /stt_tts/baidu_tts_wav.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import sys 3 | import json 4 | import time 5 | 6 | from urllib.request import urlopen 7 | from urllib.request import Request 8 | from urllib.error import URLError 9 | from urllib.parse import urlencode 10 | from urllib.parse import quote_plus 11 | 12 | API_KEY = '4E1BG9lTnlSeIf1NQFlrSq6h' 13 | SECRET_KEY = '544ca4657ba8002e3dea3ac2f5fdd241' 14 | ACCESS_TOKEN = '24.28cff53af4acb2cf08649af5802eac0e.2592000.1567086565.282335-16920155' 15 | # 发音人选择, 基础音库:0为度小美,1为度小宇,3为度逍遥,4为度丫丫, 16 | # 精品音库:5为度小娇,103为度米朵,106为度博文,110为度小童,111为度小萌,默认为度小美 17 | PER = 111 18 | # 语速,取值0-15,默认为5中语速 19 | SPD = 5 20 | # 音调,取值0-15,默认为5中语调 21 | PIT = 5 22 | # 音量,取值0-9,默认为5中音量 23 | VOL = 5 24 | # 下载的文件格式, 3:mp3(default) 4: pcm-16k 5: pcm-8k 6. wav 25 | AUE = 6 26 | 27 | FORMATS = {3: ".mp3", 4: ".pcm", 5: ".pcm", 6: ".wav"} 28 | FORMAT = FORMATS[AUE] 29 | 30 | CUID = "123456PYTHON" 31 | 32 | TTS_URL = 'http://tsn.baidu.com/text2audio' 33 | 34 | 35 | class DemoError(Exception): 36 | pass 37 | 38 | 39 | """ TOKEN start """ 40 | 41 | TOKEN_URL = 'http://openapi.baidu.com/oauth/2.0/token' 42 | SCOPE = 'audio_tts_post' # 有此scope表示有tts能力,没有请在网页里勾选 43 | 44 | 45 | def fetch_token(): 46 | print("fetch token begin") 47 | params = {'grant_type': 'client_credentials', 48 | 'client_id': API_KEY, 49 | 'client_secret': SECRET_KEY} 50 | post_data = urlencode(params) 51 | post_data = post_data.encode('utf-8') 52 | req = Request(TOKEN_URL, post_data) 53 | try: 54 | f = urlopen(req, timeout=5) 55 | result_str = f.read() 56 | except URLError as err: 57 | print('token http response http code : ' + str(err.code)) 58 | result_str = err.read() 59 | result_str = result_str.decode() 60 | 61 | print(result_str) 62 | result = json.loads(result_str) 63 | print(result) 64 | if ('access_token' in result.keys() and 'scope' in result.keys()): 65 | if not SCOPE in result['scope'].split(' '): 66 | raise DemoError('scope is not correct') 67 | print('SUCCESS WITH TOKEN: %s ; EXPIRES IN SECONDS: %s' % (result['access_token'], result['expires_in'])) 68 | return result['access_token'] 69 | else: 70 | raise DemoError('MAYBE API_KEY or SECRET_KEY not correct: access_token or scope not found in token response') 71 | """ TOKEN end """ 72 | 73 | 74 | def text_to_speak(text): 75 | token = ACCESS_TOKEN 76 | tex = quote_plus(text) # 此处TEXT需要两次urlencode 77 | print("AAAAAAAAAA" + tex) 78 | params = {'tok': token, 'tex': tex, 'per': PER, 'spd': SPD, 'pit': PIT, 'vol': VOL, 'aue': AUE, 'cuid': CUID, 79 | 'lan': 'zh', 'ctp': 1} # lan ctp 固定参数 80 | 81 | data = urlencode(params) 82 | print('test on Web Browser' + TTS_URL + '?' + data) 83 | 84 | req = Request(TTS_URL, data.encode('utf-8')) 85 | has_error = False 86 | try: 87 | f = urlopen(req) 88 | result_str = f.read() 89 | 90 | headers = dict((name.lower(), value) for name, value in f.headers.items()) 91 | 92 | has_error = ('content-type' not in headers.keys() or headers['content-type'].find('audio/') < 0) 93 | except URLError as err: 94 | print('asr http response http code : ' + str(err.code)) 95 | result_str = err.read() 96 | has_error = True 97 | 98 | save_filename = '../temp/baidu' + str(int(time.time())) + FORMAT 99 | save_file = "error.txt" if has_error else save_filename 100 | with open(save_file, 'wb') as of: 101 | of.write(result_str) 102 | 103 | if has_error: 104 | result_str = str(result_str, 'utf-8') 105 | print("tts api error:" + result_str) 106 | 107 | print("result saved as :" + save_file) 108 | return save_file 109 | 110 | 111 | if __name__ == '__main__': 112 | fname = text_to_speak("网络错误,请稍后重试。") 113 | print(fname) -------------------------------------------------------------------------------- /temp/baidu_tts.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import sys 3 | import json 4 | 5 | from urllib.request import urlopen 6 | from urllib.request import Request 7 | from urllib.error import URLError 8 | from urllib.parse import urlencode 9 | from urllib.parse import quote_plus 10 | 11 | API_KEY = '4E1BG9lTnlSeIf1NQFlrSq6h' 12 | SECRET_KEY = '544ca4657ba8002e3dea3ac2f5fdd241' 13 | ACCESS_TOKEN = '24.28cff53af4acb2cf08649af5802eac0e.2592000.1567086565.282335-16920155' 14 | # 发音人选择, 基础音库:0为度小美,1为度小宇,3为度逍遥,4为度丫丫, 15 | # 精品音库:5为度小娇,103为度米朵,106为度博文,110为度小童,111为度小萌,默认为度小美 16 | PER = 4 17 | # 语速,取值0-15,默认为5中语速 18 | SPD = 5 19 | # 音调,取值0-15,默认为5中语调 20 | PIT = 5 21 | # 音量,取值0-9,默认为5中音量 22 | VOL = 5 23 | # 下载的文件格式, 3:mp3(default) 4: pcm-16k 5: pcm-8k 6. wav 24 | AUE = 6 25 | 26 | FORMATS = {3: "mp3", 4: "pcm", 5: "pcm", 6: "wav"} 27 | FORMAT = FORMATS[AUE] 28 | 29 | CUID = "123456PYTHON" 30 | 31 | TTS_URL = 'http://tsn.baidu.com/text2audio' 32 | 33 | 34 | class DemoError(Exception): 35 | pass 36 | 37 | 38 | """ TOKEN start """ 39 | 40 | TOKEN_URL = 'http://openapi.baidu.com/oauth/2.0/token' 41 | SCOPE = 'audio_tts_post' # 有此scope表示有tts能力,没有请在网页里勾选 42 | 43 | 44 | def fetch_token(): 45 | print("fetch token begin") 46 | params = {'grant_type': 'client_credentials', 47 | 'client_id': API_KEY, 48 | 'client_secret': SECRET_KEY} 49 | post_data = urlencode(params) 50 | post_data = post_data.encode('utf-8') 51 | req = Request(TOKEN_URL, post_data) 52 | try: 53 | f = urlopen(req, timeout=5) 54 | result_str = f.read() 55 | except URLError as err: 56 | print('token http response http code : ' + str(err.code)) 57 | result_str = err.read() 58 | result_str = result_str.decode() 59 | 60 | print(result_str) 61 | result = json.loads(result_str) 62 | print(result) 63 | if ('access_token' in result.keys() and 'scope' in result.keys()): 64 | if not SCOPE in result['scope'].split(' '): 65 | raise DemoError('scope is not correct') 66 | print('SUCCESS WITH TOKEN: %s ; EXPIRES IN SECONDS: %s' % (result['access_token'], result['expires_in'])) 67 | return result['access_token'] 68 | else: 69 | raise DemoError('MAYBE API_KEY or SECRET_KEY not correct: access_token or scope not found in token response') 70 | """ TOKEN end """ 71 | 72 | 73 | def text_to_speak(text): 74 | token = ACCESS_TOKEN 75 | tex = quote_plus(text) # 此处TEXT需要两次urlencode 76 | print("AAAAAAAAAA" + tex) 77 | params = {'tok': token, 'tex': tex, 'per': PER, 'spd': SPD, 'pit': PIT, 'vol': VOL, 'aue': AUE, 'cuid': CUID, 78 | 'lan': 'zh', 'ctp': 1} # lan ctp 固定参数 79 | 80 | data = urlencode(params) 81 | print('test on Web Browser' + TTS_URL + '?' + data) 82 | 83 | req = Request(TTS_URL, data.encode('utf-8')) 84 | has_error = False 85 | try: 86 | f = urlopen(req) 87 | result_str = f.read() 88 | 89 | headers = dict((name.lower(), value) for name, value in f.headers.items()) 90 | 91 | has_error = ('content-type' not in headers.keys() or headers['content-type'].find('audio/') < 0) 92 | except URLError as err: 93 | print('asr http response http code : ' + str(err.code)) 94 | result_str = err.read() 95 | has_error = True 96 | 97 | save_file = "error.txt" if has_error else 'result.' + FORMAT 98 | with open(save_file, 'wb') as of: 99 | of.write(result_str) 100 | 101 | if has_error: 102 | result_str = str(result_str, 'utf-8') 103 | print("tts api error:" + result_str) 104 | 105 | print("result saved as :" + save_file) 106 | return save_file 107 | 108 | 109 | if __name__ == '__main__': 110 | fname = text_to_speak("你好。") 111 | print(fname) -------------------------------------------------------------------------------- /tuling/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOCW/EasyAss/fe2addd9561e3b5b33653636e4092c91b7959531/tuling/__init__.py -------------------------------------------------------------------------------- /tuling/baidu_robot.py: -------------------------------------------------------------------------------- 1 | import urllib 2 | import ssl 3 | import json 4 | import random 5 | 6 | # # client_id 为官网获取的AK, client_secret 为官网获取的SK 7 | # host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=ak&client_secret=sk' 8 | # request = urllib.request.Request(host) 9 | # request.add_header('Content-Type', 'application/json; charset=UTF-8') 10 | # response = urllib.request.urlopen(request) 11 | # content = response.read() 12 | # if (content): 13 | # print(content) 14 | # 15 | # content.decode('utf-8') 16 | # content = json.loads(content) 17 | # print(content['access_token']) 18 | 19 | #-*- version: Python3.0 -* 20 | #-*- coding: UTF-8 -* 21 | import urllib.request 22 | 23 | headers = {'Content-Type':'application/json'} 24 | # access_token = content['access_token'] 25 | access_token = '24.28cff53af4acb2cf08649af5802eac0e.2592000.1567086565.282335-16920155' 26 | print(access_token) 27 | 28 | 29 | def get_result(question, session_id): 30 | url = 'https://aip.baidubce.com/rpc/2.0/unit/service/chat?access_token=' + access_token 31 | post_data = '{"log_id":"try_again88888888",' \ 32 | '"version":"2.0",' \ 33 | '"service_id":"S20770",' \ 34 | '"session_id":"' + session_id + '",' \ 35 | '"request":{"query":"' + question + '","user_id":"88888"},' \ 36 | '"dialog_state":{"contexts":{"SYS_REMEMBERED_SKILLS":["1057"]}}}' 37 | try: 38 | request = urllib.request.Request(url,data=post_data.encode('utf-8'),headers=headers) 39 | response = urllib.request.urlopen(request) 40 | content = response.read().decode("utf-8") 41 | content = json.loads(content) 42 | except: 43 | return "哦哦,我卡住了", None 44 | if content: 45 | # print(content) 46 | result = content['result'] 47 | # print(result) 48 | session_id = result['session_id'] 49 | # print(session_id) 50 | response = result['response_list'][0] 51 | # print(response) 52 | action_list = response['action_list'] 53 | l = len(action_list) 54 | # print(l) 55 | r_int = random.randint(0, l - 1) 56 | # print(r_int) 57 | action = action_list[r_int] 58 | # print(action) 59 | say = action['say'] 60 | print(say) 61 | return say, session_id 62 | return "哦哦,我卡住了", None 63 | 64 | 65 | "{'result': " \ 66 | "{" \ 67 | "'version': '2.0'," \ 68 | " 'timestamp': '2019-07-30 22:00:25.715'," \ 69 | " 'service_id': 'S20770', " \ 70 | "'log_id': 'try_again88888888'," \ 71 | " 'session_id': 'service-session-id-1564495225715-0504cdd87fa54fad91e29012428bf5b4'," \ 72 | " 'interaction_id': 'service-interactive-id-1564495225715-e69daa6019654b8c862a35dfc87d0123', " \ 73 | "'response_list': " \ 74 | "[{'status': 0," \ 75 | " 'msg': 'ok'," \ 76 | " 'origin': '71559'," \ 77 | " 'schema': {'intent_confidence': 1.0, 'intent': 'BUILT_CHAT'}," \ 78 | "'action_list':" \ 79 | " [" \ 80 | "{'action_id': '','refine_detail': {},'confidence': 1.0, 'custom_reply': '', 'say': '你好,想聊什么呢。~','type': 'chat'}, " \ 81 | "{'action_id': '', 'refine_detail': {}, 'confidence': 1.0, 'custom_reply': '', 'say': '有礼貌的好孩子', 'type': 'chat'}, " \ 82 | "{'action_id': '', 'refine_detail': {}, 'confidence': 1.0, 'custom_reply': '', 'say': '你好。咱们聊一会呀', 'type': 'chat'}" \ 83 | "]," \ 84 | " 'qu_res': {}}" \ 85 | "], " \ 86 | "'dialog_state': " \ 87 | "{'contexts': {'SYS_REMEMBERED_SKILLS': []}, 'skill_states': {}}}, 'error_code': 0}" 88 | 89 | 90 | if __name__ == "__main__": 91 | response, session_id = get_result("现在几点了", "") 92 | print(response, session_id) -------------------------------------------------------------------------------- /tuling/tuling123.py: -------------------------------------------------------------------------------- 1 | #coding=utf8 2 | import sys, os 3 | import requests, json 4 | 5 | try: 6 | with open('../config.json') as f: key = json.loads(f.read())['key'] 7 | except: 8 | key = '' # if key is '', get_response will return None 9 | # raise Exception('There is something wrong with the format of you plugin/config/tuling.json') 10 | 11 | def get_response(msg, storageClass = None, userName = None, userid = 'ItChat'): 12 | print('tuling:' + msg) 13 | url = 'http://www.tuling123.com/openapi/api' 14 | payloads = { 15 | 'key': key, 16 | 'info': msg, 17 | 'userid': userid, 18 | } 19 | try: 20 | r = requests.post(url, data = json.dumps(payloads)).json() 21 | print(r) 22 | except: 23 | return 24 | if not r['code'] in (100000, 200000, 302000, 308000, 313000, 314000): 25 | return "对不起,我脑袋卡住了,回答不上来。" 26 | if r['code'] == 100000: # 文本类 27 | return '\n'.join([r['text'].replace('
','\n')]) 28 | elif r['code'] == 200000: # 链接类 29 | return '\n'.join([r['text'].replace('
','\n'), r['url']]) 30 | elif r['code'] == 302000: # 新闻类 31 | l = [r['text'].replace('
','\n')] 32 | for n in r['list']: l.append('%s - %s'%(n['article'], n['detailurl'])) 33 | return '\n'.join(l) 34 | elif r['code'] == 308000: # 菜谱类 35 | l = [r['text'].replace('
','\n')] 36 | for n in r['list']: l.append('%s - %s'%(n['name'], n['detailurl'])) 37 | return '\n'.join(l) 38 | elif r['code'] == 313000: # 儿歌类 39 | return '\n'.join([r['text'].replace('
','\n')]) 40 | elif r['code'] == 314000: # 诗词类 41 | return '\n'.join([r['text'].replace('
','\n')]) 42 | 43 | if __name__ == '__main__': 44 | try: 45 | ipt = input 46 | except: 47 | ipt = lambda: input('>') 48 | while True: 49 | a = ipt() 50 | print(get_response(a, 'ItChat')) --------------------------------------------------------------------------------