123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- # -*- coding: utf-8 -*-
- from __future__ import division
- from .__load__ import *
- class Robot(object):
- tool = {}
- def init(self, profiling=False):
- self.start()
- # 历史记录
- self.history = []
- # 数据文件夹
- self.data = Demeter.config['vecan']['data']
- # 日志
- self.logger = Log.init(__name__)
- # 是否正在录音
- self.isRecording = False
- # 插件验证--暂时无用
- self.matchPlugin = None
- # 勿扰模式
- self.immersiveMode = None
- # 优化
- self.profiling = profiling
- # 询问模式
- self.hasPardon = False
- # 播放器
- self.player = None
- # snowboy
- self.snowboy = None
- # 对话
- self.onSay = None
- # 技能
- self.skill = None
- def initSnowboy(self, snowboy):
- self.snowboy = snowboy
- def getSnowBoy(self):
- if self.snowboy:
- return self.snowboy
- else:
- self.snowboy = Demeter.service('snowboy')
- self.snowboy.init(self)
- return self.snowboy
- def getHistory(self):
- return self.history
- def say(self, msg, cache=False, plugin='', completed=None):
- print msg
- if self.onSay:
- self.logger.info('onSay: {}'.format(msg))
- if plugin != '':
- self.onSay("[{}] {}".format(plugin, msg))
- else:
- self.onSay(msg)
- self.onSay = None
- if plugin != '':
- self.appendHistory(1, "[{}] {}".format(plugin, msg))
- else:
- self.appendHistory(1, msg)
- pattern = r'^https?://.+'
- if re.match(pattern, msg):
- self.logger.info('内容包含URL,无法读取')
- return
- voice = ''
- voice = self.tool['tts'].tts(msg)
- if cache:
- saveCache(voice, msg)
- '''
- if getCache(msg):
- self.logger.info('命中缓存,播放缓存语音')
- voice = getCache(msg)
- else:
- try:
- voice = self.tool['tts'].tts(msg)
- if cache:
- saveCache(voice, msg)
- except Exception as e:
- self.logger.error('保存缓存失败:{}'.format(e))
- '''
- if completed is None:
- completed = lambda: self.completed(msg)
- self.play(voice, not cache, completed=completed)
- def play(self, voice, delete=False, completed=None):
- if self.player == None:
- self.player = Demeter.service('sox', 'player')
- self.player.play(voice, delete=delete, onCompleted=completed)
- def start(self):
- # 机器人配置,后续改成从数据库读取
- self.config = Demeter.config['robot']
- self.reload()
- def reload(self):
- try:
- for item in self.config:
- setting = self.setting(self.config[item])
- if item not in self.tool:
- self.tool[item] = Demeter.service(self.config[item], 'api')
- self.tool[item].setting(**setting)
- self.player = None
- self.skill = Demeter.service('skill')
- self.skill.init(self)
- self.skill.printPlugins()
- except Exception as e:
- self.logger.critical('机器人初始化失败:{}'.format(e))
- def checkRestore(self):
- if self.immersiveMode:
- self.skill.restore()
- def checkPlayer(self):
- return self.player is not None and self.player.is_playing()
- def setting(self, name):
- # 后续要改成数据库读取
- config = Demeter.config[name]
- return config
- # 中断、停止
- def interrupt(self):
- if self.checkPlayer():
- self.player.stop()
- self.player = None
- if self.immersiveMode:
- self.skill.pause()
- def talk(self, fp, callback=None):
- self.play(self.data + 'beep_lo.wav')
- self.logger.info('结束录音')
- self.isRecording = False
- if self.profiling:
- self.logger.info('性能调试已打开')
- pr = cProfile.Profile()
- pr.enable()
- self.onTalk(fp, callback)
- pr.disable()
- s = io.StringIO()
- sortby = 'cumulative'
- ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
- ps.print_stats()
- print(s.getvalue())
- else:
- self.onTalk(fp, callback)
- def onTalk(self, fp, callback=None, onSay=None):
- try:
- self.interrupt()
- query = self.tool['asr'].asr(fp)
- File.remove(fp)
- self.response(query, callback, onSay)
- except Exception as e:
- self.logger.critical(e)
- clean()
- def doParse(self, query, **args):
- return self.tool['nlu'].nlu(query, **args)
- def setImmersiveMode(self, slug):
- self.immersiveMode = slug
- def getImmersiveMode(self):
- return self.immersiveMode
- def response(self, query, uid='', onSay=None):
- # 统计
- #statistic.report(1)
- self.interrupt()
- self.appendHistory(0, query, uid)
- if onSay:
- self.onSay = onSay
- if query.strip() == '':
- self.pardon()
- return
- lastImmersiveMode = self.immersiveMode
- if not self.skill.query(query):
- # 没命中技能,使用机器人回复
- msg = self.tool['ai'].ai(query)
- self.say(msg, True, completed=self.checkRestore)
- else:
- if lastImmersiveMode is not None and lastImmersiveMode != self.matchPlugin:
- time.sleep(1)
- if self.checkPlayer():
- self.logger.debug('等说完再checkRestore')
- self.player.appendOnCompleted(lambda: self.checkRestore())
- else:
- self.logger.debug('checkRestore')
- self.checkRestore()
- #将会话历史加进历史记录
- def appendHistory(self, t, text, uid=''):
- if t in (0, 1) and text != '':
- if text.endswith(',') or text.endswith(','):
- text = text[:-1]
- if uid == '' or uid == None or uid == 'null':
- uid = Demeter.uuid(__name__)
- # 将图片处理成HTML
- pattern = r'https?://.+\.(?:png|jpg|jpeg|bmp|gif|JPG|PNG|JPEG|BMP|GIF)'
- url_pattern = r'^https?://.+'
- imgs = re.findall(pattern, text)
- for img in imgs:
- text = text.replace(img, '<img src={} class="img"/>'.format(img))
- urls = re.findall(url_pattern, text)
- for url in urls:
- text = text.replace(url, '<a href={} target="_blank">{}</a>'.format(url, url))
- self.history.append({'type': t, 'text': text, 'time': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())), 'uid': uid})
- def completed(self, msg):
- if Demeter.config['snowboy']['active_mode'] and (msg.endswith('?') or msg.endswith(u'?') or u'告诉我' in msg or u'请回答' in msg):
- query = self.getSnowBoy().listen()
- self.response(query)
- def pardon(self):
- if not self.hasPardon:
- self.say('抱歉,刚刚没听清,能再说一遍吗?', completed=lambda: self.response(self.getSnowBoy().listen()))
- self.hasPardon = True
- else:
- self.say('没听清呢')
- self.hasPardon = False
|