Skip to content
This repository has been archived by the owner on Apr 13, 2018. It is now read-only.

Commit

Permalink
完善微信控制音乐播放的功能
Browse files Browse the repository at this point in the history
  • Loading branch information
wzpan committed Jun 18, 2017
1 parent 07209e5 commit fc2154a
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 48 deletions.
21 changes: 18 additions & 3 deletions client/brain.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def __init__(self, mic, profile):

self.mic = mic
self.profile = profile
self.plugins = self.get_plugins()
(self.plugins, self.exclude_plugins) = self.get_plugins()
self._logger = logging.getLogger(__name__)
self.handling = False

Expand All @@ -38,6 +38,9 @@ def get_plugins(cls):
logger.debug("Looking for plugins in: %s",
', '.join(["'%s'" % location for location in locations]))
plugins = []
exclude_plugins = []
# plugins that are not allow to be call via Wechat or Email
thirdparty_exclude_plugins = ['NetEaseMusic']
for finder, name, ispkg in pkgutil.walk_packages(locations):
try:
loader = finder.find_module(name)
Expand All @@ -50,14 +53,16 @@ def get_plugins(cls):
logger.debug("Found plugin '%s' with words: %r", name,
mod.WORDS)
plugins.append(mod)
if name in thirdparty_exclude_plugins:
exclude_plugins.append(mod)
else:
logger.warning("Skipped plugin '%s' because it misses " +
"the WORDS constant.", name)
plugins.sort(key=lambda mod: mod.PRIORITY if hasattr(mod, 'PRIORITY')
else 0, reverse=True)
return plugins
return (plugins, exclude_plugins)

def query(self, texts, wxbot=None):
def query(self, texts, wxbot=None, thirdparty_call=False):
"""
Passes user input to the appropriate plugin, testing it against
each candidate plugin's isValid function.
Expand All @@ -66,6 +71,16 @@ def query(self, texts, wxbot=None):
text -- user input, typically speech, to be parsed by a plugin
send_wechat -- also send the respondsed result to wechat
"""
if thirdparty_call:
# check whether plugin is not allow to be call by thirdparty
for plugin in self.exclude_plugins:
for text in texts:
if plugin.isValid(text):
self.mic.say(u"抱歉,该功能暂时只能通过语音" +
"命令开启。请试试唤醒我后直接" +
"对我说\"%s\"" % text)
return

for plugin in self.plugins:
for text in texts:
if plugin.isValid(text):
Expand Down
3 changes: 3 additions & 0 deletions client/conversation.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ def handleForever(self):
str(notif))
self.mic.say(str(notif))

if self.mic.stop_passive:
continue

self._logger.debug("Started listening for keyword '%s'",
self.persona)
threshold, transcribed = self.mic.passiveListen(self.persona)
Expand Down
26 changes: 24 additions & 2 deletions client/mic.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ def __init__(self, profile, speaker, passive_stt_engine,
mode
"""
self.profile = profile
self.robot_name = u'叮当'
if 'robot_name_cn' in profile:
self.robot_name = profile['robot_name_cn']
self._logger = logging.getLogger(__name__)
self.speaker = speaker
self.wxbot = None
Expand All @@ -42,6 +45,7 @@ def __init__(self, profile, speaker, passive_stt_engine,
"can usually be safely ignored.")
self._audio = pyaudio.PyAudio()
self._logger.info("Initialization of PyAudio completed.")
self.stop_passive = False

def __del__(self):
self._audio.terminate()
Expand Down Expand Up @@ -101,6 +105,12 @@ def fetchThreshold(self):

return THRESHOLD

def stopPassiveListen(self):
"""
Stop passive listening
"""
self.stop_passive = True

def passiveListen(self, PERSONA):
"""
Listens for PERSONA in everyday sound. Times out after LISTEN_TIME, so
Expand Down Expand Up @@ -130,10 +140,15 @@ def passiveListen(self, PERSONA):
# stores the lastN score values
lastN = [i for i in range(30)]

didDetect = False

# calculate the long run average, and thereby the proper threshold
for i in range(0, RATE / CHUNK * THRESHOLD_TIME):

try:
if self.stop_passive:
break

data = stream.read(CHUNK)
frames.append(data)

Expand All @@ -158,6 +173,9 @@ def passiveListen(self, PERSONA):
for i in range(0, RATE / CHUNK * LISTEN_TIME):

try:
if self.stop_passive:
break

data = stream.read(CHUNK)
frames.append(data)
score = self.getScore(data)
Expand All @@ -173,6 +191,7 @@ def passiveListen(self, PERSONA):
if not didDetect:
print "No disturbance detected"
try:
self.stop_passive = False
stream.stop_stream()
stream.close()
except Exception, e:
Expand All @@ -188,6 +207,8 @@ def passiveListen(self, PERSONA):
for i in range(0, RATE / CHUNK * DELAY_MULTIPLIER):

try:
if self.stop_passive:
break
data = stream.read(CHUNK)
frames.append(data)
except Exception, e:
Expand All @@ -196,6 +217,7 @@ def passiveListen(self, PERSONA):

# save the audio data
try:
self.stop_passive = False
stream.stop_stream()
stream.close()
except Exception, e:
Expand Down Expand Up @@ -300,12 +322,12 @@ def activeListenToAllOptions(self, THRESHOLD=None, LISTEN=True,
return self.active_stt_engine.transcribe(f)

def say(self, phrase,
wxbot=None,
OPTIONS=" -vdefault+m3 -p 40 -s 160 --stdout > say.wav"):
# alter phrase before speaking
phrase = alteration.clean(phrase)
if self.wxbot is not None:
wechatUser(self.profile, self.wxbot, phrase, "")
wechatUser(self.profile, self.wxbot, "%s: %s" %
(self.robot_name, phrase), "")
self.speaker.say(phrase)

def play(self, src):
Expand Down
2 changes: 1 addition & 1 deletion client/notifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def styleEmail(e):
return ""
elif Email.isControlEmail(e, self.profile):
self.brain.query([subject.replace('[control]', '')
.strip()], None)
.strip()], None, True)
return ""
sender = Email.getSender(e)
return "您有来自 %s 的新邮件 %s" % (sender, subject)
Expand Down
83 changes: 45 additions & 38 deletions client/wxbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def __init__(self):
self.sync_key_str = ''
self.sync_key = []
self.sync_host = ''

self.is_login = False

self.batch_count = 50 #一次拉取50个联系人的信息
self.full_user_name_list = [] #直接获取不到通讯录时,获取的username列表
Expand Down Expand Up @@ -768,49 +768,55 @@ def schedule(self):
"""
pass

def check_msg(self):
[retcode, selector] = self.sync_check()
# print '[DEBUG] sync_check:', retcode, selector
if retcode == '1100': # 从微信客户端上登出
return False
elif retcode == '1101': # 从其它设备上登了网页微信
return False
elif retcode == '0':
if selector == '2': # 有新消息
r = self.sync()
if r is not None:
self.handle_msg(r)
elif selector == '3': # 未知
r = self.sync()
if r is not None:
self.handle_msg(r)
elif selector == '4': # 通讯录更新
r = self.sync()
if r is not None:
self.get_contact()
elif selector == '6': # 可能是红包
r = self.sync()
if r is not None:
self.handle_msg(r)
elif selector == '7': # 在手机上操作了微信
r = self.sync()
if r is not None:
self.handle_msg(r)
elif selector == '0': # 无事件
pass
else:
print '[DEBUG] sync_check:', retcode, selector
r = self.sync()
if r is not None:
self.handle_msg(r)
else:
print '[DEBUG] sync_check:', retcode, selector
time.sleep(10)
self.schedule()
return True

def proc_msg(self):
self.test_sync_check()
while True:
check_time = time.time()
try:
[retcode, selector] = self.sync_check()
# print '[DEBUG] sync_check:', retcode, selector
if retcode == '1100': # 从微信客户端上登出
res = self.check_msg()
if not res:
break
elif retcode == '1101': # 从其它设备上登了网页微信
break
elif retcode == '0':
if selector == '2': # 有新消息
r = self.sync()
if r is not None:
self.handle_msg(r)
elif selector == '3': # 未知
r = self.sync()
if r is not None:
self.handle_msg(r)
elif selector == '4': # 通讯录更新
r = self.sync()
if r is not None:
self.get_contact()
elif selector == '6': # 可能是红包
r = self.sync()
if r is not None:
self.handle_msg(r)
elif selector == '7': # 在手机上操作了微信
r = self.sync()
if r is not None:
self.handle_msg(r)
elif selector == '0': # 无事件
pass
else:
print '[DEBUG] sync_check:', retcode, selector
r = self.sync()
if r is not None:
self.handle_msg(r)
else:
print '[DEBUG] sync_check:', retcode, selector
time.sleep(10)
self.schedule()
except:
print '[ERROR] Except in proc_msg'
print format_exc()
Expand Down Expand Up @@ -1176,6 +1182,7 @@ def run(self, Mic=None):

if self.login():
print '[INFO] Web WeChat login succeed .'
self.is_login = True
if Mic is not None:
Mic.wxbot = self
else:
Expand Down
21 changes: 17 additions & 4 deletions dingdang.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
import sys
import logging

import time
import yaml
import argparse
import threading
Expand All @@ -26,6 +26,7 @@
parser.add_argument('--diagnose', action='store_true',
help='Run diagnose and exit')
parser.add_argument('--debug', action='store_true', help='Show debug messages')
parser.add_argument('--info', action='store_true', help='Show info messages')
args = parser.parse_args()

if args.local:
Expand All @@ -38,16 +39,26 @@ class WechatBot(WXBot):
def __init__(self, brain):
WXBot.__init__(self)
self.brain = brain
self.music_mode = None
self.last = time.time()

def handle_msg_all(self, msg):
# ignore the msg when handling plugins
if self.brain.handling:
return
if msg['msg_type_id'] == 1 and \
msg['to_user_id'] == self.my_account['UserName']: # reply to self

if msg['content']['type'] == 0:
msg_data = msg['content']['data']
self.brain.query([msg_data], self)
if self.music_mode is not None:
# avoid repeating command
now = time.time()
if (now - self.last) > 0.5:
# stop passive listening
self.brain.mic.stopPassiveListen()
self.last = now
self.music_mode.delegateInput(msg_data, True)
return
self.brain.query([msg_data], self, True)
elif msg['content']['type'] == 4: # echo voice
player = SimpleMp3Player()
player.play_mp3('./temp/voice_%s.mp3' % msg['msg_id'])
Expand Down Expand Up @@ -153,6 +164,8 @@ def run(self):

if args.debug:
logger.setLevel(logging.DEBUG)
elif args.info:
logger.setLevel(logging.INFO)

if not args.no_network_check and not diagnose.check_network_connection():
logger.warning("Network not connected. This may prevent Dingdang " +
Expand Down

0 comments on commit fc2154a

Please sign in to comment.