-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTrainDialog.py
More file actions
executable file
·407 lines (344 loc) · 15.3 KB
/
Copy pathTrainDialog.py
File metadata and controls
executable file
·407 lines (344 loc) · 15.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
__version__ = "$Revision: 512 $, $Date: 2013-09-04 14:45:28 +0200 (wo, 04 sep 2013) $, $Author: quintijn $"
# (unimacro - natlink macro wrapper/extensions)
# (c) copyright 2003 Quintijn Hoogenboom (quintijn@users.sourceforge.net)
# Ben Staniford (ben_staniford@users.sourceforge.net)
# Bart Jan van Os (bjvo@users.sourceforge.net)
#
# This file is part of a SourceForge project called "unimacro" see
# http://unimacro.SourceForge.net).
#
# "unimacro" is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, see:
# http://www.gnu.org/licenses/gpl.txt
#
# "unimacro" is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; See the GNU General Public License details.
#
# "unimacro" makes use of another SourceForge project "natlink",
# which has the following copyright notice:
#
# Python Macro Language for Dragon NaturallySpeaking
# (c) Copyright 1999 by Joel Gould
# Portions (c) Copyright 1999 by Dragon Systems, Inc.
#
# Author: Bart Jan van Os, Version: 0.1
"""This file implements a crude Training dialog to Train phrases
"""
import string,sys,cPickle
import win32ui,win32con,win32api,commctrl
from pywin.mfc import dialog
from pywin.framework import dlgappcore
import natlink
from natlinkutils import *
from natlinkutilsbj import SetMic
# The training dialog gives a list at the bottum with each phrase to train. After training
# is started, each phrase to train is displayed at the top, any training results
# are displayed in the control in between. If the recognized results are different from
# the phrase to train, the phrase can be trained again until
MaxRepeat=3
# is reached. If the result is correct, the next phrase will be selected.
# You can stop training at any time by 'stop training'. This stops the training process, but leaves results
# for later batch processing. Switching to another window and saying something has the same result.
# Cancel will quit the dialog without batchprocessing. NOTE: any 'results obj.correction'
# changes are processed immediately, before possible quitting.
# Choosing Done will start processing the results in the batch training mode, and leave the dialog.
# You can use ' skip phrase' or ' previous phrase' to go forth and back through the phrases to train,
# as wel as use the mouse/keyboard in the list at the bottom.
## Be careful with using this training process. Because it uses the batch training
## mode,(I presume) it also affects the acoustic models. One may question whether
## the words to be trained are a good representation of your use of the system,
## and you have to be sure that the words are in your vocabulary.
## In the end, general training is probably much better for changing the acoustic
## models. However, it has helped me to train a lot of
## often misrecognized commands without having to type them. I always do some
## general training afterwards. Possibly, training mode should be changed to
## only use the obj.correction method.
## This can be accomplished by setting the next constant to zero.
TrainInBatchMode=1
# Things to do:
# - add a control for selecting the training mode.define method
# - add a control for selecting the maximum repeat count.
class TrainDialogGrammar(GrammarBase):
gramSpec = """
<dgndictation> imported; #This must be the first rule
<TrainedWord> = {TrainedWord}; #This must be the second rule
<ChangePhrase> = previous phrase | skip phrase;
<Buttons> = (start [training]| (stop|cancel) [training | this] | done );
<TrainButtons> = click stop | click done | click cancel | ((stop |cancel) (training | this));
<normalState> exported = <Buttons>;
<trainingState> exported = <TrainButtons> | <ChangePhrase> |
<TrainedWord> | <dgndictation>;
"""
def initialize(self,dlg):
self.dlg = dlg
self.load(self.gramSpec,allResults=1)
self.thisWindow=dlg.GetSafeHwnd()
self.emptyList('TrainedWord')
def terminate(self):
self.dlg = None
self.unload()
def setMode(self):
if not self.dlg.AreTraining:
#self.activateSet(['normalState'],window=self.thisWindow,exclusive=0)
self.activateSet(['normalState'],exclusive=0)
else:
self.activateSet(['trainingState'],exclusive=1)
def gotBegin(self, moduleInfo):
winHandle = matchWindow( moduleInfo, 'pythonw', 'Train Phrases' )
if winHandle:
#if winHandle==self.thisWindow:
self.setMode()
else:
self.deactivateAll()
if self.dlg.AreTraining: self.dlg.onStop(0,0)
# This processes the results within the training mode
def gotResultsTraining(self,recogType,resObj):
if recogType == 'reject':
print 'rejected'
else:
results= convertResults(resObj.getResults(0))
rule=results.keys()[0]
#print results.keys()
if (rule<=2):
self.dlg.trainedPhrases.append((resObj,self.dlg.phrase))
results=string.join(resObj.getWords(0))
print results
#go next or repeat
lowResults=string.lower(results)
lowSpokenForm=string.split(lowResults,'\\')[-1]
lowPhrase=string.lower(self.dlg.phrase)
if (lowResults==lowPhrase) or (lowSpokenForm==lowPhrase):
self.dlg.nextWord()
else:
self.dlg.Repeat=self.dlg.Repeat+1
if self.dlg.Repeat>MaxRepeat:
self.dlg.nextWord()
# this callback is where we get the results object
def gotResultsObject(self,recogType,resObj):
if self.dlg.AreTraining:
self.gotResultsTraining(recogType,resObj)
def gotResults_Buttons(self,words,fullResults):
if 'done' in words:
key='{Alt+d}'
elif 'start' in words:
key='{Alt+s}'
elif 'cancel' in words:
key='{Alt+c}'
elif 'stop' in words:
key='{Alt+p}'
natut.playString(key)
def gotResults_TrainButtons(self,words,fullResults):
self.gotResults_Buttons(words,fullResults)
def gotResults_ChangePhrase(self,words,fullResults):
if 'previous' in words:
key='{Up}'
elif 'skip' in words:
key='{Down}'
natut.playString(key)
IDC_EDIT=1000
IDC_PHRASE=1010
IDC_START=1011
IDC_STOP=1012
class TrainDialog(dialog.Dialog):
# def __init__(self, title, hierList, bitmapID = win32ui.IDB_HIERFOLDERS, dlgID = win32ui.IDD_TREE, dll = None, childListBoxID = win32ui.IDC_LIST1):
def __init__ (self, title, phrases, MicStart):
#self.iconId = win32ui.IDR_MAINFRAME
dialog.Dialog.__init__ (self, self._maketemplate(title))
self.colHeadings=['Phrase']
self.items = phrases
self.MicStart=MicStart
self.AreTraining=0
self.CurItem=0
self.phrase=''
self.Repeat=0
self.Batch=0
def _maketemplate(self, title):
style = (win32con.WS_DLGFRAME |
win32con.WS_SYSMENU | win32con.WS_VISIBLE )
ls = (
win32con.WS_CHILD |
win32con.WS_VISIBLE |
commctrl.LVS_ALIGNLEFT |
commctrl.LVS_REPORT
)
bs = (
win32con.WS_CHILD |
win32con.WS_VISIBLE
)
child = win32con.WS_CHILD | win32con.WS_VISIBLE
return [ [title, (0, 0, 200, 200), style, None, (8, "MS Sans Serif")],
["SysListView32", None, win32ui.IDC_LIST1, (0, 0, 450, 200), ls],
[128, "&Start", IDC_START, (10, 0, 50, 14), bs | win32con.BS_DEFPUSHBUTTON],
[128, "Sto&p", IDC_STOP, (10, 0, 50, 14), bs ],
[128, "&Done", win32con.IDOK, (10, 0, 50, 14), bs],
[128, "&Cancel",win32con.IDCANCEL,(0, 0, 450, 200), bs],
[129,"",IDC_EDIT,(0,0,0,0),child|win32con.ES_MULTILINE|win32con.WS_BORDER|
win32con.ES_AUTOVSCROLL|win32con.WS_VSCROLL],
[130,"",IDC_PHRASE,(7,60,80,8),child|win32con.SS_LEFT],
]
def OnInitDialog (self):
rc = dialog.Dialog.OnInitDialog (self)
self.HookMessage (self.on_size, win32con.WM_SIZE)
self.HookNotify(self.OnListItemChange, commctrl.LVN_ITEMCHANGED)
self.HookCommand(self.onStart, IDC_START)
self.HookCommand(self.onStop, IDC_STOP)
self.itemsControl = self.GetDlgItem(win32ui.IDC_LIST1)
self.butOK = self.GetDlgItem(win32con.IDOK)
self.butCancel = self.GetDlgItem(win32con.IDCANCEL)
self.butStart = self.GetDlgItem(IDC_START)
self.butStop = self.GetDlgItem(IDC_STOP)
self.Output= self.GetDlgItem(IDC_EDIT)
self.Phrase= self.GetDlgItem(IDC_PHRASE)
self.SelItems=[]
self.FillList()
size = self.GetWindowRect()
self.LayoutControls(size[2]-size[0], size[3]-size[1])
self.butOK.EnableWindow(0) # wait for first selection
self.butStop.EnableWindow(0) # wait for first selection
self.SetFocus()
#Select First Item
self.itemsControl.SetItemState(0,commctrl.LVNI_SELECTED+commctrl.LVNI_FOCUSED,255)
self.oldStdout = sys.stdout
sys.stdout = self
self.message = ''
self.grammar = TrainDialogGrammar()
self.grammar.initialize(self)
self.trainedPhrases=[]
natlink.setChangeCallback(self.changeCallback)
SetMic(self.MicStart)
return rc
def changeCallback(self,what,param):
if what == 'user':
print 'User changed. New user is', param[0]
self.onStop(0,0)
elif what == 'mic':
print 'Microphone is ', param
if param=='off':
self.onStop(0,0)
def OnDestroy(self,msg):
sys.stdout = self.oldStdout
def write(self,text):
self.message = self.message + string.replace(text,'\n','\r\n')
self.SetDlgItemText(IDC_EDIT,self.message)
self.GetDlgItem(IDC_EDIT).SendMessage(win32con.EM_SETSEL,0x7FFF,0x7FFF)
self.GetDlgItem(IDC_EDIT).SendMessage(win32con.EM_SCROLLCARET,0,0)
def FillList(self):
size = self.GetWindowRect()
width = size[2] - size[0] - (10)
itemDetails = (commctrl.LVCFMT_LEFT, width, "Phrase", 0)
self.itemsControl.InsertColumn(0, itemDetails)
index = 0
for item in self.items:
index = self.itemsControl.InsertItem(index+1, str(item), 0)
def SetPhraseToTrain(self):
self.Repeat=1
if self.AreTraining:
self.phrase=self.items[self.CurItem]
self.SetDlgItemText(IDC_PHRASE,string.center(self.phrase,90))
self.grammar.setList('TrainedWord',[self.phrase])
else:
self.SetDlgItemText(IDC_PHRASE,'')
#self.setList('TrainedWord',[])
def OnListItemChange(self,std, extra):
(hwndFrom, idFrom, code), (itemNotify, sub, newState, oldState, change, point, lparam) = std, extra
oldSel = (oldState & commctrl.LVIS_SELECTED)<>0
newSel = (newState & commctrl.LVIS_SELECTED)<>0
if oldSel <> newSel:
try:
if newSel:
self.CurItem=itemNotify
self.SetPhraseToTrain()
except win32ui.error:
pass
def LayoutControls(self, w, h):
self.Phrase.MoveWindow((0,10,w,27))
self.Output.MoveWindow((0,30,w,97))
self.itemsControl.MoveWindow((0,100,w,h-30))
self.butStart.MoveWindow((10, h-24, 60, h-4))
self.butStop.MoveWindow((70, h-24, 120, h-4))
self.butCancel.MoveWindow((w-60, h-24, w-10, h-4))
self.butOK.MoveWindow((w-120, h-24, w-70, h-4))
def on_size (self, params):
lparam = params[3]
w = win32api.LOWORD(lparam)
h = win32api.HIWORD(lparam)
self.LayoutControls(w, h)
def onStart(self,nID,code):
print 'training started'
self.AreTraining=1
if TrainInBatchMode:
if not self.Batch:
natlink.startTraining('batchadapt')
self.Batch=1
print 'batch training started'
else:
print 'wat'
self.butOK.EnableWindow(1)
self.butStop.EnableWindow(1)
self.butStart.EnableWindow(0)
self.CurItem = self.CurItem - 1
self.itemsControl.SetFocus()
self.nextWord()
def onStop(self,nID,code):
print 'training stopped'
self.AreTraining=0
self.butStop.EnableWindow(0)
self.butStart.EnableWindow(1)
self.SetPhraseToTrain()
self.itemsControl.SetFocus()
def correctResults(self):
if len(self.trainedPhrases)>0:
print 'correcting results'
for (resObj,phrase) in self.trainedPhrases:
results=string.join(resObj.getWords(0))
if not resObj.correction(phrase):
if resObj.correction(string.lower(phrase)):
print 'correcting %s by lowercase %s.' % (results,phrase)
else:
print 'correcting %s by %s rejected.' % (results,phrase)
self.trainedPhrases=[]
def OnOK(self):
self.onStop(0,0)
self.correctResults()
if TrainInBatchMode and self.Batch:
print 'batch processing results'
try:
natlink.finishTraining()
print 'results processed'
except:
print 'results processing not possible'
self.Batch=0
else:
print 'Done'
#self._obj_.OnOK()
def EndDialog(self, rc):
self.trainedPhrases=[]
if TrainInBatchMode and self.Batch:
natlink.finishTraining(0)
print 'results not processed'
self._obj_.EndDialog(rc)
return
def nextWord(self):
if self.CurItem < len(self.items)-1:
self.itemsControl.SetFocus()
self.itemsControl.SetItemState(self.CurItem,0,commctrl.LVNI_SELECTED+commctrl.LVNI_FOCUSED)
self.CurItem = self.CurItem + 1
self.itemsControl.SetItemState(self.CurItem,0,commctrl.LVNI_SELECTED+commctrl.LVNI_FOCUSED)
self.itemsControl.SetItemState(self.CurItem,commctrl.LVNI_SELECTED+commctrl.LVNI_FOCUSED,255)
self.itemsControl.EnsureVisible(self.CurItem, 0)
else:
self.onStop(0,0)
def demodlg ():
Title='Train Phrases'
p=[('word 1'),('word 2'),('word 3')]
dlg=TrainDialog(Title, p, 1)
try:
natlink.natConnect(1)
except:
return
dlg.DoModal()
natlink.natDisconnect()
if __name__=='__main__':
#pass
demodlg()
#demomodeless()