std::string NodeTree::generateNodeName(NodeTypeID typeID) const { // Generate unique name - defaultNodeName() method guarantees there won't be any '/' char std::string defaultNodeTitle = _nodeSystem->defaultNodeName(typeID); std::string nodeTitle = defaultNodeTitle; int num = 1; while(resolveNode(nodeTitle) != InvalidNodeID) { nodeTitle = defaultNodeTitle + " " + std::to_string(num); ++num; } return nodeTitle; }
QString AIMLParser::getResponse(QString input, QList<long> &categoriesId, const bool &srai) { //debug if (srai) _indent ++; QString indentSpace = QString().fill(' ', 2*_indent); _logStream << (!srai ? "\n" : "") + indentSpace + (srai ? "::SRAI: " : "::User Input: ") + input + "\n"; //perform substitutions for input string QVALUELIST_CLASSNAME<QRegExp>::Iterator itOld = _subOld.begin(); QStringList::Iterator itNew = _subNew.begin(); for (; itOld != _subOld.end(); ++itOld, ++itNew ) input.replace(*itOld, *itNew); if (!srai) { _inputList.prepend(input); if (_inputList.count() > MAX_LIST_LENGTH) _inputList.pop_back(); } QStringList capturedTexts, capturedThatTexts, capturedTopicTexts; QString curTopic = _parameterValue["topic"]; normalizeString(curTopic); _logStream << "::Current Topic: " << curTopic; Leaf *leaf = NULL; QString result(""); QStringList sentences = QStringList::split(QRegExp("[\\.\\?!,;\\x061f]"), input); QStringList::Iterator sentence = sentences.begin(); while (sentence != sentences.end()) { if (sentence != sentences.begin()) result += " "; //normalizeString(*sentence); *sentence = (*sentence).lower(); QStringList inputWords = QStringList::split(' ', *sentence); QStringList::ConstIterator it = inputWords.begin(); if (!_root.match(it, inputWords, _thatList.count() && _thatList[0].count() ? _thatList[0][0] : QString(""), curTopic, capturedThatTexts, capturedTopicTexts, categoriesId, &leaf)) { // start lvk - force match with current topic, if no match retry without topic if (curTopic.isEmpty()) { // end lvk return "Internal Error!"; // start lvk - force match with current topic, if no match retry without topic } else { _parameterValue["topic"] = ""; return getResponse(input, categoriesId, srai); } // end lvk } Node *parentNode = leaf->parent; QString matchedPattern = parentNode->word; while (parentNode->parent->parent) { parentNode = parentNode->parent; matchedPattern = parentNode->word + " " + matchedPattern; } _logStream << indentSpace + "::Matched pattern: [" + matchedPattern + "]"; if (!leaf->that.isEmpty()) _logStream << " - Matched that: [" + leaf->that + "]"; if (!leaf->topic.isEmpty()) _logStream << " - Matched topic: [" + leaf->topic + "]"; _logStream << "\n"; capturedTexts.clear(); exactMatch(matchedPattern, *sentence, capturedTexts); //strip whitespaces from the beggining and the end of result if (_visitedNodeList.contains(&leaf->tmplate)) result += "ProgramQ: Infinite loop detected!"; else { _visitedNodeList.append(&leaf->tmplate); categoriesId.append(leaf->id); result += resolveNode(&leaf->tmplate, categoriesId, capturedTexts, capturedThatTexts, capturedTopicTexts).stripWhiteSpace(); } ++sentence; } if (!srai) { QString tempResult = result.simplifyWhiteSpace(); //get the sentences of the result splitted by: . ? ! ; and "arabic ?" QStringList thatSentencesList = QStringList::split(QRegExp("[\\.\\?!;\\x061f]"), tempResult); QStringList inversedList; for (QStringList::Iterator it = thatSentencesList.begin(); it != thatSentencesList.end(); ++it) { //perform substitutions for that string itOld = _subOld.begin(); itNew = _subNew.begin(); for (; itOld != _subOld.end(); ++itOld, ++itNew ) tempResult.replace(*itOld, *itNew); normalizeString(*it); inversedList.prepend(*it); } _thatList.prepend(inversedList); if (_thatList.count() > MAX_LIST_LENGTH) _thatList.pop_back(); _visitedNodeList.clear(); } //debug _logStream << indentSpace + "::Result: " + result + "\n"; if (srai) _indent --; return result; }
//recursively replace all the values & return the QString result QString AIMLParser::resolveNode(QDomNode* node, QList<long> &categoriesId, const QStringList &capturedTexts, const QStringList &capturedThatTexts, const QStringList &capturedTopicTexts) { QString result(""); QString nodeName = node->nodeName(); QDomElement element = node->toElement(); if (nodeName == "random") { QVALUELIST_CLASSNAME<QDomNode> childNodes = elementsByTagName(node, "li"); uint childCount = childNodes.count(); uint random = rand() % childCount; QDomNode child = childNodes[random]; result = resolveNode(&child, categoriesId, capturedTexts, capturedThatTexts, capturedTopicTexts); } else if (nodeName == "condition") { QString name(""); uint condType = 2; if (element.hasAttribute("name")) { condType = 1; name = element.attribute("name"); if (element.hasAttribute("value")) { condType = 0; QString value = element.attribute("value").upper(); QStringList dummy; if (exactMatch(value, _parameterValue[name].upper(), dummy)) { //dirty trick to avoid infinite loop ! element.setTagName("parsedCondition"); result = resolveNode(&element, categoriesId, capturedTexts, capturedThatTexts, capturedTopicTexts); element.setTagName("condition"); } } } if (condType) { QVALUELIST_CLASSNAME<QDomNode> childNodes = elementsByTagName(node, "li"); for (int i = 0; i < childNodes.count(); i++) { QDomNode n = childNodes[i]; if (n.toElement().hasAttribute("value")) { if (condType == 2) name = n.toElement().attribute("name"); QString value = n.toElement().attribute("value").upper(); QStringList dummy; if (exactMatch(value, _parameterValue[name].upper(), dummy)) { result = resolveNode(&n, categoriesId, capturedTexts, capturedThatTexts, capturedTopicTexts); break; } } else { result = resolveNode(&n, categoriesId, capturedTexts, capturedThatTexts, capturedTopicTexts); break; } } } } else { QDomNode n = node->firstChild(); while (!n.isNull()) { result += resolveNode(&n, categoriesId, capturedTexts, capturedThatTexts, capturedTopicTexts); n = n.nextSibling(); } if (node->isText()) result = node->toText().nodeValue(); else if (nodeName == "set") _parameterValue[element.attribute("name")] = result.stripWhiteSpace(); else if (nodeName == "srai") result = getResponse(result, categoriesId, true); else if (nodeName == "think") result = ""; else if (nodeName == "system") //lvk: Remvoved for security reasons //result = executeCommand(result); ; else if (nodeName == "learn") { loadAiml(result); result = ""; } else if (nodeName == "uppercase") { result = result.upper(); } else if (nodeName == "lowercase") { result = result.lower(); } else if (!node->hasChildNodes()) { if (nodeName == "star") { int index = element.attribute("index", "1").toUInt() - 1; result = index < capturedTexts.count() ? capturedTexts[index] : QString(""); } else if (nodeName == "thatstar") { int index = element.attribute("index", "1").toUInt() - 1; result = index < capturedThatTexts.count() ? capturedThatTexts[index] : QString(""); } else if (nodeName == "topicstar") { int index = element.attribute("index", "1").toUInt() - 1; result = index < capturedTopicTexts.count() ? capturedTopicTexts[index] : QString(""); } else if (nodeName == "that") { QString indexStr = element.attribute("index", "1,1"); if (!indexStr.contains(",")) indexStr = "1," + indexStr; int index1 = indexStr.section(',', 0, 0).toInt()-1; int index2 = indexStr.section(',', 1, 1).toInt()-1; result = (index1 < _thatList.count()) && (index2 < _thatList[index1].count()) ? _thatList[index1][index2] : QString(""); } else if (nodeName == "sr") result = getResponse(capturedTexts.count() ? capturedTexts[0] : QString(""), categoriesId, true); else if ( (nodeName == "br") || (nodeName == "html:br") ) result = "\n"; else if ( nodeName == "get" ) result = _parameterValue[element.attribute("name")]; else if ( nodeName == "bot") result = _botVarValue[element.attribute("name")]; else if ( (nodeName == "person") || (nodeName == "person2") || (nodeName == "gender") ) result = capturedTexts.count() ? capturedTexts[0] : QString(""); else if (nodeName == "input") { int index = element.attribute("index", "1").toUInt() - 1; result = index < _inputList.count() ? _inputList[index] : QString(""); } //the following just to avoid warnings ! else if (nodeName == "li") ; else _logStream << "Warning: unknown tag \"" + nodeName + "\"\n"; } //the following just to avoid warnings ! else if ((nodeName == "template") || (nodeName == "pattern") || (nodeName == "li") || (nodeName == "person") || (nodeName == "person2") || (nodeName == "gender") || (nodeName == "parsedCondition")) ; else _logStream << "Warning: unknown tag \"" + nodeName + "\"\n"; } return result; }
//parses a category and creates a correspondant element void AIMLParser::parseCategory(QDomNode* categoryNode) { QDomNode patternNode = categoryNode->namedItem("pattern"); QList<long> categoriesId; QString pattern = resolveNode(&patternNode, categoriesId); normalizeString(pattern); //find where to insert the new node Node *whereToInsert = &_root; QStringList words = QStringList::split(' ', pattern); for ( QStringList::ConstIterator it = words.begin(); it != words.end(); ++it ) { bool found = false; for (Node* child = whereToInsert->childs.first(); child; child = whereToInsert->childs.next()) { if (child->word == *it) { whereToInsert = child; found = true; break; } } if (!found) { for (; it != words.end(); ++it ) { Node *n = new Node; n->word = *it; n->parent = whereToInsert; int index = 0; if (*it == "*") index = whereToInsert->childs.count(); else if ((*it != "_") && whereToInsert->childs.count() && (whereToInsert->childs.at(0)->word == "_")) index = 1; whereToInsert->childs.insert(index, n); whereToInsert = n; } break; } } //Now insert the leaf Leaf *leaf = new Leaf; leaf->parent = whereToInsert; // lvk extension QDomNode idNode = categoryNode->namedItem("id"); if (!idNode.isNull()) { leaf->id = idNode.firstChild().toText().nodeValue().toInt(); } // end lvk extension QDomNode thatNode = categoryNode->namedItem("that"); if (!thatNode.isNull()) { leaf->that = thatNode.firstChild().toText().nodeValue(); normalizeString(leaf->that); } leaf->tmplate = categoryNode->namedItem("template"); QDomNode parentNode = categoryNode->parentNode(); if (!parentNode.isNull() && (parentNode.nodeName() == "topic")) { leaf->topic = parentNode.toElement().attribute("name"); normalizeString(leaf->topic); } int index = 0; int leafWeight = !leaf->that.isEmpty() + !leaf->topic.isEmpty() * 2; for (Leaf* childLeaf = whereToInsert->leafs.first(); childLeaf; childLeaf = whereToInsert->leafs.next()) { int childLeafWeight = !childLeaf->that.isEmpty() + !childLeaf->topic.isEmpty() * 2; if (leafWeight >= childLeafWeight) break; index++; } whereToInsert->leafs.insert(index, leaf); }