Skip to content

Commit 4863f27

Browse files
authored
fix: stop message.context source/destination (#706)
* refactor: reduce bus spam * fix: stop message routing
1 parent d5dbd30 commit 4863f27

File tree

2 files changed

+49
-21
lines changed

2 files changed

+49
-21
lines changed

ovos_core/intent_services/stop_service.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from langcodes import closest_match
88
from ovos_bus_client.client import MessageBusClient
99
from ovos_bus_client.message import Message
10-
from ovos_bus_client.session import SessionManager
10+
from ovos_bus_client.session import SessionManager, UtteranceState
1111

1212
from ovos_config.config import Configuration
1313
from ovos_plugin_manager.templates.pipeline import ConfidenceMatcherPipeline, IntentHandlerMatch
@@ -29,12 +29,17 @@ def __init__(self, bus: Optional[Union[MessageBusClient, FakeBus]] = None,
2929
self._voc_cache = {}
3030
self.load_resource_files()
3131
self.bus.on("stop:global", self.handle_global_stop)
32+
self.bus.on("stop:skill", self.handle_skill_stop)
3233

3334
def handle_global_stop(self, message: Message):
3435
self.bus.emit(message.forward("mycroft.stop"))
3536
# TODO - this needs a confirmation dialog if nothing was stopped
3637
self.bus.emit(message.forward("ovos.utterance.handled"))
3738

39+
def handle_skill_stop(self, message: Message):
40+
skill_id = message.data["skill_id"]
41+
self.bus.emit(message.reply(f"{skill_id}.stop"))
42+
3843
def load_resource_files(self):
3944
base = f"{dirname(__file__)}/locale"
4045
for lang in os.listdir(base):
@@ -148,11 +153,21 @@ def handle_stop_confirmation(self, message: Message):
148153
error_msg = message.data['error']
149154
LOG.error(f"{skill_id}: {error_msg}")
150155
elif message.data.get('result', False):
151-
# force-kill any ongoing get_response/converse/TTS - see @killable_event decorator
152-
self.bus.emit(message.forward("mycroft.skills.abort_question", {"skill_id": skill_id}))
153-
self.bus.emit(message.forward("ovos.skills.converse.force_timeout", {"skill_id": skill_id}))
154-
# TODO - track if speech is coming from this skill! not currently tracked
155-
self.bus.emit(message.reply("mycroft.audio.speech.stop", {"skill_id": skill_id}))
156+
sess = SessionManager.get(message)
157+
utt_state = sess.utterance_states.get(skill_id, UtteranceState.INTENT)
158+
if utt_state == UtteranceState.RESPONSE:
159+
LOG.debug("Forcing get_response timeout")
160+
# force-kill any ongoing get_response - see @killable_event decorator (ovos-workshop)
161+
self.bus.emit(message.reply("mycroft.skills.abort_question", {"skill_id": skill_id}))
162+
if sess.is_active(skill_id):
163+
LOG.debug("Forcing converse timeout")
164+
# force-kill any ongoing converse - see @killable_event decorator (ovos-workshop)
165+
self.bus.emit(message.reply("ovos.skills.converse.force_timeout", {"skill_id": skill_id}))
166+
167+
# TODO - track if speech is coming from this skill! not currently tracked (ovos-audio)
168+
if sess.is_speaking:
169+
# force-kill any ongoing TTS
170+
self.bus.emit(message.forward("mycroft.audio.speech.stop", {"skill_id": skill_id}))
156171

157172
def match_high(self, utterances: List[str], lang: str, message: Message) -> Optional[IntentHandlerMatch]:
158173
"""
@@ -211,8 +226,8 @@ def match_high(self, utterances: List[str], lang: str, message: Message) -> Opti
211226
sess.disable_response_mode(skill_id)
212227
self.bus.once(f"{skill_id}.stop.response", self.handle_stop_confirmation)
213228
return IntentHandlerMatch(
214-
match_type=f"{skill_id}.stop",
215-
match_data={"conf": conf},
229+
match_type="stop:skill",
230+
match_data={"conf": conf, "skill_id": skill_id},
216231
updated_session=sess,
217232
utterance=utterance,
218233
skill_id="stop.openvoiceos"
@@ -299,8 +314,8 @@ def match_low(self, utterances: List[str], lang: str, message: Message) -> Optio
299314
sess.disable_response_mode(skill_id)
300315
self.bus.once(f"{skill_id}.stop.response", self.handle_stop_confirmation)
301316
return IntentHandlerMatch(
302-
match_type=f"{skill_id}.stop",
303-
match_data={"conf": conf},
317+
match_type="stop:skill",
318+
match_data={"conf": conf, "skill_id": skill_id},
304319
updated_session=sess,
305320
utterance=utterance,
306321
skill_id="stop.openvoiceos"

test/end2end/test_stop.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def make_it_count():
166166
nonlocal session
167167
message = Message("recognizer_loop:utterance",
168168
{"utterances": ["count to infinity"], "lang": "en-US"},
169-
{"session": session.serialize()})
169+
{"session": session.serialize(), "source": "A", "destination": "B"})
170170
session.activate_skill(self.skill_id) # ensure in active skill list
171171
self.minicroft.bus.emit(message)
172172

@@ -177,33 +177,41 @@ def make_it_count():
177177

178178
message = Message("recognizer_loop:utterance",
179179
{"utterances": ["stop"], "lang": "en-US"},
180-
{"session": session.serialize()}) # skill in active list now
180+
{"session": session.serialize(), "source": "A", "destination": "B"})
181181

182182
stop_skill_active = [
183183
message,
184-
Message("ovos-skill-count.openvoiceos.stop.ping",
184+
Message(f"{self.skill_id}.stop.ping",
185185
{"skill_id":self.skill_id}),
186186
Message("skill.stop.pong",
187187
{"skill_id": self.skill_id, "can_handle": True},
188188
{"skill_id": self.skill_id}),
189189

190190
Message("stop.openvoiceos.activate",
191191
context={"skill_id": "stop.openvoiceos"}),
192+
Message("stop:skill",
193+
context={"skill_id": "stop.openvoiceos"}),
192194
Message(f"{self.skill_id}.stop",
193195
context={"skill_id": "stop.openvoiceos"}),
194196
Message(f"{self.skill_id}.stop.response",
195197
{"skill_id": self.skill_id, "result": True},
196198
{"skill_id": self.skill_id}),
197199

198-
# skill callback to stop everything
199-
# TODO - clean up! most arent needed/can check session if needed (ovos-workshop)
200-
Message("mycroft.skills.abort_question", {"skill_id": self.skill_id},
201-
{"skill_id": self.skill_id}),
202-
Message("ovos.skills.converse.force_timeout", {"skill_id": self.skill_id},
203-
{"skill_id": self.skill_id}),
204-
Message("mycroft.audio.speech.stop", {"skill_id": self.skill_id},
200+
# stop pipeline callback to stop everything
201+
202+
# if skill is in middle of get_response
203+
#Message("mycroft.skills.abort_question", {"skill_id": self.skill_id},
204+
# {"skill_id": self.skill_id}),
205+
206+
# if skill is in active_list
207+
Message("ovos.skills.converse.force_timeout",
208+
{"skill_id": self.skill_id},
205209
{"skill_id": self.skill_id}),
206210

211+
# if skill is executing TTS
212+
#Message("mycroft.audio.speech.stop", {"skill_id": self.skill_id},
213+
# {"skill_id": self.skill_id}),
214+
207215
# the intent running in the daemon thread exits cleanly
208216
Message("mycroft.skill.handler.complete",
209217
{"name": "CountSkill.handle_how_are_you_intent"},
@@ -214,10 +222,15 @@ def make_it_count():
214222
]
215223
test = End2EndTest(
216224
minicroft=self.minicroft,
217-
# inject_active=[self.skill_id], # ensure this skill is in active skills list for the test
218225
skill_ids=[],
219226
eof_msgs=[],
220227
flip_points=["recognizer_loop:utterance"],
228+
# messages in 'keep_original_src' would not be sent to hivemind clients
229+
# i.e. they are directed towards ovos-core
230+
keep_original_src=[f"{self.skill_id}.stop.ping",
231+
f"{self.skill_id}.stop",
232+
"mycroft.skills.abort_question",
233+
"ovos.skills.converse.force_timeout"],
221234
ignore_messages=self.ignore_messages,
222235
source_message=message,
223236
expected_messages=stop_skill_active

0 commit comments

Comments
 (0)