22import time
33
44from ovos_bus_client .message import Message
5+ from ovos_bus_client .session import SessionManager , Session
56from ovos_config import Configuration
67from ovos_utils import classproperty
78from ovos_utils .process_utils import RuntimeRequirements
89from ovos_workshop .decorators import intent_handler , adds_context , removes_context
9- from ovos_workshop .skills import OVOSSkill
10+ from ovos_workshop .skills . converse import ConversationalSkill
1011
1112
12- class DictationSkill (OVOSSkill ):
13+ class DictationSkill (ConversationalSkill ):
1314 """
1415 - start dictation
1516 - enable continuous conversation mode
@@ -37,9 +38,7 @@ def runtime_requirements(self):
3738 )
3839
3940 def initialize (self ):
40- self .file_name = None
41- self .dictating = False
42- self .dictation_stack = []
41+ self .dictation_sessions = {}
4342
4443 @property
4544 def default_listen_mode (self ):
@@ -54,54 +53,88 @@ def default_listen_mode(self):
5453 @adds_context ("DictationKeyword" , "dictation" )
5554 def start_dictation (self , message = None ):
5655 message = message or Message ("" )
57- self .dictation_stack = []
58- self .dictating = True
59- self .file_name = message .data .get ("name" , str (time .time ()))
56+ sess = SessionManager .get (message )
57+ self .dictation_sessions [sess .session_id ] = dict (
58+ file_name = message .data .get ("name" , str (time .time ())),
59+ dictating = True ,
60+ dictation_stack = []
61+ )
6062 self .bus .emit (message .forward ("recognizer_loop:state.set" ,
6163 {"mode" : "continuous" }))
6264
6365 @removes_context ("DictationKeyword" )
6466 def stop_dictation (self , message = None ):
6567 message = message or Message ("" )
66- self . dictating = False
68+ sess = SessionManager . get ( message )
6769 self .bus .emit (message .forward ("recognizer_loop:state.set" ,
6870 {"mode" : self .default_listen_mode }))
71+
6972 path = f"{ os .path .expanduser ('~' )} /Documents/dictations"
7073 os .makedirs (path , exist_ok = True )
71- name = self .file_name or time .time ()
74+ name = self .dictation_sessions [ sess . session_id ][ " file_name" ] or time .time ()
7275 with open (f"{ path } /{ name } .txt" , "w" ) as f :
73- f .write ("\n " .join (self .dictation_stack ))
76+ f .write ("\n " .join (self .dictation_sessions [ sess . session_id ][ " dictation_stack" ] ))
7477 self .gui .show_text (f"saved to { path } /{ name } .txt" )
7578
79+ self .dictation_sessions [sess .session_id ]["dictating" ] = False
80+
7681 @intent_handler ("start_dictation.intent" )
7782 def handle_start_dictation_intent (self , message ):
7883 if not self .dictating :
7984 self .speak_dialog ("start" , wait = True )
8085 else :
8186 self .speak_dialog ("already_dictating" , wait = True )
82- self .start_dictation () # enable continuous listening, no wake word needed
87+ self .start_dictation (message ) # enable continuous listening, no wake word needed
8388
8489 @intent_handler ("stop_dictation.intent" )
8590 def handle_stop_dictation_intent (self , message ):
8691 if self .dictating :
8792 self .speak_dialog ("stop" )
8893 else :
8994 self .speak_dialog ("not_dictating" )
90- self .stop_dictation ()
95+ self .stop_dictation (message )
9196
92- def stop (self ):
93- if self .dictating :
97+ def stop_session (self , session : Session ):
98+ if session .session_id in self .dictation_sessions and \
99+ self .dictation_sessions [session .session_id ]["dictating" ]:
100+ self .dictation_sessions [session .session_id ]["dictating" ] = False
94101 self .stop_dictation ()
95102 return True
103+ return False
104+
105+ def stop (self ):
106+ sess = SessionManager .get ()
107+ if sess .session_id in self .dictation_sessions and \
108+ self .dictation_sessions [sess .session_id ]["dictating" ]:
109+ self .stop_session (sess )
110+ return True
111+ return False
112+
113+ def can_answer (self , message : Message ) -> bool :
114+ """
115+ Determines if the skill can handle the given utterances in the specified language in the converse method.
116+
117+ Override this method to implement custom logic for assessing whether the skill is capable of answering a query.
118+
119+ Returns:
120+ True if the skill can handle the query during converse; otherwise, False.
121+ """
122+ sess = SessionManager .get (message )
123+ if sess .session_id in self .dictation_sessions and \
124+ self .dictation_sessions [sess .session_id ]["dictating" ]:
125+ return True
126+ return False
96127
97128 def converse (self , message ):
98129 utterance = message .data ["utterances" ][0 ]
99- if self .dictating :
130+ sess = SessionManager .get (message )
131+ if sess .session_id in self .dictation_sessions and \
132+ self .dictation_sessions [sess .session_id ]["dictating" ]:
100133 if self .voc_match (utterance , "StopKeyword" ):
101134 self .handle_stop_dictation_intent (message )
102135 else :
103136 self .gui .show_text (utterance )
104- self .dictation_stack .append (utterance )
137+ self .dictation_sessions [ sess . session_id ][ " dictation_stack" ] .append (utterance )
105138 return True
106139 return False
107140
@@ -129,4 +162,4 @@ def spk(utt, *args, **kwargs):
129162 # dictation stopped
130163 s .converse (Message ("" , {"utterances" : ["test" ]}))
131164
132- assert s .dictation_stack == ['test' , 'test' , 'test' ]
165+ assert s .dictation_stack == ['test' , 'test' , 'test' ]
0 commit comments