Issues (208)

server/sarah.js (2 issues)

Labels
1
  var request    = require('request');
2
  var express    = require('express');
3
  var FeedParser = require('feedparser');
4
  var extend     = require('extend');
5
  var ent        = require('ent');
6
  
7
  var USERAGENT  = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.75 Safari/537.1";
8
  
9
// ------------------------------------------
10
//  CONSTRUCTOR
11
// ------------------------------------------
12
13
var init = function(){
14
  info('Starting SARAH ...');
15
  global.SARAH = SARAH;
16
  
17
  SARAH.ConfigManager  = require('./config.js').init();
18
  SARAH.PluginManager  = require('./plugin.js').init();
19
  SARAH.LangManager    = require('./lang.js').init();
20
  SARAH.PrivacyManager = require('./privacy.js').init();
21
  SARAH.PortalManager  = require('./portal.js').init();
22
  SARAH.ScriptManager  = require('./script.js').init();
23
  SARAH.RuleEngine     = require('./rules.js').init();
24
  SARAH.CRONManager    = require('./cron.js').init();
25
  SARAH.ProfileManager = require('./profile.js').init();
26
  SARAH.Marketplace    = require('./marketplace.js').init();
27
  
28
  /*
29
  SARAH.PhantomManager = require('./phantom.js').init();
30
  */
31
  
32
  SARAH.run      = SARAH.ScriptManager.run;
33
  SARAH.call     = SARAH.ScriptManager.call;
34
  SARAH.last     = SARAH.ScriptManager.last;
35
  SARAH.find     = SARAH.PluginManager.find;
36
  SARAH.exists   = SARAH.PluginManager.exists;
37
  SARAH.trigger  = SARAH.PluginManager.trigger;
38
  SARAH.listen   = SARAH.PluginManager.listen;
39
  
40
  return SARAH;
41
}
42
43
// ------------------------------------------
44
//  RSS
45
// ------------------------------------------
46
47
var RSSFeedCache = {};
48
var getRSSFeed = function(url, cache){
49
  
50
  // Use cache
51
  if (!cache && RSSFeedCache[url]){ return RSSFeedCache[url]; }
52
  
53
  var feed = { items : [] };
54
  request(url)
55
  .pipe(new FeedParser())
56
  .on('meta', function (meta) { feed.meta = meta; })
57
  .on('readable', function() {
58
    var stream = this, item;
59
    while (item = stream.read()) { 
60
      item.description = ent.decode(item.description);
61
      feed.items.push(item);
62
    }
63
    RSSFeedCache[url] = feed; // Cache
64
  });
65
}
66
67
// ------------------------------------------
68
//  ASKME
69
// ------------------------------------------
70
71
var ASKME = false;
72
var stack = [];
73
74
var end = function(){ 
75
  ASKME = false;  next(); 
76
}
77
78
var next = function(){
79
  if (stack.length <= 0){ 
80
    return SARAH.context('default');
81
  }
82
  var args = stack.shift();
83
  askme(args[0], args[1], args[2], args[3])
84
}
85
86
var askme = function(tts, grammar, timeout, callback, wrong){
87
  if (!grammar) { return; }
88
  if (!callback){ return; }
89
  if (ASKME)  { return stack.push(arguments); }
90
  
91
  // Build request
92
  info('AskMe', ASKME);
93
  ASKME = { 'sentences':[], 'tags':[] }
94
  if (tts){ 
95
    ASKME.tts = tts;
96
    ASKME.sync = true;
97
    ASKME.wrong = wrong;
98
  }
99
  for (var g in grammar){
100
    ASKME.sentences.push(g);
101
    ASKME.tags.push(grammar[g]);
102
  }
103
  
104
  // Send request
105
  remote(ASKME);
106
  
107
  // Backup
108
  ASKME.rule     = grammar
109
  ASKME.callback = callback;
110
  ASKME.token    = setTimeout(function(){
111
    ASKME = false;
112
    if (timeout <= 0){
113
      callback(false, end);
114
    } else {
115
      SARAH.askme(tts, grammar, 0, callback);
116
    }
117
  }, timeout || 16000);
118
}
119
120
var answerme = function(req, res, next){ res.end();
121
  if (!ASKME){ return; }
122
  if (ASKME.token){ clearTimeout(ASKME.token); }
123
  ASKME.callback(req.param('dictation') || req.param('tag'), end);
124
}
125
126
// ------------------------------------------
127
//  ROUTER
128
// ------------------------------------------
129
130
var Router = express.Router();
131
132
Router.all('/sarah/:name', function(req, res, next) {
133
134
  var name = req.params.name;
135
  var options = {};
136
  extend(true, options, req.query);
137
  extend(true, options, req.body);
138
  
139
  // 1. Log action into rule engine
140
  var entry = SARAH.RuleEngine.log(name, options);
141
  // info('Rule Engine Log:', entry);
142
  
143
  // 3. Send back TTS
144
  var callback = function(data){
145
    
146
    // Redirect to portlet (no rules, asknect, ...)
147
    if (req.query.ajax){
148
      res.redirect('/plugin/'+name);
149
      return;
150
    }
151
    
152
    //res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
153
    if (!res.headersSent){
154
      res.set({'Content-Type': 'text/html; charset=utf-8'});
155
    }
156
    
157
    // Speak
158
    if (data && data.tts){
159
      var tts = SARAH.ScriptManager.speak(data.tts);
160
      if (tts){ res.write(tts); }
161
    }
162
    
163
    res.status(200).end();
164
    
165
    // Ask next from data
166
    if (data && data.asknext){
167
      if (typeof data.asknext === 'string'){
168
        SARAH.asknext(data.asknext);
169
      } else {
170
        SARAH.asknext(data.asknext.rule, data.asknext);
171
      }
172
    }
173
    else if (options.asknext){
174
      SARAH.asknext(options.asknext);
175
    }
176
    
177
    // 4. Guess next action from RuleEngine
178
    var next = SARAH.RuleEngine.next(entry);
179
    //info('Rule Engine Guess:', next);
180
  }
181
  
182
  // 2. Run plugin's script
183
  SARAH.run(name, options, callback, true);
184
});
185
186
Router.all('/standby', function(req, res, next) { 
187
  var motion = req.query.motion == "True" ? true : false;
188
  SARAH.ScriptManager.standBy(motion, req.query.client);
189
  res.end(); 
190
});
191
192
Router.all('/askme', answerme);
193
194
195
// ------------------------------------------
196
//  REMOTE
197
// ------------------------------------------
198
199
var _callback = function (err, response, body){
200
  if (err || response.statusCode != 200) {
201
    warn("HTTP Error: ", err, response, body);
202
    return;
203
  }
204
};
205
206
var remote = function(query, callback){
207
  var url = Config.http.remote;
0 ignored issues
show
The variable Config seems to be never declared. If this is a global, consider adding a /** global: Config */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
208
  var querystring = require('querystring');
209
  url += '?' + querystring.stringify(query);
210
211
  info('Remote: ', url);
212
  var request = require('request');
213
  request({ 'url' : url }, callback || _callback);
214
};
215
216
var speak = function(tts, callback){
217
  
218
  tts = SARAH.ScriptManager.speak(tts, callback);
219
  if (!tts){ return; }
220
  
221
  // Hook for TTS
222
  var qs = { 
223
    'tts'  : tts,
224
    'sync' : callback ? true : false
225
  };
226
  return remote(qs, callback);
227
}
228
229
var answer = function(tts, callback){
230
  var answers = Config.bot.answers.split('|');
0 ignored issues
show
The variable Config seems to be never declared. If this is a global, consider adding a /** global: Config */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
231
  var answer = answers[ Math.floor(Math.random() * answers.length)];
232
  return speak(answer, callback);
233
}
234
235
var shutup = function(once){
236
  var qs = { 'notts' : 'true' }
237
  if (once){ qs.once = true; }
238
  return remote(qs);
239
}
240
241
var play = function(path, callback){
242
  // Hook for TTS
243
  var qs = { 
244
    'play'  : path,
245
    'sync' : callback ? true : false
246
  };
247
  return remote(qs, callback);
248
}
249
250
var stop = function(path){
251
  return remote({ 'stop' : path });
252
}
253
254
var runApp = function(path, params){
255
  var qs = { 'run' : path };
256
  if (params){ qs.runp = params; }
257
  return remote(qs);
258
}
259
260
var activate = function(process){
261
  return remote({ 'activate' : process });
262
}
263
264
var keyText = function(text){
265
  return remote({ 'keyText' : text });
266
}
267
268
var keyUp = function(key, mod){
269
  var qs = { 'keyUp' : key };
270
  if (mod){ qs.keyMod = mod; }
271
  return remote(qs);
272
}
273
274
var keyDown = function(key, mod){
275
  var qs = { 'keyDown' : key };
276
  if (mod){ qs.keyMod = mod; }
277
  return remote(qs);
278
}
279
280
var keyPress = function(key, mod){
281
  var qs = { 'keyPress' : key };
282
  if (mod){ qs.keyMod = mod; }
283
  return remote(qs);
284
}
285
286
var face = function(pause){
287
  return remote({ 'face' : pause });
288
}
289
290
var gesture = function(pause){
291
  return remote({ 'gesture' : pause });
292
}
293
294
var listen = function(pause){
295
  return remote({ 'listen' : pause });
296
}
297
298
var picture = function(device, path, type){
299
  var qs = { 'picture' : type || 'true'  };
300
301
  if (path){ qs.picture = path; }
302
  if (device){ qs.device = device; }
303
  return remote(qs);
304
}
305
306
var recognize = function(path){
307
  return remote({ 'recognize' : path });
308
}
309
310
var context = function(rules){
311
  return remote({ 'context' : rules });
312
}
313
314
var grammar = function(rule, xml){
315
  return remote({ 'grammar' : rule , 'xml' : xml});
316
}
317
318
var asknext = function(rule, options){
319
  var qs = {'asknext' : rule };
320
  if (options){  extend(true, qs, options); }
321
  return remote(qs);
322
}
323
324
// ------------------------------------------
325
//  PUBLIC
326
// ------------------------------------------
327
328
var SARAH = {
329
  'init'      : init,
330
  'remote'    : remote,
331
              
332
  'speak'     : speak,
333
  'answer'    : answer,
334
  'shutup'    : shutup,
335
  'play'      : play,
336
  'stop'      : stop,
337
              
338
  'runApp'    : runApp,
339
  'activate'  : activate,
340
  'keyText'   : keyText,
341
  'keyUp'     : keyUp,
342
  'keyDown'   : keyDown,
343
  'keyPress'  : keyPress,
344
              
345
  'face'      : face,
346
  'gesture'   : gesture,
347
  'listen'    : listen,
348
  'picture'   : picture,
349
  'recognize' : recognize,
350
  
351
  'context'   : context,
352
  'grammar'   : grammar,
353
  'askme'     : askme,
354
  'asknext'   : asknext,
355
  
356
  'getRSSFeed' : getRSSFeed,
357
  'Router'     : Router,
358
  'USERAGENT'  : USERAGENT
359
}
360
361
// Exports SARAH singleton
362
exports.init = init;