我正在为痴呆症患者开发一个伴侣机器人,能够记录、存储并将记忆整合到对话中。机器人调用 xml。对话文件,可以检测通过 baseContext.xml 传递参数的上下文以调用 topic.class 并动态重新加载新的 xml 数据解析器和机器人,同时 Main.class 继续其他任务。
但是,我无法决定尝试将解析器/机器人重新加载到 JVM 中是否可行,或者暂停类线程并调用新的类/es 是否是最佳解决方案,或者是否有其他解决方案可用。理想情况下,我想将新的 xml 数据传递到 JVM,而其他类仍然存在。
非常感谢任何帮助。
主类(调用机器人、摄像头、调度程序、文本历史记录等)
public class Main extends javax.swing.JFrame {
private static Bot bot;
public BlockingQueue<String> queue;
public Main() {
initComponents();
//get the parser going
DataParser dp = new DataParser();
//make new bot with level 0 as default and given data parser
bot = new Bot("0", dp);
//dispaly the default message
txtHistory.setText("Bot: " + bot.getMessage());
}
public Main(BlockingQueue<String>queue) {
this.queue = queue;
}
// display bot response in the text area
private static final String VOICENAME="kevin16";
private static void addBotText(String message) {
txtHistory.setText(txtHistory.getText() + "\nBot: " + message);
//turn the bot response to sound
Voice voice;
VoiceManager vm= VoiceManager.getInstance();
voice=vm.getVoice(VOICENAME);
voice.allocate();
try{
voice.speak(bot.getMessage());
}catch(Exception e){
}
voice.deallocate();
}
public static void listen (String speech) {
txtHistory.setText(txtHistory.getText() + "\nYou: " + speech + "\n");
//send the input to the bot and get bot response
数据解析器类处理 xml 加载到 DOM
package bot;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class DataParser {
private Document dom;
private HashMap<String, State> states = new HashMap<String, State>();
private ArrayList<String> invalidMessages = new ArrayList();
private int invalidMessageIndex = 0;
public int stateCounter = 1000;
public String fileSource;
// default constructor
public DataParser() {
// Load the XML file and parse it
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
//get the filepath of source
String fileSource = Context.getSource();
DocumentBuilder db = dbf.newDocumentBuilder();
//parse using builder to get DOM representation of the XML file
dom = db.parse(fileSource);
// Load configuration and states from the XML file
loadConfiguration();
loadStates();
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (SAXException se) {
se.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
// Load states from XML file
private void loadStates() {
// get document element object
Element docEle = dom.getDocumentElement();
// get all State node names
NodeList nl = docEle.getElementsByTagName("State");
// if node is not null and has children
if (nl != null && nl.getLength() > 0) {
// loop through all children
for (int i = 0; i < nl.getLength(); i++) {
// get state element
Element el = (Element) nl.item(i);
// get state id
String id = el.getAttribute("id");
// get all state messages
ArrayList messages = new ArrayList();
NodeList messagesNodeList = el.getElementsByTagName("message");
// if messages node is not null and has children
if (messagesNodeList != null && messagesNodeList.getLength() > 0) {
// loop through all children
for (int j = 0; j < messagesNodeList.getLength(); j++) {
// get current message element
Element elmsg = (Element) messagesNodeList.item(j);
// append message node value to the messages list
messages.add(elmsg.getFirstChild().getNodeValue());
}
}
// get keywords in the current state
ArrayList keywords = getKeywords(el);
// construct a new State object
State state = new State(id, messages, keywords);
stateCounter ++;
// add the state to the states hashmap
states.put(id, state);
}
}
}
// get state object by id
public State getState(String id) {
return states.get(id);
}
// create a new state
public void addState(State state){
states.put(state.getId(), state);
stateCounter++;
}
// get all keywords in an State tag
public ArrayList getKeywords(Element ele) {
// construct keywords arraylist
ArrayList keywords = new ArrayList();
// get all nodes by keyword tag name
NodeList nl = ele.getElementsByTagName("keyword");
// if the tag is not null and has children
if (nl != null && nl.getLength() > 0) {
// loop through all the children
for (int i = 0; i < nl.getLength(); i++) {
//get the keyword element
Element el = (Element) nl.item(i);
// find the keyword target, classname and argument attributes
String wordTag = el.getFirstChild().getNodeValue();
String target = el.getAttribute("target");
String className = el.getAttribute("className");
String arg = el.getAttribute("arg");
String variable = el.getAttribute("variable");
int points = 0;
try{
points = Integer.valueOf(el.getAttribute("points"));
}catch (Exception e){
}
String learn = el.getAttribute("learn");
// split keyword by comma
String[] words = wordTag.split(",");
// loop through all words
for (String word : words) {
// trim the word to remove spaces
word = word.trim();
// construct a new keyword
Keyword keyword = new Keyword(word, target, className, arg, variable, points, learn );
// add the keyword to keywords array list
keywords.add(keyword);
}
}
}
// return all the keywords in the given node
return keywords;
}
// returns one of the invalid messages and move the index to the next message
public String getInvalidAnswer() {
// get current answer
String answer = invalidMessages.get(invalidMessageIndex);
// increase the index, if it is end of messages, reset the index to 0
invalidMessageIndex++;
if (invalidMessageIndex >= invalidMessages.size()) {
invalidMessageIndex = 0;
}
return answer;
}
// load cofig tags from data xml file
private void loadConfiguration() {
// get document element
Element docEle = dom.getDocumentElement();
// get all node names for invalid messages
NodeList node = docEle.getElementsByTagName("InvalidMessages");
// get all message nodes inside invalid messages node
NodeList nl = ((Element) node.item(0)).getElementsByTagName("message");
// if node is not null and has children
if (nl != null && nl.getLength() > 0) {
// loop through all children
for (int i = 0; i < nl.getLength(); i++) {
// get message node
Element el = (Element) nl.item(i);
// get message and add it to invalid messages array
String message = el.getFirstChild().getNodeValue();
invalidMessages.add(message);
}
}
}
}
bot 类管理对话并调用专门的类。
package bot;
import smallTalk.Morning;
import smallTalk.Afternoon;
import smallTalk.Evening;
import smallTalk.Night;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class Bot {
// Store all regular expression matches
private HashMap<String,String> dictionary;
// Default state to start the bot
String level = "0";
DataParser parser;
// default constructor
public Bot(String level, DataParser parser) {
dictionary = new HashMap<String,String>();
this.level = level;
this.parser = parser;
}
// get current state message
public String getMessage() {
State state = parser.getState(level);
return replaceMatches(state.getMessage()).trim();
}
// send user message to the bot and get the response
public String send(String message) {
String response = "";
State state = parser.getState(level);
// end of the tree
if (state.getKeywords().isEmpty()) {
this.level = "0";
}
// match the keyword with given message
Keyword match = parse(message, state.getKeywords());
// if no keyword is matched, display one of the invalid answers
if (match == null) {
response = parser.getInvalidAnswer();
} else {
// if match classname is provided, check to get the dynamic response
if (match.className.length() > 0) {
// check for Weather dynamic response
if (match.className.equals("Weather")) {
Weather weather = new Weather();
response = weather.getResponse(match.arg);
this.level = "0";
}
// check for News dynamic response
else if (match.className.equals("News")) {
News news = new News();
response = news.getResponse(match.arg);
this.level = "0";
}
else if (match.className.equals("Morning")) {
Morning morning = new Morning();
morning.wakeup();
}
else if (match.className.equals("Afternoon")) {
Afternoon afternoon = new Afternoon();
afternoon.midday();
}
else if (match.className.equals("Evening")) {
Evening evening = new Evening();
evening.dinner();
}
else if (match.className.equals("Night")) {
Night night = new Night();
night.late();
}
// check for Topic dynamic response
else if (match.className.equals("Topic")) {
Topic topic = new Topic();
topic.getTopic(match.arg);
}
} else {
// get the new state and return the new message
if (response.length() == 0) {
this.level = match.target;
state = parser.getState(level);
// if it is end of the tree
if (state.getKeywords().isEmpty()) {
response = this.getMessage();
this.level = "0";
}
}
}
}
return response;
}
// parse the given text to find best match in the keywords
private Keyword parse(String text, ArrayList<Keyword> keylist) {
// set the default match to none
int bestMatch = -1;
Keyword match = null;
// loop through keywords
for (int i = 0; i < keylist.size(); i++) {
// get number of matches of the keyword with given text
int matches = getMatches(text, keylist.get(i));
// if match is better than best match, replace it
if (matches > -1 && matches > bestMatch) {
match = keylist.get(i);
bestMatch = matches;
}
}
// add best answers regex variable value into the dictionary for future reference
if (match != null){
if(match.learn.length() > 0 ){
// get training data keyword and description
String subject = dictionary.get(match.learn);
String result = match.variableValue;
// create a new state for new trained data
ArrayList<String> messages = new ArrayList<String>();
messages.add(result);
State myState = new State(String.valueOf(parser.stateCounter),messages,new ArrayList());
parser.addState(myState);
// add the new trained keyword
Keyword keyword = new Keyword(subject, myState.getId(), "", "", "", 1, "" );
State state = parser.getState("1");
ArrayList<Keyword> keywords = state.getKeywords();
keywords.add(keyword);
}else{
if (match.variableValue.length() > 0){
dictionary.put(match.variable, match.variableValue);
}
}
}
return match;
}
// get number of matches of the given keywords in the given list
private int getMatches(String text, Keyword keyword) {
// no match by default
int result = -1;
// return 0 match when keyword is *
if(keyword.keyword.equals("*")){
return keyword.points;
}
// if regex is expected
if(keyword.variable.length() > 0){
String match = Regex.match(keyword.keyword, text);
if(match.length() > 0){
keyword.variableValue = match;
return keyword.points;
}
}
String[] words = keyword.keyword.split(" ");
// loop through list of the keywords
for (String word : words) {
// if current keyword is in the text, add points
if (text.toLowerCase().indexOf(word.toLowerCase()) >= 0) {
result = result + keyword.points + 1;
} else {
// return null if one of the keywords does not exists
return -1;
}
}
return result;
}
// replace given text with variables in the dictionary
public String replaceMatches(String text){
// replace variables within dictionary in the text
for (Map.Entry<String, String> entry : dictionary.entrySet()) {
text = text.replaceAll("\\["+entry.getKey() + "\\]", entry.getValue());
}
// remove empty variables tags
return Regex.clear(text);
}
}
Context 类将 xml 文件源传递给数据解析器。
package bot;
public class Context {
public static String source = "newcontext.xml";
//method to get value of source called in dataParser
public static String getSource(){
return source;
}
//get the new topic from Topic Class and prepare to reload DataParser/Bot
public static void newSource(String currentTopic){
source = currentTopic;
}
}