Go to the documentation of this file.00001
00009 package com.rosalfred.core.ia;
00010
00011 import java.beans.XMLDecoder;
00012 import java.beans.XMLEncoder;
00013 import java.io.File;
00014 import java.io.FileInputStream;
00015 import java.io.FileNotFoundException;
00016 import java.io.FileOutputStream;
00017 import java.io.IOException;
00018
00019 import org.ros.dynamic_reconfigure.server.Server;
00020 import org.ros.dynamic_reconfigure.server.Server.ReconfigureListener;
00021 import org.ros.message.MessageListener;
00022 import org.ros.namespace.GraphName;
00023 import org.ros.node.AbstractNodeMain;
00024 import org.ros.node.ConnectedNode;
00025 import org.ros.node.Node;
00026 import org.ros.node.topic.Publisher;
00027 import org.ros.node.topic.Subscriber;
00028 import org.rosbuilding.common.media.CommandUtil;
00029
00030 import com.google.common.base.Joiner;
00031 import com.google.common.base.Strings;
00032 import com.rivescript.ClientManager;
00033 import com.rosalfred.core.ia.rivescript.BotReply;
00034 import com.rosalfred.core.ia.rivescript.RiveScript;
00035 import com.rosalfred.core.ia.rivescript.lang.Echo;
00036 import com.rosalfred.core.ia.rivescript.lang.Java;
00037
00038 import smarthome_comm_msgs.Command;
00039
00046 public class IaNode extends AbstractNodeMain implements MessageListener<Command>, ReconfigureListener<IaConfig> {
00047
00048 public static final String VAR_CONTEXT_WHERE = "context-where";
00049 private static final String SUB_CMD = "speech";
00050 private static final String PUB_STATE = "robotsay";
00051 private static final String PERSITE_FILE = "saveContext.xml";
00052
00053 public static String botname = "Alfred";
00054
00055 protected String prefix;
00056 protected String path;
00057
00058 protected ConnectedNode connectedNode;
00059 protected Server<IaConfig> reconfigServer;
00060 protected Publisher<Command> publisherSay;
00061 protected Subscriber<Command> subscriberListen;
00062
00063 protected RosRiveScript bot;
00064
00065 @Override
00066 public GraphName getDefaultNodeName() {
00067 return GraphName.of("local_ia");
00068 }
00069
00070 @Override
00071 public void onStart(ConnectedNode connectedNode) {
00072 super.onStart(connectedNode);
00073 this.connectedNode = connectedNode;
00074
00075 this.path = this.getPath();
00076
00077 this.loadParameters();
00078
00079 this.initTopics();
00080 this.initBot();
00081
00082 this.sayWelcome();
00083 }
00084
00085 protected String getPath() {
00086 return IaNode.class.getProtectionDomain().getCodeSource()
00087 .getLocation().getPath().replace("bin/", "") + "/res";
00088 }
00089
00090 private void initBot() {
00091 this.sayReload();
00092 this.bot = this.getRiveScript();
00093
00094
00095
00096 this.loadHandlers();
00097 this.reloadBot();
00098 }
00099
00100 protected RosRiveScript getRiveScript() {
00101 return new RosRiveScript(this, false);
00102 }
00103
00104 protected void loadHandlers() {
00105
00106 this.logI("\tLoad engine...");
00107 this.bot.setHandler(RiveScript.TYPE_PERL, new Echo(this.bot));
00108
00109
00110 this.bot.setHandler(RiveScript.TYPE_PYTHON, new Echo(this.bot));
00111 this.bot.setHandler(RiveScript.TYPE_JAVA, new Java(this.bot, this.path + "/src"));
00112 }
00113
00114 private void reloadBot() {
00115 if (this.bot != null) {
00116 this.logI(String.format("\tLoad rules... in %s", this.path));
00117 this.bot.loadDirectory(this.path);
00118
00119 this.bot.sortReplies();
00120 this.reloadBotState();
00121
00122 try {
00123 Thread.sleep(1);
00124 } catch (InterruptedException e) {
00125 e.printStackTrace();
00126 }
00127 }
00128 }
00129
00135 public void persistBotState() {
00136 if (this.bot != null) {
00137 XMLEncoder encoder = null;
00138 String path = this.getFolderPersist();
00139
00140 File file = new File(path + "/" + PERSITE_FILE);
00141 try {
00142 if (!file.exists() && !file.createNewFile()) {
00143 this.logE("File couldn't be created...");
00144 }
00145 encoder = new XMLEncoder(new FileOutputStream(file));
00146 encoder.writeObject(this.bot.getUservars());
00147 encoder.flush();
00148 } catch (FileNotFoundException e) {
00149 this.logE(e);
00150 } catch (IOException e) {
00151 this.logE(e);
00152 } finally {
00153 if (encoder != null)
00154 encoder.close();
00155 }
00156 }
00157 }
00158
00162 protected String getFolderPersist() {
00163 String path = System.getProperty("user.home") + "/.ros";
00164 if (System.getenv().containsKey("ROS_HOME")) {
00165 path = System.getenv("ROS_HOME");
00166 }
00167 return path;
00168 }
00169
00173 public void reloadBotState() {
00174 if (this.bot != null) {
00175 Object object = null;
00176 XMLDecoder decoder = null;
00177 ClientManager clientManager;
00178 String path = this.getFolderPersist();
00179
00180 File file = new File(path + "/" + PERSITE_FILE);
00181 if (file.exists()) {
00182 try {
00183 decoder = new XMLDecoder(new FileInputStream(file));
00184 object = decoder.readObject();
00185 clientManager = (ClientManager) object;
00186 this.bot.setUservars(clientManager);
00187 } catch (Exception e) {
00188 this.logI(e.getMessage());
00189 } finally {
00190 if (decoder != null)
00191 decoder.close();
00192 }
00193 }
00194 }
00195 }
00196
00197 protected void initTopics() {
00198 this.logI("Start Topics (publishers/subscribers)...");
00199
00200
00201 this.publisherSay = this.connectedNode.newPublisher(
00202 this.prefix + PUB_STATE, Command._TYPE);
00203
00204
00205 this.subscriberListen = this.connectedNode.newSubscriber(
00206 this.prefix + SUB_CMD, Command._TYPE);
00207 this.subscriberListen.addMessageListener(this);
00208 }
00209
00210 private Command makeSay() {
00211 Command command = this.connectedNode.getTopicMessageFactory().newFromType(Command._TYPE);
00212 command.getContext().setWho(IaNode.botname);
00213 command.setAction(CommandUtil.Action.SAY.getValue());
00214 return command;
00215 }
00216
00217 private void sayReload() {
00218 Command command = this.makeSay();
00219 command.setSubject("Chargement de ma base de donnée...");
00220 this.publisherSay.publish(command);
00221 }
00222
00223 private void sayGoodbye() {
00224 Command command = this.makeSay();
00225 command.setSubject("Arrêt du système...");
00226 this.publisherSay.publish(command);
00227 }
00228
00229 private void sayWelcome() {
00230 Command command = this.makeSay();
00231 command.setSubject("Système prêt!");
00232 this.publisherSay.publish(command);
00233 }
00234
00238 private void loadParameters() {
00239
00240 this.prefix = String.format("/%s/", this.connectedNode
00241 .getParameterTree().getString("~tf_prefix", ""));
00242
00243 if (this.prefix.equals("//"))
00244 this.prefix = "/";
00245
00246
00247 this.path = this.connectedNode.getParameterTree()
00248 .getString("~" + IaConfig.RES_PATH, this.path);
00249 this.connectedNode.getParameterTree().set("~" + IaConfig.RES_PATH, this.path);
00250
00251 this.logI(String.format("prefix : %s", this.prefix));
00252
00253
00254 this.reconfigServer = new Server<IaConfig>(
00255 this.connectedNode, new IaConfig(this.connectedNode), this);
00256 }
00257
00261 @Override
00262 public void onNewMessage(Command command) {
00263 String user = command.getContext().getWho();
00264 String where = command.getContext().getWhere();
00265
00266 if (this.bot != null) {
00267 String speech = command.getSubject();
00268 this.logI(String.format("from %s : %s", user, speech));
00269
00270 this.bot.setUservar(user, VAR_CONTEXT_WHERE, where);
00271
00272
00273 switch (speech) {
00274 case "/reload":
00275 this.initBot();
00276 break;
00277 case "/save":
00278 this.persistBotState();
00279 break;
00280 case "/load":
00281 this.reloadBotState();
00282 break;
00283 case "/status":
00284 this.reloadBotState();
00285 break;
00286 default:
00287 if (!user.equals(IaNode.botname)) {
00288 String escapeString = speech.replaceAll("-:", " ");
00289 String[] res = escapeString.split("[.!?;]+\\s*");
00290
00291 BotReply responce = new BotReply("ERR: Sentence not work !!");
00292 for (String sentence : res) {
00293 responce = this.bot.reply(user, sentence);
00294 }
00295 command.getContext().setWho(IaNode.botname);
00296
00297 if (!Strings.isNullOrEmpty(responce.getReply())
00298 && !responce.getReply().startsWith("ERR:")) {
00299
00300 command.setSubject(responce.getReply());
00301 this.publisherSay.publish(command);
00302
00303 this.logI(String.format("from %s to %s : %s",
00304 command.getContext().getWho(),
00305 user,
00306 command.getSubject()));
00307
00308 if (!responce.getIntents().isEmpty()) {
00309 String content = String.format("[%s]",
00310 Joiner.on(",").join(responce.getIntents()));
00311
00312 command = this.publisherSay.newMessage();
00313 command.getContext().setWhere(where);
00314 command.getContext().setWho(IaNode.botname);
00315 command.setAction("show");
00316 command.setSubject(content);
00317
00318 this.publisherSay.publish(command);
00319 }
00320
00321 } else {
00322 if (Strings.isNullOrEmpty(responce.getReply())
00323 || responce.getReply().contains("ERR: No Reply Matched")) {
00324
00325 } else if (responce.getReply().startsWith("ERR:")) {
00326 this.logE(String.format("bot error : %s", responce));
00327 } else {
00328 this.logI(String.format("bot command : %s", responce));
00329 }
00330 }
00331 }
00332 }
00333 } else {
00334 command.setSubject("IA loading...");
00335 this.publisherSay.publish(command);
00336 this.logI(String.format("from %s to %s : %s",
00337 command.getContext().getWho(), user, command.getSubject()));
00338 }
00339 }
00340
00344 @Override
00345 public void onShutdown(Node node) {
00346 this.persistBotState();
00347 this.sayGoodbye();
00348
00349 this.reconfigServer.close();
00350 super.onShutdown(node);
00351 try {
00352 Thread.sleep(1);
00353 } catch (InterruptedException e) {
00354 }
00355 }
00356
00357 @Override
00358 public IaConfig onReconfigure(IaConfig config, int level) {
00359 this.path = config.getString(IaConfig.RES_PATH, this.path);
00360
00361
00362 config.setString(IaConfig.RES_PATH, this.path);
00363
00364 this.reloadBot();
00365 return config;
00366 }
00367
00373 public void logD(Object message) {
00374 this.connectedNode.getLog().debug(message);
00375 }
00376
00382 public void logI(Object message) {
00383 this.connectedNode.getLog().info(message);
00384 }
00385
00391 public void logE(Object message) {
00392 this.connectedNode.getLog().error(message);
00393 }
00394
00400 public void logE(Exception message) {
00401 this.connectedNode.getLog().error(message.getStackTrace());
00402 }
00403
00404 }