⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 graphbuilderaiml.cpp

📁 AIML的实现
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/*
 * RebeccaAIML, Artificial Intelligence Markup Language 
 * C++ api and engine.
 *
 * Copyright (C) 2005 Frank Hassanabad
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

//Boost includes
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>    
#include <boost/filesystem/exception.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string_regex.hpp>
#include <sstream>
using namespace boost;
using namespace boost::filesystem;

//Stl includes
#include <iostream>
using namespace std;


//Xerces includes
#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
XERCES_CPP_NAMESPACE_USE

//Rebecca includes
#include <rebecca/impl/GraphBuilderAIML.h>
#include <rebecca/impl/utils/StackTrace.h>
#include <rebecca/impl/utils/Logging.h>
#include <rebecca/impl/utils/Transcode.h>
#include <rebecca/impl/GraphHandler.h>
#include <rebecca/impl/ConfigurationHandler.h>
#include <rebecca/impl/Exceptions.h>
#include <rebecca/impl/GraphHandlerError.h>
#include <rebecca/impl/ConfigurationHandlerError.h>
#include <rebecca/framework/CustomTags.h>
using namespace rebecca;
using namespace rebecca::framework;

/* Disable Windows VC 7.x warning about 
 * it ignoring the throw specification
 *
 * The extra includes under Windows is 
 * for the callCommand() method to 
 * operate under Windows
 */
#ifdef _WIN32
#    pragma warning( disable : 4290 )
#    include <windows.h>
#    include <errno.h>
#    include <io.h>
#    include <fcntl.h> 
#    include <ctype.h>
#else 
#   include <dlfcn.h>	
#endif

namespace rebecca
{
namespace impl
{

GraphBuilderAIML::GraphBuilderAIML()
	throw(InitializationException &, Exception &)
	: m_setAIMLValidation(false), 
	  m_NodeMapperRoot(*this),
	  m_useThatStar(false),
	  m_useTopicStar(false),
	  m_doConfigurationValidation(false),
	  m_size(0),
	  m_aimlHeader("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> "
						"<aiml version=\"1.0.1\" xmlns=\"http://alicebot.org/2001/AIML-1.0.1\" "
						"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
						"xsi:schemaLocation=\"http://alicebot.org/2001/AIML-1.0.1 http://aitools.org/aiml/schema/AIML.xsd\">"
	               ),
	  m_aimlFooter("</aiml>")
{
	try 
	{
		LOG_BOT_METHOD("GraphBuilderAIML::GraphBuilderAIML()");

		initializeXerces();
		init();
	}
	catch(const XMLException &toCatch) 
	{
		logging("ERROR, Caught XMLXMLException exception");
		Transcode message(toCatch.getMessage());
		String msg("XMLException during initalization: " + message.getString());
		throw InitializationExceptionImpl(msg.c_str());
	}
	catch(exception &e)
	{
		throw ExceptionImpl(e.what());
	}
}

GraphBuilderAIML::GraphBuilderAIML(const GraphBuilderAIML &builder)
	throw(InitializationException &, Exception &)
	: m_setAIMLValidation(false),
	  m_NodeMapperRoot(*this),
	  m_useThatStar(false),
	  m_useTopicStar(false),
	  m_doConfigurationValidation(false),
	  m_size(0),
	  m_aimlHeader("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> "
						"<aiml version=\"1.0.1\" xmlns=\"http://alicebot.org/2001/AIML-1.0.1\" "
						"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
						"xsi:schemaLocation=\"http://alicebot.org/2001/AIML-1.0.1 http://aitools.org/aiml/schema/AIML.xsd\">"
	               ),
	  m_aimlFooter("</aiml>")
{
	try
	{
		LOG_BOT_METHOD("GraphBuilderAIML::GraphBuilderAIML(const GraphBuilderAIML &builder)");	
		init();
	}
	catch(exception &e)
	{
		throw ExceptionImpl(e.what());
	}
}

void GraphBuilderAIML::init()
	throw(XMLException &, Exception &)
{
	try
	{
		//defaultCallBacks does nothing.
		m_callBacks = &m_defaultCallBacks;

		setThat("*");
		setTopic("*");
		logging("Allocating the parsers for various XML files");
		m_AIMLparser.reset(new SAXParser);
		m_configurationParser.reset(new SAXParser);

		logging("Allocating the document handlers for the respective parsers");
		m_AIMLDocumentHandler.reset(new GraphHandler(m_NodeMapperRoot, *this));
		m_configurationDocumentHandler.reset(new ConfigurationHandler(*this));
		
		logging("Allocating the Error handling routines for the respective parsers");
		m_AIMLErrorHandler.reset(new GraphHandlerError(*this));
		m_configurationErrorHandler.reset(new ConfigurationHandlerError(*this));

		logging("Setting the document handlers for the respective parsers");
		m_AIMLparser->setDocumentHandler(m_AIMLDocumentHandler.get());
		m_configurationParser->setDocumentHandler(m_configurationDocumentHandler.get());

		logging("Setting up the error handlers for the respective parsers");
		m_AIMLparser->setErrorHandler(m_AIMLErrorHandler.get());
		m_configurationParser->setErrorHandler(m_configurationErrorHandler.get());
	}
	catch(exception &e)
	{
		throw ExceptionImpl(e.what());
	}
}

void GraphBuilderAIML::addFile(const char * const file) 
	throw(FileNotFoundException &, Exception &)
{
	try
	{
		LOG_BOT_METHOD("void GraphBuilderAIML::addFile(const String &file)");

		logging("<Input> file: " + String(file));

		//Get the file format in the native string for Xerces
		path nativeFileFormat(file, native);
		
		//Get the complete path to the file
		path completePath = complete(nativeFileFormat);
		if(!exists(nativeFileFormat))
		{
			logging("USER ERROR, is not a file");
			String fileNotFoundMsg = "File:" + String(file) + " was not found";
			throw FileNotFoundExceptionImpl(fileNotFoundMsg.c_str());
		}
		else
		{
			logging("file exists, adding to filesNotGraphed");
			//Get the native file system's string to pass to xerces
			string nativeFile = completePath.native_file_string();
			m_filesGraphed.insert(pair<String, bool>(nativeFile, false));
		}
	}
	catch(exception &e)
	{
		throw ExceptionImpl(e.what());
	}
}

void GraphBuilderAIML::addDirectory(const char * const directory, const char * const regularExpression) 
	throw(IllegalArgumentException &, DirectoryNotFoundException &, Exception &)
{
	try
	{
		LOG_BOT_METHOD("void GraphBuilderAIML::addDirectory(const String &directory, const char * const regularExpression)");
		logging("<Input> directory: " + String(directory));
		logging("<Input> regular expression: " + String(regularExpression));

		regex rx1(regularExpression, boost::regex::icase);
		smatch what;

		//Get the file format in the native string for Xerces
		path nativeDirFormat(directory, native);
		
		//Get the complete path to the file
		path completePath = complete(nativeDirFormat);
		if (!exists(nativeDirFormat))
		{
			logging("ERROR, Exception Directory does not exist");
			String directoryNotFoundmsg("Directory:" + String(directory) + " was not found");
			throw DirectoryNotFoundExceptionImpl(directoryNotFoundmsg.c_str());
		}
		
		// default construction yields past-the-end
		directory_iterator end_itr; 

		//Get the native file system's string to pass to xerces
		string nativeDir = completePath.native_file_string();
		for ( directory_iterator itr(completePath); itr != end_itr; ++itr )
		{
			if ( !is_directory( *itr ) && regex_match(string(itr->leaf()), what, rx1))
			{
				logging("Found file of:" + itr->leaf());
				String fileLocation(nativeDir);
				fileLocation += "/" + itr->leaf();
				addFile(fileLocation.c_str());
			}
		}	
	}
	catch(filesystem_error &)
	{
		logging("ERROR, filesystem error");
		throw IllegalArgumentExceptionImpl("File system error");
	}
	catch(bad_expression &)
	{
		logging("ERROR, bad expression");
		throw IllegalArgumentExceptionImpl("Bad expression with the regular expression argument");
	}
	catch(runtime_error &)
	{
		logging("ERROR, Runtime error");
		throw IllegalArgumentExceptionImpl("Run time error occured, more than likely with the regular expression");
	}
	catch(FileNotFoundException &)
	{
		logging("FileNotFoundException, you should not be here.");
		throw IllegalArgumentExceptionImpl("File not found exception occured.  You must have passed a bad directory in.");
	}
	catch(exception &e)
	{
		throw ExceptionImpl(e.what());
	}
}

void GraphBuilderAIML::addString(const char * const stringContainingAIML)
	throw(Exception &)
{
	try
	{
		String stringToInsert = m_aimlHeader + stringContainingAIML + m_aimlFooter;
		m_stringsGraphed.insert(pair<String, bool>(stringToInsert, false));
	}
	catch(exception &e)
	{
		throw ExceptionImpl(e.what());
	}
}

void GraphBuilderAIML::setAddStringAIMLHeader(const char * const aimlHeader)
	throw(Exception &)
{
	try
	{
		m_aimlHeader = aimlHeader;
	}
	catch(exception &e)
	{
		throw ExceptionImpl(e.what());
	}
}

void GraphBuilderAIML::setAddStringAIMLFooter(const char * const aimlFooter)
	throw(Exception &)
{
	try
	{
		m_aimlFooter = aimlFooter;
	}
	catch(exception &e)
	{
		throw ExceptionImpl(e.what());
	}
}


void GraphBuilderAIML::setAIMLSchema(const char * const schema)
	throw(Exception &)
{
	try
	{
		LOG_BOT_METHOD("void GraphBuilderAIML::setAIMLSchema(const char * const schema)");
		logging("<Input> schema:" + String(schema));
		m_aimlSchema = schema;
	}
	catch(exception &e)
	{
		throw ExceptionImpl(e.what());
	}
}

void GraphBuilderAIML::setCommonTypesSchema(const char * const schema)
	throw(Exception &)
{
	try
	{
		LOG_BOT_METHOD("void GraphBuilderAIML::setCommonTypesSchema(const char * const schema)");
		logging("<Input> schema:" + String(schema));
		m_commonTypesSchema = schema;
	}
	catch(exception &e)
	{
		throw ExceptionImpl(e.what());
	}
}

StringPimpl GraphBuilderAIML::getResponseInternal(const char * const input, bool keepPreviousUserInput)
{
	/*
	 * Create a tokenizer to tokenize the words.
	 */
	typedef tokenizer<char_separator<char> > tokenize;
	//const iterator to iterate over the tokens
	typedef tokenize::const_iterator CI; 	

	//Create a string from the input
	String stringInput = inputSubstitute(input).c_str();
	
	//Create a "seperator" based on the sentence splitters
	char_separator<char> sep(m_sentenceSplitters.c_str());
	
	/*
	 * Create a "seperator" based on the sentence splitters but 
	 * when the sentence is split with this seperator the splitters 
	 * will be kept.
	 */
	char_separator<char> sepWithKeptDel("", m_sentenceSplitters.c_str());
	
	//Create a tokenizer from the sentences.
	tokenize tokens(stringInput, sep);

	//The response we are going to return
	String returnResponse;
	
	//Iterate over the senteces one sentence at a time.
	for(CI it = tokens.begin(); it != tokens.end(); ++it)
	{
		//Only Srai::getString() disables this
		if(keepPreviousUserInput)
		{
			//Keep the input for the <input index=""> aiml tag
			m_previousUserInput.push_front(stringInput);
		}
		
		//Get the bot response based upon the string 
		String response = m_NodeMapperRoot.getTemplateString(*it);

		if(!response.empty())
		{	
			/* 
			 * We want to tokenize the returned response but keep the 
			 * seperators such as punctiation and semicolons intact.
			 */
			tokenize responseTokens(response, sepWithKeptDel);
			int i = 1;
			DequeString sentencePunct(1);
			DequeString sentence;
			
			//Iterate over the response output one sentence at a time.
			for(CI jit = responseTokens.begin(); jit != responseTokens.end(); ++jit, ++i)
			{
				/*
				 * Create a modifiable string 
				 * version of it and trim the spaces from it.
				 */
				String that(*jit);
				trim(that);
				
				//Fancy way of checking every other sentence
				if(i % 2) 
				{ 
					//boolean for checking if it's just punctuation.
					bool isPunct = false;
					if(that.size() == 1)
					{
					   /*
						* It has a size of 1.  Check if it is a sentence splitter.
						* This can happen when you have a sentece of the
						* form "hi.?" with two punctiations next to each
						* other.
						*/
						for(unsigned int k = 0; k < m_sentenceSplitters.size(); ++k)
						{
							if(that.at(0) == m_sentenceSplitters.at(k))
							{
								sentencePunct.at(0) += that;
								--i;
								isPunct = true;
								break;
							}
						}
					}
					
					if(!isPunct)
					{
					   /*
						* Not punctiation, so add
						* it as that
						*/
						setThat(that.c_str());
						sentence.push_front(that);
						sentencePunct.push_front(that);
					}
				}
				else 
				{
					/*
					 * It is the punctionation by its self.
					 * So tack on the punctionation to the end of the 
					 * previous sentence.
					 */
					if(!sentencePunct.empty()) 
					{
						sentencePunct.at(0) += that;
					}
				}
			}
			
			//Add this response as a previous bot response
			m_previousBotResponse.push_front(sentence);
			
			/*
			 * Add this response as a previous bot response but with the 
			 * added punctiation.
			 */ 
			m_previousBotResponseWithPunct.push_front(sentencePunct);

			/*
			 * If we don't have a return response let's at least return 
             * a seperating space so if we have more sentences to add to
			 * the return response they'll be seperated by a space.
			 */
			if(!returnResponse.empty())
			{
				returnResponse += " ";
			}
			
			//Add the sentence to the returnResponse string
			returnResponse += response;
		}
		else
		{
			logging("Warning empty response being returned");
		}
	} //end of iterating over the sentences one sentence at a time

	//Trim any remaining spaces at the begining or end of the sentence
	trim(returnResponse);

	//Return a StringPimpl version of the string
	return StringPimpl(returnResponse.c_str());
}

StringPimpl GraphBuilderAIML::getResponse(const char * const input)
	throw(Exception &)
{
	try
	{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -