Initial commit

This commit is contained in:
CrabMustard 2018-12-13 18:20:08 -06:00
commit 8cd9032f69
94 changed files with 7613 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
*.iml
.gradle
/local.properties
/.idea/caches/build_file_checksums.ser
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
.DS_Store
/build
/captures
.externalNativeBuild

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WizardSettings">
<option name="children">
<map>
<entry key="imageWizard">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="imageAssetPanel">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="launcher">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="foregroundImage">
<value>
<PersistentState>
<option name="values">
<map>
<entry key="scalingPercent" value="173" />
<entry key="trimmed" value="true" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
<option name="values">
<map>
<entry key="foregroundImage" value="C:\Users\tommy\AndroidStudioProjects\AndroidBotInterface\app\src\main\res\drawable\applgogo.png" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</component>
</project>

View File

@ -0,0 +1,29 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
</code_scheme>
</component>

18
.idea/gradle.xml Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

38
.idea/misc.xml Normal file
View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="7">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="6">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

53
app/build.gradle Normal file
View File

@ -0,0 +1,53 @@
apply plugin: 'com.android.application'
repositories {
maven {
url 'http://nexus.bippo.co.id/nexus/content/repositories/soluvas-public-snapshots/'
}
maven {
url 'http://nexus.bippo.co.id/nexus/content/repositories/soluvas-public-thirdparty/'
}
maven {
url 'http://jcenter.bintray.com'
}
}
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.fpghoti.androidbotinterface"
minSdkVersion 26
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation ('com.android.support:appcompat-v7:28.0.0')
implementation ('com.android.support.constraint:constraint-layout:1.1.3')
implementation group: 'joda-time', name: 'joda-time', version: '2.3'
implementation ('com.jcabi:jcabi-aspects:0.22.6')
testImplementation ('junit:junit:4.12')
androidTestImplementation ('com.android.support.test:runner:1.0.2')
androidTestImplementation ('com.android.support.test.espresso:espresso-core:3.0.2')
}

21
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,26 @@
package com.fpghoti.androidbotinterface;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.fpghoti.androidbotinterface", appContext.getPackageName());
}
}

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fpghoti.androidbotinterface">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".SplashActivity"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,157 @@
package com.fpghoti.androidbotinterface;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import com.fpghoti.androidbotinterface.bot.ChatBot;
import java.io.File;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class MainActivity extends AppCompatActivity {
private EditText editText;
private TextView textOut;
public static ChatBot bot;
private boolean isLoaded;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
isLoaded = false;
editText = (EditText) findViewById(R.id.editText);
loadBot();
}
private void loadBot(){
outputPrint("Now loading the chat bot files...");
File fileExt = new File(getExternalFilesDir(null).getAbsolutePath() + "/bots");
if (!fileExt.exists()) {
try {
unpackBot();
} catch (Exception e) {
e.printStackTrace();
return;
}
}
bot = new ChatBot(getExternalFilesDir(null).getAbsolutePath());
isLoaded = true;
outputPrint("Chat bot files are done loading!");
}
private void unpackBot() {
try {
ZipInputStream zs = new ZipInputStream(getAssets().open("bots.zip"));
ZipEntry entry = null;
String destination = getExternalFilesDir(null).getAbsolutePath() + "/";
byte[] buffer = new byte[4096];
int bytes;
while ((entry = zs.getNextEntry()) != null) {
if (entry.isDirectory()) {
File dir = new File(destination, entry.getName());
if (!dir.exists()) {
dir.mkdir();
}
} else {
FileOutputStream file = new FileOutputStream(destination + entry.getName());
while ((bytes = zs.read(buffer)) != -1) {
file.write(buffer, 0, bytes);
}
file.close();
}
}
zs.close();
} catch(Exception e) {
e.printStackTrace();
}
}
public void sendMessage(View view) {
String message = editText.getText().toString();
textOut = (TextView) findViewById(R.id.output);
if (message.length() > 0) {
while(lineCount(textOut.getText().toString()) > 20){
textOut.setText(removeFirstLine(textOut.getText().toString()));
}
textOut.setText(textOut.getText() + "\n" + "You: " + message);
hideKeyboard();
editText.getText().clear();
if(isLoaded) {
final String finalmsg = bot.chatBot(message);
new java.util.Timer().schedule(
new java.util.TimerTask() {
@Override
public void run() {
while (lineCount(textOut.getText().toString()) > 20) {
textOut.setText(removeFirstLine(textOut.getText().toString()));
}
textOut.setText(textOut.getText() + "\n" + "Bot: " + finalmsg);
}
},
2000
);
}else{
new java.util.Timer().schedule(
new java.util.TimerTask() {
@Override
public void run() {
while (lineCount(textOut.getText().toString()) > 20) {
textOut.setText(removeFirstLine(textOut.getText().toString()));
}
outputPrint("The chat bot is still loading.");
}
},
2000
);
}
}
}
public void outputPrint(String input){
textOut = (TextView) findViewById(R.id.output);
if (input.length() > 0) {
while(lineCount(textOut.getText().toString()) > 20){
textOut.setText(removeFirstLine(textOut.getText().toString()));
}
textOut.setText(textOut.getText() + "\n" + input);
}
}
private void hideKeyboard() {
View v = getCurrentFocus();
if (v == null) {
v = new View(this);
}
InputMethodManager manager = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
manager.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
public int lineCount(String s){
return s.split("\r\n|\r|\n").length;
}
public String removeFirstLine(String s){
if(lineCount(s) < 2){
return "";
}
String result = "";
String[] lines = s.split("\r\n|\r|\n");
for(int i = 1; i < lineCount(s) - 1; i++){
result += lines[i] + "\n";
}
result += lines[lineCount(s) - 1];
return result;
}
}

View File

@ -0,0 +1,16 @@
package com.fpghoti.androidbotinterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class SplashActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
}

View File

@ -0,0 +1,32 @@
package com.fpghoti.androidbotinterface.bot;
public class BotThink {
//easteregg won't see this if everything's working
public static String think(String input){
input = input.toLowerCase();
if(input.contains("android studio")){
if(input.contains("like")){
if(input.contains("dont") || input.contains("don't") || input.contains("not")){
return "It is wise to keep your distance from Android Studio.";
} else if(input.contains("i ")){
return "Try staying up until 4:00 AM trying to get the bot software to load in Android Studio. Good luck liking it after that.";
}
return "No more Android Studio, please!";
}
}else if(input.contains("hello") || input.equals("hi") || input.equals("hi.") || input.equals("hi!") || input.contains("greetings") || input.contains("blessings and tidings")){
return "Hello!";
}else if(input.contains("are you working right now")){
return("No, I am in fact NOT working right now. Android Studio INSISTS on not reading files from the SD card, so you are seeing this error message. Thanks for asking, though.");
}else if(input.contains("the room")){
return "Produced by, directed by, written by, and starring Tommy Wiseau, The Room was once an odd, obscure cult classic, but has gotten too much attention for my tastes lately.";
}else if(input.contains("a talking cat")){
return "That is that one movie with the cat that can only talk to people once. It was a direct to DVD low-budget film. I honestly thin Foodfight was higher quality than A Talking Cat.";
}else if(input.contains("backstroke of the west")){
return "Backstroke of the West is arguably the best Star Wars film and a fan-favorite Star War Gatering. It ends with Darth Vader shouting, \"DO NOT WANT!\" instead of his usual line.";
}else if(input.contains("space thunder kids")){
return "What can I say? This is a mix of eight different Korean cartoons with one guy doing ninety percent of the voice acting. A massive trainwreck.";
}
return "lol";
}
}

View File

@ -0,0 +1,55 @@
package com.fpghoti.androidbotinterface.bot;
import org.alicebot.ab.Bot;
import org.alicebot.ab.Chat;
import com.jcabi.aspects.Async;
public class ChatBot {
private Bot bot;
private Chat chatSession = null;
public ChatBot(String path) {
bot = new Bot("default",path,"chat");
chatSession = new Chat(bot);
}
@Async
public String chatBot(String input) {
String msg = "none";
try {
msg = chatSession.multisentenceRespond(input);
//zelda cdi reference
if(input.toLowerCase().contains("youve killed me") || input.toLowerCase().contains("you've killed me")){
msg = "Good.";
}
int count = 0;
//bot does not always respond
while(msg.equalsIgnoreCase("") || msg.equalsIgnoreCase("I have no answer for that.")){
String lastWord = input.substring(input.lastIndexOf(" ")+1);
if(count > 0){
lastWord = "lol ";
}
msg = chatSession.multisentenceRespond(lastWord);
if(count > 0){
msg = BotThink.think(input);
}
count++;
}
//bot sometimes tries to pull up weird link. I Decided to just disable this outright by replacing the message
if(msg.contains("<oob>") || msg.contains("<a") || msg.toLowerCase().contains("unknown?")){
msg = "If you say so.";
}
} catch (Exception e) {
e.printStackTrace();
}
final String sendthis = msg;
return sendthis;
}
}

View File

@ -0,0 +1,309 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.util.ArrayList;
import java.util.Collections;
import org.alicebot.ab.utils.IOUtils;
public class AB {
/**
* Experimental class that analyzes log data and suggests
* new AIML patterns.
*
*/
public static boolean shuffle_mode = true;
public static boolean sort_mode = false;
public static boolean filter_atomic_mode = false;
public static boolean filter_wild_mode = false;
public static String logfile = MagicStrings.root_path+"/data/"+MagicStrings.ab_sample_file; //normal.txt";
public static AIMLSet passed = new AIMLSet("passed");
public static AIMLSet testSet = new AIMLSet("1000");
public static int runCompletedCnt;
/**
* Calculates the botmaster's productivity rate in
* categories/sec when using Pattern Suggestor to create content.
*
* @param runCompletedCnt number of categories completed in this run
* @param timer tells elapsed time in ms
* @see AB
*/
public static void productivity (int runCompletedCnt, Timer timer) {
//float time = timer.elapsedTimeMins();
}
/** saves a new AIML category and increments runCompletedCnt
*
* @param bot the bot the category belongs to
* @param pattern the category's pattern (that and topic = *)
* @param template the category's template
* @param filename the filename for the category.
*/
public static void saveCategory(Bot bot, String pattern, String template, String filename) {
String that = "*";
String topic = "*";
Category c = new Category(0, pattern, that, topic, template, filename);
if (c.validate()) {
bot.brain.addCategory(c);
// bot.categories.add(c);
bot.writeAIMLIFFiles();
runCompletedCnt++;
}
}
/** mark a category as deleted
*
* @param bot the bot the category belogs to
* @param c the category
*/
public static void deleteCategory(Bot bot, Category c) {
c.setFilename(MagicStrings.deleted_aiml_file);
c.setTemplate(MagicStrings.deleted_template);
bot.deletedGraph.addCategory(c);
bot.writeDeletedIFCategories();
}
/** skip a category. Make the category as "unfinished"
*
* @param bot the bot the category belogs to
* @param c the category
*/
public static void skipCategory(Bot bot, Category c) {
c.setFilename(MagicStrings.unfinished_aiml_file);
c.setTemplate(MagicStrings.unfinished_template);
bot.unfinishedGraph.addCategory(c);
bot.writeUnfinishedIFCategories();
}
public static void abwq(Bot bot) {
Timer timer = new Timer();
timer.start();
bot.classifyInputs(logfile);
bot.writeQuit();
}
/** magically suggests new patterns for a bot.
* Reads an input file of sample data called logFile.
* Builds a graph of all the inputs.
* Finds new patterns in the graph that are not already in the bot.
* Classifies input log into those new patterns.
*
*
* @param bot the bot to perform the magic on
*/
public static void ab (Bot bot) {
String logFile = logfile;
MagicBooleans.trace_mode = false;
MagicBooleans.enable_external_sets = false;
Timer timer = new Timer();
bot.brain.nodeStats();
timer.start();
bot.graphInputs(logFile);
//bot.inputGraph.printgraph();
timer.start();
bot.findPatterns();
timer.start();
bot.patternGraph.nodeStats();
bot.classifyInputs(logFile);
}
/** train the bot through a terminal interaction
*
* @param bot the bot to train
*/
public static void terminalInteraction (Bot bot) {
Timer timer = new Timer();
sort_mode = !shuffle_mode;
// if (sort_mode)
Collections.sort(bot.suggestedCategories, Category.ACTIVATION_COMPARATOR);
ArrayList<Category> topSuggestCategories = new ArrayList<Category>();
for (int i = 0; i < 10000 && i < bot.suggestedCategories.size(); i++) {
topSuggestCategories.add(bot.suggestedCategories.get(i));
}
bot.suggestedCategories = topSuggestCategories;
if (shuffle_mode) Collections.shuffle(bot.suggestedCategories);
timer = new Timer();
timer.start();
runCompletedCnt = 0;
ArrayList<Category> filteredAtomicCategories = new ArrayList<Category>();
ArrayList<Category> filteredWildCategories = new ArrayList<Category>();
for (Category c : bot.suggestedCategories) if (!c.getPattern().contains("*")) filteredAtomicCategories.add(c);
else filteredWildCategories.add(c);
ArrayList <Category> browserCategories;
if (filter_atomic_mode) browserCategories = filteredAtomicCategories;
else if (filter_wild_mode) browserCategories = filteredWildCategories;
else browserCategories = bot.suggestedCategories;
// log.info(filteredAtomicCategories.size()+" filtered suggested categories");
for (Category c : browserCategories) {
try {
@SuppressWarnings({ "rawtypes", "unchecked" })
ArrayList samples = new ArrayList(c.getMatches());
Collections.shuffle(samples);
int sampleSize = Math.min(MagicNumbers.displayed_input_sample_size, c.getMatches().size());
for (int i = 0; i < sampleSize; i++) {
}
productivity(runCompletedCnt, timer);
String textLine = "" + IOUtils.readInputTextLine();
terminalInteractionStep(bot, "", textLine, c);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
/** process one step of the terminal interaction
*
* @param bot the bot being trained.
* @param request used when this routine is called by benchmark testSuite
* @param textLine response typed by the botmaster
* @param c AIML category selected
*/
public static void terminalInteractionStep (Bot bot, String request, String textLine, Category c) {
String template = null;
if (textLine.contains("<pattern>") && textLine.contains("</pattern>")) {
int index = textLine.indexOf("<pattern>")+"<pattern>".length();
int jndex = textLine.indexOf("</pattern>");
int kndex = jndex + "</pattern>".length();
if (index < jndex) {
String pattern = textLine.substring(index, jndex);
c.setPattern(pattern);
textLine = textLine.substring(kndex, textLine.length());
}
}
String botThinks = "";
String[] pronouns = {"he", "she", "it", "we", "they"};
for (String p : pronouns) {
if (textLine.contains("<"+p+">")) {
textLine = textLine.replace("<"+p+">","");
botThinks = "<think><set name=\""+p+"\"><set name=\"topic\"><star/></set></set></think>";
}
}
if (textLine.equals("q")) System.exit(0); // Quit program
else if (textLine.equals("wq")) { // Write AIML Files and quit program
bot.writeQuit();
/* Nodemapper udcNode = bot.brain.findNode("*", "*", "*");
if (udcNode != null) {
AIMLSet udcMatches = new AIMLSet("udcmatches");
udcMatches.addAll(udcNode.category.getMatches());
udcMatches.writeAIMLSet();
}*/
/* Nodemapper cNode = bot.brain.match("JOE MAKES BEER", "unknown", "unknown");
if (cNode != null) {
AIMLSet cMatches = new AIMLSet("cmatches");
cMatches.addAll(cNode.category.getMatches());
cMatches.writeAIMLSet();
}
if (passed.size() > 0) {
AIMLSet difference = new AIMLSet("difference");
AIMLSet intersection = new AIMLSet("intersection");
for (String s : passed) if (testSet.contains(s)) intersection.add(s);
passed = intersection;
passed.setName = "passed";
difference.addAll(testSet);
difference.removeAll(passed);
difference.writeAIMLSet();
passed.writeAIMLSet();
testSet.writeAIMLSet();
log.info("Wrote passed test cases");
}*/
System.exit(0);
}
else if (textLine.equals("skip") || textLine.equals("")) { // skip this one for now
skipCategory(bot, c);
}
else if (textLine.equals("s") || textLine.equals("pass")) { // skip this one for now
passed.add(request);
AIMLSet difference = new AIMLSet("difference");
difference.addAll(testSet);
difference.removeAll(passed);
difference.writeAIMLSet();
passed.writeAIMLSet();
}
else if (textLine.equals("d")) { // delete this suggested category
deleteCategory(bot, c);
}
else if (textLine.equals("x")) { // ask another bot
template = "<sraix>"+c.getPattern().replace("*","<star/>")+"</sraix>";
template += botThinks;
saveCategory(bot, c.getPattern(), template, MagicStrings.sraix_aiml_file);
}
else if (textLine.equals("p")) { // filter inappropriate content
template = "<srai>"+MagicStrings.inappropriate_filter+"</srai>";
template += botThinks;
saveCategory(bot, c.getPattern(), template, MagicStrings.inappropriate_aiml_file);
}
else if (textLine.equals("f")) { // filter profanity
template = "<srai>"+MagicStrings.profanity_filter+"</srai>";
template += botThinks;
saveCategory(bot, c.getPattern(), template, MagicStrings.profanity_aiml_file);
}
else if (textLine.equals("i")) {
template = "<srai>"+MagicStrings.insult_filter+"</srai>";
template += botThinks;
saveCategory(bot, c.getPattern(), template, MagicStrings.insult_aiml_file);
}
else if (textLine.contains("<srai>") || textLine.contains("<sr/>")) {
template = textLine;
template += botThinks;
saveCategory(bot, c.getPattern(), template, MagicStrings.reductions_update_aiml_file);
}
else if (textLine.contains("<oob>")) {
textLine = "I don't know.";
template = textLine;
template += botThinks;
saveCategory(bot, c.getPattern(), template, MagicStrings.oob_aiml_file);
}
else if (textLine.contains("<set name") || botThinks.length() > 0) {
template = textLine;
template += botThinks;
saveCategory(bot, c.getPattern(), template, MagicStrings.predicates_aiml_file);
}
else if (textLine.contains("<get name") && !textLine.contains("<get name=\"name")) {
template = textLine;
template += botThinks;
saveCategory(bot, c.getPattern(), template, MagicStrings.predicates_aiml_file);
}
else {
template = textLine;
template += botThinks;
saveCategory(bot, c.getPattern(), template, MagicStrings.personality_aiml_file);
}
}
}

View File

@ -0,0 +1,169 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
/**
* implements AIML Map
*
* A map is a function from one string set to another.
* Elements of the domain are called keys and elements of the range are called values.
*
*/
@SuppressWarnings("serial")
public class AIMLMap extends HashMap<String, String> {
public String mapName;
String host; // for external maps
String botid; // for external maps
boolean isExternal = false;
/**
* constructor to create a new AIML Map
*
* @param name the name of the map
*/
public AIMLMap (String name) {
super();
this.mapName = name;
}
/**
* return a map value given a key
*
* @param key the domain element
* @return the range element or a string indicating the key was not found
*/
public String get(String key) {
String value;
if (mapName.equals(MagicStrings.map_successor)) {
try {
int number = Integer.parseInt(key);
return String.valueOf(number+1);
} catch (Exception ex) {
return MagicStrings.unknown_map_value;
}
}
else if (mapName.equals(MagicStrings.map_predecessor)) {
try {
int number = Integer.parseInt(key);
return String.valueOf(number-1);
} catch (Exception ex) {
return MagicStrings.unknown_map_value;
}
}
else if (isExternal && MagicBooleans.enable_external_sets) {
//String[] split = key.split(" ");
String query = mapName.toUpperCase()+" "+key;
String response = Sraix.sraix(null, query, MagicStrings.unknown_map_value, null, host, botid, null, "0");
value = response;
}
else value = super.get(key);
if (value == null) value = MagicStrings.unknown_map_value;
return value;
}
/**
* put a new key, value pair into the map.
*
* @param key the domain element
* @param value the range element
* @return the value
*/
@Override
public String put(String key, String value) {
//log.info("AIMLMap put "+key+"="+value);
return super.put(key, value);
}
/**
* reads an input stream and loads a map into the bot.
*
* @param in input stream
* @param bot AIML bot
* @return number of map elements loaded
*/
public int readAIMLMapFromInputStream(InputStream in, Bot bot) {
int cnt=0;
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
//Read File Line By Line
try {
while ((strLine = br.readLine()) != null && strLine.length() > 0) {
String[] splitLine = strLine.split(":");
//log.info("AIMLMap line="+strLine);
if (splitLine.length >= 2) {
cnt++;
if (strLine.startsWith(MagicStrings.remote_map_key)) {
if (splitLine.length >= 3) {
host = splitLine[1];
botid = splitLine[2];
isExternal = true;
}
}
else {
String key = splitLine[0].toUpperCase();
String value = splitLine[1];
// assume domain element is already normalized for speedier load
//key = bot.preProcessor.normalize(key).trim();
put(key, value);
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return cnt;
}
/**
* read an AIML map for a bot
*
* @param bot the bot associated with this map.
*/
public void readAIMLMap (Bot bot) {
try{
// Open the file that is the first
// command line parameter
File file = new File(MagicStrings.maps_path+"/"+mapName+".txt");
if (file.exists()) {
FileInputStream fstream = new FileInputStream(MagicStrings.maps_path+"/"+mapName+".txt");
// Get the object
readAIMLMapFromInputStream(fstream, bot);
fstream.close();
}
}catch (Exception e){//Catch exception if any
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import org.w3c.dom.Node;
import java.util.Set;
/**
* The interface needed to implement AIML Extension
*
* A class implementing AIMLProcessorExtension should return
* a Set of tag names and provide a function to recursively evaluate the
* XML parse tree for each node associated with a new tag.
*/
public interface AIMLProcessorExtension {
/**
* provide the AIMLProcessor with a list of extension tag names.
*
* @return Set of extension tag names
*/
public Set<String> extensionTagSet();
/**
* recursively evaluate AIML from a node corresponding an extension tag
*
* @param node current XML parse node
* @param ps current parse state
* @return result of evaluating AIML
*/
public String recursEval(Node node, ParseState ps);
}

View File

@ -0,0 +1,151 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/**
* implements AIML Sets
*/
public class AIMLSet extends HashSet<String> {
//private static final Logger log = LoggerFactory.getLogger(AIMLSet.class);
public String setName;
int maxLength = 1; // there are no empty sets
String host; // for external sets
String botid; // for external sets
boolean isExternal = false;
/**
* constructor
* @param name name of set
*/
public AIMLSet (String name) {
super();
this.setName = name.toLowerCase();
if (setName.equals(MagicStrings.natural_number_set_name)) maxLength = 1;
}
public boolean contains(String s) {
//if (isExternal) log.info("External "+setName+" contains "+s+"?");
//else log.info("Internal "+setName+" contains "+s+"?");
if (isExternal && MagicBooleans.enable_external_sets) {
String[] split = s.split(" ");
if (split.length > maxLength) return false;
String query = MagicStrings.set_member_string+setName.toUpperCase()+" "+s;
String response = Sraix.sraix(null, query, "false", null, host, botid, null, "0");
// log.info("External "+setName+" contains "+s+"? "+response);
if (response.equals("true")) return true;
else return false;
} else if (setName.equals(MagicStrings.natural_number_set_name)) {
Pattern numberPattern = Pattern.compile("[0-9]+");
Matcher numberMatcher = numberPattern.matcher(s);
Boolean isanumber = numberMatcher.matches();
//log.info("AIMLSet isanumber '"+s+"' "+isanumber);
return isanumber;
}
else return super.contains(s);
}
public void writeAIMLSet () {
// log.info("Writing AIML Set "+setName);
try{
// Create file
FileWriter fstream = new FileWriter(MagicStrings.sets_path+"/"+setName+".txt");
BufferedWriter out = new BufferedWriter(fstream);
for (String p : this) {
out.write(p.trim());
out.newLine();
}
//Close the output stream
out.close();
}catch (Exception e){//Catch exception if any
// log.error("Cannot write AIML set " + setName + ": " + e, e);
}
}
public int readAIMLSetFromInputStream(InputStream in, Bot bot) {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
int cnt = 0;
//Read File Line By Line
try {
while ((strLine = br.readLine()) != null && strLine.length() > 0) {
cnt++;
//strLine = bot.preProcessor.normalize(strLine).toUpperCase();
// assume the set is pre-normalized for faster loading
if (strLine.startsWith("external")) {
String[] splitLine = strLine.split(":");
if (splitLine.length >= 4) {
host = splitLine[1];
botid = splitLine[2];
maxLength = Integer.parseInt(splitLine[3]);
isExternal = true;
// log.info("Created external set at "+host+" "+botid);
}
}
else {
strLine = strLine.toUpperCase().trim();
String [] splitLine = strLine.split(" ");
int length = splitLine.length;
if (length > maxLength) maxLength = length;
//log.info("readAIMLSetFromInputStream "+strLine);
add(strLine.trim());
}
/*Category c = new Category(0, "ISA"+setName.toUpperCase()+" "+strLine.toUpperCase(), "*", "*", "true", MagicStrings.null_aiml_file);
bot.brain.addCategory(c);*/
}
} catch (Exception ex) {
ex.printStackTrace();
}
return cnt;
}
public void readAIMLSet (Bot bot) {
final String setPath = MagicStrings.sets_path+"/"+setName+".txt";
// log.info("Reading AIML Set " + setPath);
try{
// Open the file that is the first
// command line parameter
File file = new File(setPath);
if (file.exists()) {
FileInputStream fstream = new FileInputStream(setPath);
// Get the object
readAIMLSetFromInputStream(fstream, bot);
fstream.close();
}
// else log.info(MagicStrings.sets_path+"/"+setName+".txt not found");
}catch (Exception e){//Catch exception if any
// log.error("Cannot read AIML set '" + setPath + "': " + e, e);
}
}
}

View File

@ -0,0 +1,86 @@
package org.alicebot.ab;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
/**
* Helper class to write some custom AIML
*/
public class AIMLWriter {
//private static final Logger log = LoggerFactory.getLogger(AIMLWriter.class);
public static String[][] relatives = {
// aunt uncle nephew niece grandma grandpa
{"aunt", "her", "who", "aunt"},
{"ant", "her", "who", "aunt"},
{"uncle", "his", "who", "uncle"},
{"friend", "his", "who", "friend"},
{"bestfriend", "his", "who", "bestfriend"},
{"niece", "her", "who", "niece"},
{"nephew", "his", "who", "nephew"},
{"grandmother", "her", "who", "grandmother"},
{"grandma", "her", "who", "grandmother"},
{"grandmom", "her", "who", "grandmother"},
{"mother", "her", "who", "mother"},
{"ma", "her", "who", "mother"},
{"mom", "her", "who", "mother"},
{"momma", "her", "who", "mother"},
{"mum", "her", "who", "mother"},
{"mumma", "her", "who", "mother"},
{"mommy", "her", "who", "mother"},
{"mummy", "her", "who", "mother"},
{"grandfather", "his", "who", "grandfather"},
{"granddad", "his", "who", "grandfather"},
{"father", "his", "who", "father"},
{"dad", "his", "who", "father"},
{"dada", "his", "who", "father"},
{"daddy", "his", "who", "father"},
{"husband", "his", "who", "husband"},
{"hubby", "his", "who", "husband"},
{"wife", "her", "who", "wife"},
{"wifey", "her", "who", "wife"},
{"son", "his", "who", "son"},
{"daughter", "her", "who", "daughter"},
{"brother", "his", "who", "brother"},
{"sister", "her", "who", "sister"},
{"bro", "his", "who", "brother"},
{"sis", "her", "who", "sister"},
{"boyfriend", "his", "who", "boyfriend"},
{"girlfriend", "her", "who", "girlfriend"}};
public static void familiarContactAIML () {
for (int i = 0; i < relatives.length; i++) {
String familiar = relatives[i][0];
String pronoun = relatives[i][1];
String predicate = relatives[i][3];
String aiml =
"<category><pattern>ISFAMILIARNAME "+familiar.toUpperCase()+"</pattern>" +
"<template>true</template></category>\n"+
"<category><pattern>FAMILIARPREDICATE "+familiar.toUpperCase()+"</pattern>" +
"<template>"+predicate +"</template></category>\n"+
"<category><pattern>FAMILIARPRONOUN "+familiar.toUpperCase()+"</pattern>" +
"<template>"+pronoun+"</template></category>\n";
//info(aiml);
}
}
}

View File

@ -0,0 +1,756 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Set;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/**
* Class representing the AIML bot
*/
public class Bot {
//private static final Logger log = LoggerFactory.getLogger(Bot.class);
public final Properties properties = new Properties();
public final PreProcessor preProcessor;
public final Graphmaster brain;
public final Graphmaster inputGraph;
public final Graphmaster learnfGraph;
public final Graphmaster patternGraph;
public final Graphmaster deletedGraph;
public Graphmaster unfinishedGraph;
// public final ArrayList<Category> categories;
public ArrayList<Category> suggestedCategories;
public String name=MagicStrings.unknown_bot_name;
public HashMap<String, AIMLSet> setMap = new HashMap<String, AIMLSet>();
public HashMap<String, AIMLMap> mapMap = new HashMap<String, AIMLMap>();
/**
* Set all directory path variables for this bot
*
* @param root root directory of Program AB
* @param name name of bot
*/
public void setAllPaths (String root, String name) {
MagicStrings.bot_path = root+"/bots";
MagicStrings.bot_name_path = MagicStrings.bot_path+"/"+name;
// org.alicebot.ab
// org.alicebot.ab.cli
// org.alicebot.ab.utils
MagicStrings.aiml_path = MagicStrings.bot_name_path+"/aiml";
MagicStrings.aimlif_path = MagicStrings.bot_name_path+"/aimlif";
MagicStrings.config_path = MagicStrings.bot_name_path+"/config";
MagicStrings.log_path = MagicStrings.bot_name_path+"/logs";
MagicStrings.sets_path = MagicStrings.bot_name_path+"/sets";
MagicStrings.maps_path = MagicStrings.bot_name_path+"/maps";
}
/**
* Constructor (default action, default path, default bot name)
*/
public Bot() {
this(MagicStrings.default_bot);
}
/**
* Constructor (default action, default path)
* @param name
*/
public Bot(String name) {
this(name, MagicStrings.root_path);
}
/**
* Constructor (default action)
*
* @param name
* @param path
*/
public Bot(String name, String path) {
this(name, path, "auto");
}
/**
* Constructor
*
* @param name name of bot
* @param path root path of Program AB
* @param action Program AB action
*/
public Bot(String name, String path, String action) {
this.name = name;
setAllPaths(path, name);
this.brain = new Graphmaster(this);
this.inputGraph = new Graphmaster(this);
this.learnfGraph = new Graphmaster(this);
this.deletedGraph = new Graphmaster(this);
this.patternGraph = new Graphmaster(this);
this.unfinishedGraph = new Graphmaster(this);
// this.categories = new ArrayList<Category>();
this.suggestedCategories = new ArrayList<Category>();
preProcessor = new PreProcessor(this);
addProperties();
addAIMLSets();
addAIMLMaps();
AIMLSet number = new AIMLSet(MagicStrings.natural_number_set_name);
setMap.put(MagicStrings.natural_number_set_name, number);
AIMLMap successor = new AIMLMap(MagicStrings.map_successor);
mapMap.put(MagicStrings.map_successor, successor);
AIMLMap predecessor = new AIMLMap(MagicStrings.map_predecessor);
mapMap.put(MagicStrings.map_predecessor, predecessor);
////info("setMap = "+setMap);
Date aimlDate = new Date(new File(MagicStrings.aiml_path).lastModified());
Date aimlIFDate = new Date(new File(MagicStrings.aimlif_path).lastModified());
//info("AIML modified {} AIMLIF modified {}", aimlDate, aimlIFDate);
readDeletedIFCategories();
readUnfinishedIFCategories();
MagicStrings.pannous_api_key = Utilities.getPannousAPIKey();
MagicStrings.pannous_login = Utilities.getPannousLogin();
if (action.equals("aiml2csv")) addCategoriesFromAIML();
else if (action.equals("csv2aiml")) addCategoriesFromAIMLIF();
else if (aimlDate.after(aimlIFDate)) {
//info("AIML modified after AIMLIF");
addCategoriesFromAIML();
writeAIMLIFFiles();
}
else {
addCategoriesFromAIMLIF();
if (brain.getCategories().size()==0) {
//info("No AIMLIF Files found. Looking for AIML");
addCategoriesFromAIML();
}
}
//info("--> Bot {} {} completed {} deleted {} unfinished",
//name, brain.getCategories().size(), deletedGraph.getCategories().size(), unfinishedGraph.getCategories().size());
}
/**
* add an array list of categories with a specific file name
*
* @param file name of AIML file
* @param moreCategories list of categories
*/
void addMoreCategories (String file, ArrayList<Category> moreCategories) {
if (file.contains(MagicStrings.deleted_aiml_file)) {
for (Category c : moreCategories) {
////info("Delete "+c.getPattern());
deletedGraph.addCategory(c);
}
} else if (file.contains(MagicStrings.unfinished_aiml_file)) {
for (Category c : moreCategories) {
////info("Delete "+c.getPattern());
if (brain.findNode(c) == null)
unfinishedGraph.addCategory(c);
//info("unfinished {} found in brain", c.inputThatTopic());
}
} else if (file.contains(MagicStrings.learnf_aiml_file) ) {
//info("Reading Learnf file");
for (Category c : moreCategories) {
brain.addCategory(c);
learnfGraph.addCategory(c);
patternGraph.addCategory(c);
}
//this.categories.addAll(moreCategories);
} else {
for (Category c : moreCategories) {
////info("Brain size="+brain.root.size());
//brain.printgraph();
brain.addCategory(c);
patternGraph.addCategory(c);
//brain.printgraph();
}
//this.categories.addAll(moreCategories);
}
}
/**
* Load all brain categories from AIML directory
*/
void addCategoriesFromAIML() {
Timer timer = new Timer();
timer.start();
try {
// Directory path here
String file;
File folder = new File(MagicStrings.aiml_path);
if (folder.exists()) {
File[] listOfFiles = folder.listFiles();
//info("Loading AIML files from '{}'", MagicStrings.aiml_path);
for (File listOfFile : listOfFiles) {
if (listOfFile.isFile()) {
file = listOfFile.getName();
if (file.endsWith(".aiml") || file.endsWith(".AIML")) {
//info(file);
try {
ArrayList<Category> moreCategories = AIMLProcessor.AIMLToCategories(MagicStrings.aiml_path, file);
addMoreCategories(file, moreCategories);
} catch (Exception iex) {
//error("Problem loading '" + file +"': " + iex, iex);
}
}
}
}
}
//info("addCategories: '{}' does not exist.", MagicStrings.aiml_path);
} catch (Exception ex) {
ex.printStackTrace();
}
//info("Loaded {} categories in {} sec", brain.getCategories().size(), timer.elapsedTimeSecs());
}
/**
* load all brain categories from AIMLIF directory
*/
void addCategoriesFromAIMLIF() {
Timer timer = new Timer();
timer.start();
try {
// Directory path here
String file;
File folder = new File(MagicStrings.aimlif_path);
if (folder.exists()) {
File[] listOfFiles = folder.listFiles();
//info("Loading AIML files from '{}'", MagicStrings.aimlif_path);
for (File listOfFile : listOfFiles) {
if (listOfFile.isFile()) {
file = listOfFile.getName();
if (file.endsWith(MagicStrings.aimlif_file_suffix) || file.endsWith(MagicStrings.aimlif_file_suffix.toUpperCase())) {
////info(file);
try {
ArrayList<Category> moreCategories = readIFCategories(MagicStrings.aimlif_path + "/" + file);
addMoreCategories(file, moreCategories);
// MemStats.memStats();
} catch (Exception iex) {
//error("Problem loading '" + file + "': " + iex, iex);
}
}
}
}
}
//info("addCategories: '{}' does not exist.", MagicStrings.aimlif_path);
} catch (Exception ex) {
ex.printStackTrace();
}
//info("Loaded {} categories in {} sec", brain.getCategories().size(), timer.elapsedTimeSecs());
}
/**
* read deleted categories from AIMLIF file
*/
public void readDeletedIFCategories() {
readCertainIFCategories(deletedGraph, MagicStrings.deleted_aiml_file);
}
/**
* read unfinished categories from AIMLIF file
*/
public void readUnfinishedIFCategories() {
readCertainIFCategories(unfinishedGraph, MagicStrings.unfinished_aiml_file);
}
/**
* update unfinished categories removing any categories that have been finished
*/
public void updateUnfinishedCategories () {
ArrayList<Category> unfinished = unfinishedGraph.getCategories();
unfinishedGraph = new Graphmaster(this);
for (Category c : unfinished) {
if (!brain.existsCategory(c)) unfinishedGraph.addCategory(c);
}
}
/**
* write all AIML and AIMLIF categories
*/
public void writeQuit() {
writeAIMLIFFiles();
//info("Wrote AIMLIF Files");
writeAIMLFiles();
//info("Wrote AIML Files");
writeDeletedIFCategories();
updateUnfinishedCategories();
writeUnfinishedIFCategories();
}
/**
* read categories from specified AIMLIF file into specified graph
*
* @param graph Graphmaster to store categories
* @param fileName file name of AIMLIF file
*/
public void readCertainIFCategories(Graphmaster graph, String fileName) {
File file = new File(MagicStrings.aimlif_path+"/"+fileName+MagicStrings.aimlif_file_suffix);
if (file.exists()) {
try {
ArrayList<Category> deletedCategories = readIFCategories(MagicStrings.aimlif_path+"/"+fileName+MagicStrings.aimlif_file_suffix);
for (Category d : deletedCategories) graph.addCategory(d);
//info("readCertainIFCategories {} categories from {}", graph.getCategories().size(), fileName+MagicStrings.aimlif_file_suffix);
} catch (Exception iex) {
//error("Problem loading '" + fileName + "': " + iex, iex);
}
}
//info("No "+MagicStrings.deleted_aiml_file+MagicStrings.aimlif_file_suffix+" file found");
}
/**
* write certain specified categories as AIMLIF files
*
* @param graph the Graphmaster containing the categories to write
* @param file the destination AIMLIF file
*/
public void writeCertainIFCategories(Graphmaster graph, String file) {
if (MagicBooleans.trace_mode) //info("writeCertainIFCaegories "+file+" size= "+graph.getCategories().size());
writeIFCategories(graph.getCategories(), file+MagicStrings.aimlif_file_suffix);
File dir = new File(MagicStrings.aimlif_path);
dir.setLastModified(new Date().getTime());
}
/**
* write deleted categories to AIMLIF file
*/
public void writeDeletedIFCategories() {
writeCertainIFCategories(deletedGraph, MagicStrings.deleted_aiml_file);
}
/**
* write learned categories to AIMLIF file
*/
public void writeLearnfIFCategories() {
writeCertainIFCategories(learnfGraph, MagicStrings.learnf_aiml_file);
}
/**
* write unfinished categories to AIMLIF file
*/
public void writeUnfinishedIFCategories() {
writeCertainIFCategories(unfinishedGraph, MagicStrings.unfinished_aiml_file);
}
/**
* write categories to AIMLIF file
*
* @param cats array list of categories
* @param filename AIMLIF filename
*/
public void writeIFCategories (ArrayList<Category> cats, String filename) {
////info("writeIFCategories "+filename);
BufferedWriter bw = null;
File existsPath = new File(MagicStrings.aimlif_path);
if (existsPath.exists())
try {
//Construct the bw object
bw = new BufferedWriter(new FileWriter(MagicStrings.aimlif_path+"/"+filename)) ;
for (Category category : cats) {
bw.write(Category.categoryToIF(category));
bw.newLine();
}
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
//Close the bw
try {
if (bw != null) {
bw.flush();
bw.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
/**
* Write all AIMLIF files from bot brain
*/
public void writeAIMLIFFiles () {
//info("writeAIMLIFFiles");
HashMap<String, BufferedWriter> fileMap = new HashMap<String, BufferedWriter>();
if (deletedGraph.getCategories().size() > 0) writeDeletedIFCategories();
ArrayList<Category> brainCategories = brain.getCategories();
Collections.sort(brainCategories, Category.CATEGORY_NUMBER_COMPARATOR);
for (Category c : brainCategories) {
try {
BufferedWriter bw;
String fileName = c.getFilename();
if (fileMap.containsKey(fileName)) bw = fileMap.get(fileName);
else {
bw = new BufferedWriter(new FileWriter(MagicStrings.aimlif_path+"/"+fileName+MagicStrings.aimlif_file_suffix));
fileMap.put(fileName, bw);
}
bw.write(Category.categoryToIF(c));
bw.newLine();
} catch (Exception ex) {
ex.printStackTrace();
}
}
Set set = fileMap.keySet();
for (Object aSet : set) {
BufferedWriter bw = fileMap.get(aSet);
//Close the bw
try {
if (bw != null) {
bw.flush();
bw.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
File dir = new File(MagicStrings.aimlif_path);
dir.setLastModified(new Date().getTime());
}
/**
* Write all AIML files. Adds categories for BUILD and DEVELOPMENT ENVIRONMENT
*/
public void writeAIMLFiles () {
HashMap<String, BufferedWriter> fileMap = new HashMap<String, BufferedWriter>();
Category b = new Category(0, "BUILD", "*", "*", new Date().toString(), "update.aiml");
brain.addCategory(b);
b = new Category(0, "DELEVLOPMENT ENVIRONMENT", "*", "*", MagicStrings.programNameVersion, "update.aiml");
brain.addCategory(b);
ArrayList<Category> brainCategories = brain.getCategories();
Collections.sort(brainCategories, Category.CATEGORY_NUMBER_COMPARATOR);
for (Category c : brainCategories) {
if (!c.getFilename().equals(MagicStrings.null_aiml_file))
try {
////info("Writing "+c.getCategoryNumber()+" "+c.inputThatTopic());
BufferedWriter bw;
String fileName = c.getFilename();
if (fileMap.containsKey(fileName)) bw = fileMap.get(fileName);
else {
String copyright = Utilities.getCopyright(this, fileName);
bw = new BufferedWriter(new FileWriter(MagicStrings.aiml_path+"/"+fileName));
fileMap.put(fileName, bw);
bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n" +
"<aiml>\n");
bw.write(copyright);
//bw.newLine();
}
bw.write(Category.categoryToAIML(c)+"\n");
//bw.newLine();
} catch (Exception ex) {
ex.printStackTrace();
}
}
Set set = fileMap.keySet();
for (Object aSet : set) {
BufferedWriter bw = fileMap.get(aSet);
//Close the bw
try {
if (bw != null) {
bw.write("</aiml>\n");
bw.flush();
bw.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
File dir = new File(MagicStrings.aiml_path);
dir.setLastModified(new Date().getTime());
}
/**
* load bot properties
*/
void addProperties() {
try {
properties.getProperties(MagicStrings.config_path+"/properties.txt");
} catch (Exception ex) {
ex.printStackTrace();
}
}
static int leafPatternCnt = 0;
static int starPatternCnt = 0;
/** find suggested patterns in a graph of inputs
*
*/
public void findPatterns() {
findPatterns(inputGraph.root, "");
//info("{} Leaf Patterns {} Star Patterns", leafPatternCnt, starPatternCnt);
}
/** find patterns recursively
*
* @param node current graph node
* @param partialPatternThatTopic partial pattern path
*/
void findPatterns(Nodemapper node, String partialPatternThatTopic) {
if (NodemapperOperator.isLeaf(node)) {
////info("LEAF: "+node.category.getActivationCnt()+". "+partialPatternThatTopic);
if (node.category.getActivationCnt() > MagicNumbers.node_activation_cnt) {
////info("LEAF: "+node.category.getActivationCnt()+". "+partialPatternThatTopic+" "+node.shortCut); //Start writing to the output stream
leafPatternCnt ++;
try {
String categoryPatternThatTopic = "";
if (node.shortCut) {
////info("Partial patternThatTopic = "+partialPatternThatTopic);
categoryPatternThatTopic = partialPatternThatTopic + " <THAT> * <TOPIC> *";
}
else categoryPatternThatTopic = partialPatternThatTopic;
Category c = new Category(0, categoryPatternThatTopic, MagicStrings.blank_template, MagicStrings.unknown_aiml_file);
//if (brain.existsCategory(c)) //info(c.inputThatTopic()+" Exists");
//if (deleted.existsCategory(c)) //info(c.inputThatTopic()+ " Deleted");
if (!brain.existsCategory(c) && !deletedGraph.existsCategory(c) && !unfinishedGraph.existsCategory(c)) {
patternGraph.addCategory(c);
suggestedCategories.add(c);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
if(NodemapperOperator.size(node) > MagicNumbers.node_size) {
////info("STAR: "+NodemapperOperator.size(node)+". "+partialPatternThatTopic+" * <that> * <topic> *");
starPatternCnt ++;
try {
Category c = new Category(0, partialPatternThatTopic+" * <THAT> * <TOPIC> *", MagicStrings.blank_template, MagicStrings.unknown_aiml_file);
//if (brain.existsCategory(c)) //info(c.inputThatTopic()+" Exists");
//if (deleted.existsCategory(c)) //info(c.inputThatTopic()+ " Deleted");
if (!brain.existsCategory(c) && !deletedGraph.existsCategory(c) && !unfinishedGraph.existsCategory(c)) {
patternGraph.addCategory(c);
suggestedCategories.add(c);
}
} catch (Exception e) {
e.printStackTrace();
}
}
for (String key : NodemapperOperator.keySet(node)) {
Nodemapper value = NodemapperOperator.get(node, key);
findPatterns(value, partialPatternThatTopic + " " + key);
}
}
/** classify inputs into matching categories
*
* @param filename file containing sample normalized inputs
*/
public void classifyInputs (String filename) {
try{
FileInputStream fstream = new FileInputStream(filename);
// Get the object
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
//Read File Line By Line
int count = 0;
while ((strLine = br.readLine())!= null) {
// Print the content on the console
////info("Classifying "+strLine);
if (strLine.startsWith("Human: ")) strLine = strLine.substring("Human: ".length(), strLine.length());
Nodemapper match = patternGraph.match(strLine, "unknown", "unknown");
match.category.incrementActivationCnt();
count += 1;
}
//Close the input stream
br.close();
} catch (Exception e){//Catch exception if any
//error("Cannot classify inputs from '" + filename + "': " + e, e);
}
}
/** read sample inputs from filename, turn them into Paths, and
* add them to the graph.
*
* @param filename file containing sample inputs
*/
public void graphInputs (String filename) {
try{
// Open the file that is the first
// command line parameter
FileInputStream fstream = new FileInputStream(filename);
// Get the object
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
//strLine = preProcessor.normalize(strLine);
Category c = new Category(0, strLine, "*", "*", "nothing", MagicStrings.unknown_aiml_file);
Nodemapper node = inputGraph.findNode(c);
if (node == null) {
inputGraph.addCategory(c);
c.incrementActivationCnt();
}
else node.category.incrementActivationCnt();
////info("Root branches="+g.root.size());
}
//Close the input stream
br.close();
}catch (Exception e){//Catch exception if any
//error("Cannot graph inputs from '" + filename + "': " + e, e);
}
}
/**
* read AIMLIF categories from a file into bot brain
*
* @param filename name of AIMLIF file
* @return array list of categories read
*/
public ArrayList<Category> readIFCategories (String filename) {
ArrayList<Category> categories = new ArrayList<Category>();
try{
// Open the file that is the first
// command line parameter
FileInputStream fstream = new FileInputStream(filename);
// Get the object
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
try {
Category c = Category.IFToCategory(strLine);
categories.add(c);
} catch (Exception ex) {
//warn("Invalid AIMLIF in "+filename+" line "+strLine, ex);
}
}
//Close the input stream
br.close();
}catch (Exception e){//Catch exception if any
//error("Cannot read IF Categories from '" + filename + "': " + e, e);
}
return categories;
}
/**
* check Graphmaster for shadowed categories
*/
public void shadowChecker () {
shadowChecker(brain.root) ;
}
/** traverse graph and test all categories found in leaf nodes for shadows
*
* @param node
*/
void shadowChecker(Nodemapper node) {
if (NodemapperOperator.isLeaf(node)) {
String input = node.category.getPattern().replace("*", "XXX").replace("_", "XXX");
String that = node.category.getThat().replace("*", "XXX").replace("_", "XXX");
String topic = node.category.getTopic().replace("*", "XXX").replace("_", "XXX");
Nodemapper match = brain.match(input, that, topic);
if (match != node) {
//info(Graphmaster.inputThatTopic(input, that, topic));
//info("MATCHED: {}", match.category.inputThatTopic());
//info("SHOULD MATCH: {}", node.category.inputThatTopic());
}
}
else {
for (String key : NodemapperOperator.keySet(node)) {
shadowChecker(NodemapperOperator.get(node, key));
}
}
}
/**
* Load all AIML Sets
*/
void addAIMLSets() {
Timer timer = new Timer();
timer.start();
try {
// Directory path here
String file;
File folder = new File(MagicStrings.sets_path);
if (folder.exists()) {
File[] listOfFiles = folder.listFiles();
//info("Loading AIML Sets files from '{}'", MagicStrings.sets_path);
for (File listOfFile : listOfFiles) {
if (listOfFile.isFile()) {
file = listOfFile.getName();
if (file.endsWith(".txt") || file.endsWith(".TXT")) {
//info(file);
String setName = file.substring(0, file.length()-".txt".length());
//info("Read AIML Set {}", setName);
AIMLSet aimlSet = new AIMLSet(setName);
aimlSet.readAIMLSet(this);
setMap.put(setName, aimlSet);
}
}
}
}
//info("addAIMLSets: {} does not exist.", MagicStrings.sets_path);
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* Load all AIML Maps
*/
void addAIMLMaps() {
Timer timer = new Timer();
timer.start();
try {
// Directory path here
String file;
File folder = new File(MagicStrings.maps_path);
if (folder.exists()) {
File[] listOfFiles = folder.listFiles();
//info("Loading AIML Map files from '{}'", MagicStrings.maps_path);
for (File listOfFile : listOfFiles) {
if (listOfFile.isFile()) {
file = listOfFile.getName();
if (file.endsWith(".txt") || file.endsWith(".TXT")) {
//info(file);
String mapName = file.substring(0, file.length()-".txt".length());
//info("Read AIML Map "+mapName);
AIMLMap aimlMap = new AIMLMap(mapName);
aimlMap.readAIMLMap(this);
mapMap.put(mapName, aimlMap);
}
}
}
}
//info("addCategories: '{}' does not exist.", MagicStrings.aiml_path);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

View File

@ -0,0 +1,392 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.util.Comparator;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/**
* structure representing an AIML category and operations on Category
*/
public class Category {
//private static final Logger log = LoggerFactory.getLogger(Category.class);
private String pattern;
private String that;
private String topic;
private String template;
private String filename;
private int activationCnt;
private final int categoryNumber; // for loading order
public static int categoryCnt = 0;
private AIMLSet matches;
/**
* Return a set of inputs matching the category
*
* @return and AIML Set of elements matching this category
*/
public AIMLSet getMatches() {
if (matches != null)
return matches;
else return new AIMLSet("No Matches");
}
/**
* number of times a category was activated by inputs
*
* @return integer number of activations
*/
public int getActivationCnt () {
return activationCnt;
}
/**
* get the index number of this category
*
* @return unique integer identifying this category
*/
public int getCategoryNumber () {
return categoryNumber;
}
/**
* get category pattern
*
* @return pattern
*/
public String getPattern () {
if (pattern == null) return "*";
else return pattern;
}
/**
* get category that pattern
*
* @return that pattern
*/
public String getThat () {
if (that == null) return "*";
else return that;
}
/**
* get category topic pattern
*
* @return topic pattern
*/
public String getTopic () {
if (topic == null) return "*";
else return topic;
}
/**
* get category template
*
* @return template
*/
public String getTemplate () {
if (template==null) return "";
else
return template;
}
/**
* get name of AIML file for this category
*
* @return file name
*/
public String getFilename () {
if (filename==null) return MagicStrings.unknown_aiml_file;
else
return filename;
}
/**
* increment the category activation count
*/
public void incrementActivationCnt() {
activationCnt++;
}
/** set category activation count
*
* @param cnt activation count
*/
public void setActivationCnt(int cnt) {
activationCnt = cnt;
}
/**
* set category filename
* @param filename name of AIML file
*/
public void setFilename(String filename) {
this.filename = filename;
}
/**
* set category template
* @param template AIML template
*/
public void setTemplate(String template) {
this.template = template;
}
/**
* set category pattern
*
* @param pattern AIML pattern
*/
public void setPattern(String pattern) {
this.pattern = pattern;
}
/**
* set category that pattern
*
* @param that AIML that pattern
*/
public void setThat(String that) {
this.that = that;
}
/**
* set category topic
*
* @param topic AIML topic pattern
*/
public void setTopic(String topic) {
this.topic = topic;
}
/**
* return a string represeting the full pattern path as "{@code input pattern <THAT> that pattern <TOPIC> topic pattern}"
* @return
*/
public String inputThatTopic() {
return Graphmaster.inputThatTopic(pattern, that, topic);
}
/**
* add a matching input to the matching input set
*
* @param input matching input
*/
public void addMatch (String input) {
if (matches == null) {
String setName = this.inputThatTopic().replace("*", "STAR").replace("_", "UNDERSCORE").replace(" ","-").replace("<THAT>","THAT").replace("<TOPIC>","TOPIC");
// log.info("Created match set "+setName);
matches = new AIMLSet(setName);
}
matches.add(input);
}
/**
* convert a template to a single-line representation by replacing "," with #Comma and newline with #Newline
* @param template original template
* @return template on a single line of text
*/
public static String templateToLine (String template) {
String result = template;
result = result.replaceAll("(\r\n|\n\r|\r|\n)", "\\#Newline");
result = result.replaceAll(MagicStrings.aimlif_split_char, MagicStrings.aimlif_split_char_name);
return result;
}
/**
* restore a template to its original form by replacing #Comma with "," and #Newline with newline.
* @param line template on a single line of text
* @return original multi-line template
*/
private static String lineToTemplate(String line) {
String result = line.replaceAll("\\#Newline","\n");
result = result.replaceAll(MagicStrings.aimlif_split_char_name, MagicStrings.aimlif_split_char);
return result;
}
/**
* convert a category from AIMLIF format to a Category object
*
* @param IF Category in AIMLIF format
* @return Category object
*/
public static Category IFToCategory(String IF) {
String[] split = IF.split(MagicStrings.aimlif_split_char);
//log.info("Read: "+split);
return new Category(Integer.parseInt(split[0]), split[1], split[2], split[3], lineToTemplate(split[4]), split[5]);
}
/**
* convert a Category object to AIMLIF format
* @param category Category object
* @return category in AIML format
*/
public static String categoryToIF(Category category) {
//log.info("categoryToIF: template="+templateToLine(category.getTemplate()));
String c = MagicStrings.aimlif_split_char;
return category.getActivationCnt()+c+category.getPattern()+c+category.getThat()+c+category.getTopic()+c+templateToLine(category.getTemplate())+c+category.getFilename();
}
/**
* convert a Category object to AIML syntax
*
* @param category Category object
* @return AIML Category
*/
public static String categoryToAIML(Category category) {
String topicStart = ""; String topicEnd = "";
String thatStatement = "";
String result = "";
String pattern = category.getPattern();
String[] splitPattern = pattern.split(" ");
for (String w : splitPattern) {
if (w.startsWith("<TYPE>")) w = w.toLowerCase();
pattern = pattern+" "+w;
}
pattern = pattern.trim();
// if (pattern.contains("type")) log.info("Rebuilt pattern "+pattern);
String NL = System.getProperty("line.separator");
NL = "\n";
try {
if (!category.getTopic().equals("*")) { topicStart = "<topic name=\""+category.getTopic()+"\">"+NL; topicEnd = "</topic>"+NL;}
if (!category.getThat().equals("*")) { thatStatement = "<that>"+category.getThat()+"</that>";}
result = topicStart+"<category><pattern>"+category.getPattern()+"</pattern>"+thatStatement+NL+
"<template>"+category.getTemplate()+"</template>"+NL+
"</category>"+topicEnd;
} catch (Exception ex) {
ex.printStackTrace();
}
return result;
}
/**
* check to see if a pattern expression is valid in AIML 2.0
*
* @param pattern pattern expression
* @return true or false
*/
public boolean validPatternForm(String pattern) {
if (pattern.length() < 1) {validationMessage += "Zero length. "; return false; }
String[] words = pattern.split(" ");
for (int i = 0; i < words.length; i++) {
//String word = words[i];
/*if (!(word.matches("[\\p{Hiragana}\\p{Katakana}\\p{Han}\\p{Latin}]*+") || word.equals("*") || word.equals("_"))) {
log.info("Invalid pattern word "+word);
return false;
}*/
}
return true;
}
public String validationMessage="";
/**
* check for valid Category format
*
* @return true or false
*/
public boolean validate () {
validationMessage = "";
if (!validPatternForm(pattern)) {validationMessage += "Badly formatted <pattern>"; return false;}
if (!validPatternForm(that)) {validationMessage += "Badly formatted <that>"; return false;}
if (!validPatternForm(topic)) {validationMessage += "Badly formatted <topic>"; return false;}
if (!AIMLProcessor.validTemplate(template)) {validationMessage += "Badly formatted <template>"; return false;}
if (!filename.endsWith(".aiml")) {validationMessage += "Filename suffix should be .aiml"; return false;}
return true;
}
/**
* Constructor
*
* @param activationCnt category activation count
* @param pattern input pattern
* @param that that pattern
* @param topic topic pattern
* @param template AIML template
* @param filename AIML file name
*/
public Category (int activationCnt, String pattern, String that, String topic, String template, String filename){
if (MagicBooleans.fix_excel_csv) {
pattern = Utilities.fixCSV(pattern);
that = Utilities.fixCSV(that);
topic = Utilities.fixCSV(topic);
template = Utilities.fixCSV(template);
filename = Utilities.fixCSV(filename);
}
this.pattern = pattern.trim().toUpperCase();
this.that = that.trim().toUpperCase();
this.topic = topic.trim().toUpperCase();
this.template = template.replace("& ", " and "); // XML parser treats & badly
this.filename = filename;
this.activationCnt = activationCnt;
matches = null;
this.categoryNumber = categoryCnt++;
// in Android, even this is too much for trace:
//log.trace("Creating {} {}", categoryNumber, inputThatTopic());
}
/**
* Constructor
*
* @param activationCnt category activation count
* @param patternThatTopic string representing Pattern Path
* @param template AIML template
* @param filename AIML category
*/
public Category(int activationCnt, String patternThatTopic, String template, String filename){
this(activationCnt,
patternThatTopic.substring(0, patternThatTopic.indexOf("<THAT>")),
patternThatTopic.substring(patternThatTopic.indexOf("<THAT>")+"<THAT>".length(), patternThatTopic.indexOf("<TOPIC>")),
patternThatTopic.substring(patternThatTopic.indexOf("<TOPIC>")+"<TOPIC>".length(), patternThatTopic.length()), template, filename);
}
/**
* compare two categories for sorting purposes based on activation count
*/
public static Comparator<Category> ACTIVATION_COMPARATOR = new Comparator<Category>()
{
@Override
public int compare(Category c1, Category c2)
{
return c2.getActivationCnt() - c1.getActivationCnt();
}
};
/**
* compare two categories for sorting purposes based on alphabetical order of patterns
*/
public static Comparator<Category> PATTERN_COMPARATOR = new Comparator<Category>()
{
@Override
public int compare(Category c1, Category c2)
{
return String.CASE_INSENSITIVE_ORDER.compare(c1.inputThatTopic(), c2.inputThatTopic());
}
};
/**
* compare two categories for sorting purposes based on category index number
*/
public static Comparator<Category> CATEGORY_NUMBER_COMPARATOR = new Comparator<Category>()
{
@Override
public int compare(Category c1, Category c2)
{
return c1.getCategoryNumber() - c2.getCategoryNumber();
}
};
}

View File

@ -0,0 +1,190 @@
package org.alicebot.ab;
import java.io.BufferedWriter;
import java.io.FileWriter;
import org.alicebot.ab.utils.IOUtils;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
/**
* Class encapsulating a chat session between a bot and a client
*/
public class Chat {
//private static final Logger log = LoggerFactory.getLogger(Chat.class);
public Bot bot;
public String customerId = MagicStrings.unknown_customer_id;
public History<History> thatHistory= new History<History>("that");
public History<String> requestHistory=new History<String>("request");
public History<String> responseHistory=new History<String>("response");
public History<String> inputHistory=new History<String>("input");
public Predicates predicates = new Predicates();
public static String matchTrace = "";
public static boolean locationKnown = false;
public static String longitude;
public static String latitude;
/**
* Constructor (defualt customer ID)
*
* @param bot the bot to chat with
*/
public Chat(Bot bot) {
this(bot, "0");
}
/**
* Constructor
* @param bot bot to chat with
* @param customerId unique customer identifier
*/
public Chat(Bot bot, String customerId) {
this.customerId = customerId;
this.bot = bot;
History<String> contextThatHistory = new History<String>();
contextThatHistory.add(MagicStrings.default_that);
thatHistory.add(contextThatHistory);
addPredicates();
predicates.put("topic", MagicStrings.default_topic);
}
/**
* Load all predicate defaults
*/
void addPredicates() {
try {
predicates.getPredicateDefaults(MagicStrings.config_path+"/predicates.txt") ;
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* Chat session terminal interaction
*/
public void chat () {
BufferedWriter bw = null;
String logFile = MagicStrings.log_path+"/log_"+customerId+".txt";
try {
//Construct the bw object
bw = new BufferedWriter(new FileWriter(logFile, true)) ;
String request="SET PREDICATES";
String response = multisentenceRespond(request);
while (!request.equals("quit")) {
System.out.print("Human: ");
request = IOUtils.readInputTextLine();
response = multisentenceRespond(request);
//info("Robot: "+response);
bw.write("Human: "+request);
bw.newLine();
bw.write("Robot: "+response);
bw.newLine();
bw.flush();
}
bw.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* Return bot response to a single sentence input given conversation context
*
* @param input client input
* @param that bot's last sentence
* @param topic current topic
* @param contextThatHistory history of "that" values for this request/response interaction
* @return bot's reply
*/
String respond(String input, String that, String topic, History contextThatHistory) {
String response;
inputHistory.add(input);
response = AIMLProcessor.respond(input, that, topic, this);
String normResponse = bot.preProcessor.normalize(response);
// normResponse = JapaneseTokenizer.morphSentence(normResponse); //response.trim(); //
String sentences[] = bot.preProcessor.sentenceSplit(normResponse);
for (int i = 0; i < sentences.length; i++) {
that = sentences[i];
////info("That "+i+" '"+that+"'");
if (that.trim().equals("")) that = MagicStrings.default_that;
contextThatHistory.add(that);
}
return response.trim()+" ";
}
/**
* Return bot response given an input and a history of "that" for the current conversational interaction
*
* @param input client input
* @param contextThatHistory history of "that" values for this request/response interaction
* @return bot's reply
*/
String respond(String input, History<String> contextThatHistory) {
History hist = thatHistory.get(0);
String that;
if (hist == null) that = MagicStrings.default_that;
else that = hist.getString(0);
return respond(input, that, predicates.get("topic"), contextThatHistory);
}
/**
* return a compound response to a multiple-sentence request. "Multiple" means one or more.
*
* @param request client's multiple-sentence input
* @return
*/
public String multisentenceRespond(String request) {
String response="";
matchTrace="";
/*thatHistory.printHistory();
inputHistory.printHistory();
requestHistory.printHistory();
responseHistory.printHistory();*/
try {
String norm = bot.preProcessor.normalize(request);
// norm = JapaneseTokenizer.morphSentence(norm);
//debug("normalized = "+norm);
String sentences[] = bot.preProcessor.sentenceSplit(norm);
History<String> contextThatHistory = new History<String>("contextThat");
for (int i = 0; i < sentences.length; i++) {
////info("Human: "+sentences[i]);
AIMLProcessor.trace_count = 0;
String reply = respond(sentences[i], contextThatHistory);
response += " "+reply;
////info("Robot: "+reply);
}
requestHistory.add(request);
responseHistory.add(response);
thatHistory.add(contextThatHistory);
//if (MagicBooleans.trace_mode) //info(matchTrace);
} catch (Exception ex) {
ex.printStackTrace();
return MagicStrings.error_bot_response;
}
bot.writeLearnfIFCategories();
return response.trim();
}
public static void setMatchTrace(String newMatchTrace) {
matchTrace = newMatchTrace;
}
}

View File

@ -0,0 +1,114 @@
package org.alicebot.ab;
import java.util.HashMap;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/**
* This class is here to simulate a Contacts database for the purpose of testing contactaction.aiml
*/
public class Contact {
//private static final Logger log = LoggerFactory.getLogger(Contact.class);
public static int contactCount=0;
public static HashMap<String, Contact> idContactMap = new HashMap<String, Contact>();
public static HashMap<String, String> nameIdMap = new HashMap<String, String>();
public String contactId;
public String displayName;
public String birthday;
public HashMap<String, String> phones;
public HashMap<String, String> emails;
public static String multipleIds(String contactName) {
String patternString = " ("+contactName.toUpperCase()+") ";
while (patternString.contains(" ")) patternString = patternString.replace(" ", "(.*)");
////info("Pattern='"+patternString+"'");
Pattern pattern = Pattern.compile(patternString);
Set<String> keys = nameIdMap.keySet();
String result="";
int idCount = 0;
for (String key : keys) {
Matcher m = pattern.matcher(key);
if (m.find()) {
result += nameIdMap.get(key.toUpperCase())+" ";
idCount++;
}
}
if (idCount <= 1) result = "false";
return result.trim();
}
public static String contactId(String contactName) {
String patternString = " "+contactName.toUpperCase()+" ";
while (patternString.contains(" ")) patternString = patternString.replace(" ", ".*");
////info("Pattern='"+patternString+"'");
Pattern pattern = Pattern.compile(patternString);
Set<String> keys = nameIdMap.keySet();
String result="unknown";
for (String key: keys) {
Matcher m = pattern.matcher(key);
if (m.find()) result = nameIdMap.get(key.toUpperCase())+" ";
}
return result.trim();
}
public static String displayName(String id) {
Contact c = idContactMap.get(id.toUpperCase());
String result = "unknown";
if (c != null) {
result = c.displayName;
}
return result;
}
public static String dialNumber(String type, String id) {
String result = "unknown";
Contact c = idContactMap.get(id.toUpperCase());
if (c != null) {
String dialNumber = c.phones.get(type.toUpperCase());
if (dialNumber != null) result = dialNumber;
}
return result;
}
public static String emailAddress(String type, String id) {
String result = "unknown";
Contact c = idContactMap.get(id.toUpperCase());
if (c != null) {
String emailAddress = c.emails.get(type.toUpperCase());
if (emailAddress != null) result = emailAddress;
}
return result;
}
public static String birthday(String id) {
Contact c = idContactMap.get(id.toUpperCase());
if (c == null) return "unknown";
else return c.birthday;
}
public Contact (String displayName, String phoneType, String dialNumber, String emailType, String emailAddress, String birthday) {
contactId = "ID"+contactCount;
contactCount++;
phones = new HashMap<String, String>();
emails = new HashMap<String, String>();
idContactMap.put(contactId.toUpperCase(), this);
addPhone(phoneType, dialNumber);
addEmail(emailType, emailAddress);
addName(displayName);
addBirthday(birthday);
}
public void addPhone(String type, String dialNumber) {
phones.put(type.toUpperCase(), dialNumber);
}
public void addEmail(String type, String emailAddress) {
emails.put(type.toUpperCase(), emailAddress);
}
public void addName (String name) {
displayName = name;
nameIdMap.put(displayName.toUpperCase(), contactId);
////info(nameIdMap.toString());
}
public void addBirthday(String birthday) {
this.birthday = birthday;
}
}

View File

@ -0,0 +1,605 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.util.ArrayList;
import java.util.HashSet;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/**
* The AIML Pattern matching algorithm and data structure.
*
*/
public class Graphmaster {
//private static final Logger log = LoggerFactory.getLogger(Graphmaster.class);
public Bot bot;
public final Nodemapper root;
public int matchCount = 0;
public int upgradeCnt = 0;
public HashSet<String> vocabulary;
public String resultNote = "";
public int categoryCnt = 0;
public static boolean enableShortCuts = false;
/**
* Constructor
*
* @param bot the bot the graph belongs to.
*/
public Graphmaster (Bot bot) {
root = new Nodemapper();
this.bot = bot;
vocabulary = new HashSet<String>();
}
/**
* Convert input, that and topic to a single sentence having the form
* {@code input <THAT> that <TOPIC> topic}
*
* @param input input (or input pattern)
* @param that that (or that pattern)
* @param topic topic (or topic pattern)
* @return
*/
public static String inputThatTopic (String input, String that, String topic) {
return input.trim()+" <THAT> "+that.trim()+" <TOPIC> "+topic.trim();
}
/**
* add an AIML category to this graph.
*
* @param category AIML Category
*/
public void addCategory (Category category) {
Path p = Path.sentenceToPath(inputThatTopic(category.getPattern(), category.getThat(), category.getTopic()));
addPath(p, category);
categoryCnt++;
}
boolean thatStarTopicStar(Path path) {
String tail = Path.pathToSentence(path).trim();
//log.info("thatStarTopicStar "+tail+" "+tail.equals("<THAT> * <TOPIC> *"));
return tail.equals("<THAT> * <TOPIC> *");
}
void addSets (String type, Bot bot, Nodemapper node) {
//log.info("adding Set "+type+" from "+bot.setMap);
String typeName = Utilities.tagTrim(type, "SET").toLowerCase();
//AIMLSet aimlSet;
if (bot.setMap.containsKey(typeName)) {
if (node.sets == null) node.sets = new ArrayList<String>();
node.sets.add(typeName);
// log.info("sets = "+node.sets);
}
else {
}
}
/**
* add a path to the graph from the root to a Category
*
* @param path Pattern path
* @param category AIML category
*/
void addPath(Path path, Category category) {
addPath(root, path, category);
}
/**
* add a Path to the graph from a given node.
* Shortcuts: Replace all instances of paths "<THAT> * <TOPIC> *" with a direct link to the matching category
*
* @param node starting node in graph
* @param path Pattern path to be added
* @param category AIML Category
*/
void addPath(Nodemapper node, Path path, Category category) {
if (path == null) {
node.category = category;
node.height = 0;
}
else if (enableShortCuts && thatStarTopicStar(path)) {
node.category = category;
node.height = Math.min(4, node.height);
node.shortCut = true;
}
else if (NodemapperOperator.containsKey(node, path.word)) {
if (path.word.startsWith("<SET>")) addSets(path.word, bot, node);
Nodemapper nextNode = NodemapperOperator.get(node, path.word);
addPath(nextNode, path.next, category);
int offset = 1;
if (path.word.equals("#") || path.word.equals("^")) offset = 0;
node.height = Math.min(offset + nextNode.height, node.height);
}
else {
Nodemapper nextNode = new Nodemapper();
if (path.word.startsWith("<SET>")) {
addSets(path.word, bot, node);
}
if (node.key != null) {
NodemapperOperator.upgrade(node);
upgradeCnt++;
}
NodemapperOperator.put(node, path.word, nextNode);
addPath(nextNode, path.next, category);
int offset = 1;
if (path.word.equals("#") || path.word.equals("^")) offset = 0;
node.height = Math.min(offset + nextNode.height, node.height);
}
}
/**
* test if category is already in graph
*
* @return true or false
*/
public boolean existsCategory(Category c) {
return (findNode(c) != null);
}
/**
* test if category is already in graph
*
* @return true or false
*/
public Nodemapper findNode(Category c) {
return findNode(c.getPattern(), c.getThat(), c.getTopic());
}
/** Given an input pattern, that pattern and topic pattern, find the leaf node associated with this path.
*
* @param input input pattern
* @param that that pattern
* @param topic topic pattern
* @return leaf node or null if no matching node is found
*/
public Nodemapper findNode(String input, String that, String topic) {
Nodemapper result = findNode(root, Path.sentenceToPath(inputThatTopic(input, that, topic)));
if (verbose) ;
return result;
}
public static boolean verbose = false;
/**
* Recursively find a leaf node given a starting node and a path.
*
* @param node string node
* @param path string path
* @return the leaf node or null if no leaf is found
*/
Nodemapper findNode(Nodemapper node, Path path) {
if (path == null && node != null) {
if (verbose) ;
return node;
}
else if (Path.pathToSentence(path).trim().equals("<THAT> * <TOPIC> *") && node.shortCut && path.word.equals("<THAT>")) {
if (verbose);
return node;
}
else if (NodemapperOperator.containsKey(node, path.word)) {
if (verbose) ;
Nodemapper nextNode = NodemapperOperator.get(node, path.word.toUpperCase());
return findNode(nextNode, path.next);
}
else {
if (verbose) ;
return null;
}
}
/**
* Find the matching leaf node given an input, that state and topic value
*
* @param input client input
* @param that bot's last sentence
* @param topic current topic
* @return matching leaf node or null if no match is found
*/
public final Nodemapper match(String input, String that, String topic) {
Nodemapper n = null;
try {
String inputThatTopic = inputThatTopic(input, that, topic);
//log.info("Matching: "+inputThatTopic);
Path p = Path.sentenceToPath(inputThatTopic);
//p.print();
n = match(p, inputThatTopic);
if (MagicBooleans.trace_mode) {
if (n != null) {
//log.debug("Matched: "+n.category.inputThatTopic()+" "+n.category.getFilename());
}
else ;
}
} catch (Exception ex) {
//log.info("Match: "+input);
ex.printStackTrace();
n = null;
}
if (MagicBooleans.trace_mode && Chat.matchTrace.length() < MagicNumbers.max_trace_length) {
if (n != null) {
Chat.setMatchTrace(Chat.matchTrace + n.category.inputThatTopic()+"\n");
}
}
return n;
}
/**
* Find the matching leaf node given a path of the form "{@code input <THAT> that <TOPIC> topic}"
* @param path
* @param inputThatTopic
* @return matching leaf node or null if no match is found
*/
final Nodemapper match(Path path, String inputThatTopic) {
try {
String[] inputStars = new String[MagicNumbers.max_stars];
String[] thatStars = new String[MagicNumbers.max_stars];
String[] topicStars = new String[MagicNumbers.max_stars];
String starState = "inputStar";
String matchTrace = "";
Nodemapper n = match(path, root, inputThatTopic, starState, 0, inputStars, thatStars, topicStars, matchTrace);
if (n != null) {
StarBindings sb = new StarBindings();
for (int i=0; inputStars[i] != null && i < MagicNumbers.max_stars; i++) sb.inputStars.add(inputStars[i]);
for (int i=0; thatStars[i] != null && i < MagicNumbers.max_stars; i++) sb.thatStars.add(thatStars[i]);
for (int i=0; topicStars[i] != null && i < MagicNumbers.max_stars; i++) sb.topicStars.add(topicStars[i]);
n.starBindings = sb;
}
//if (!n.category.getPattern().contains("*")) log.info("adding match "+inputThatTopic);
if (n != null) n.category.addMatch(inputThatTopic);
return n;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/**
* Depth-first search of the graph for a matching leaf node.
* At each node, the order of search is
* 1. $WORD (high priority exact word match)
* 2. # wildcard (zero or more word match)
* 3. _ wildcard (one or more words match)
* 4. WORD (exact word match)
* 5. {@code <set></set>} (AIML Set match)
* 6. shortcut (graph shortcut when that pattern = * and topic pattern = *)
* 7. ^ wildcard (zero or more words match)
* 8. * wildcard (one or more words match)
*
* @param path remaining path to be matched
* @param node current search node
* @param inputThatTopic original input, that and topic string
* @param starState tells whether wildcards are in input pattern, that pattern or topic pattern
* @param starIndex index of wildcard
* @param inputStars array of input pattern wildcard matches
* @param thatStars array of that pattern wildcard matches
* @param topicStars array of topic pattern wildcard matches
* @param matchTrace trace of match path for debugging purposes
* @return matching leaf node or null if no match is found
*/
final Nodemapper match(Path path, Nodemapper node, String inputThatTopic, String starState, int starIndex, String[] inputStars, String[] thatStars, String[] topicStars, String matchTrace) {
Nodemapper matchedNode;
//log.info("Match: Height="+node.height+" Length="+path.length+" Path="+Path.pathToSentence(path));
matchCount++;
if ((matchedNode = nullMatch(path, node, matchTrace)) != null) return matchedNode;
else if (path.length < node.height) {
return null;}
else if ((matchedNode = dollarMatch(path, node, inputThatTopic, starState, starIndex, inputStars, thatStars, topicStars, matchTrace)) != null) return matchedNode;
else if ((matchedNode = sharpMatch(path, node, inputThatTopic, starState, starIndex, inputStars, thatStars, topicStars, matchTrace)) != null) return matchedNode;
else if ((matchedNode = underMatch(path, node, inputThatTopic, starState, starIndex, inputStars, thatStars, topicStars, matchTrace)) != null) return matchedNode;
else if ((matchedNode = wordMatch(path, node, inputThatTopic, starState, starIndex, inputStars, thatStars, topicStars, matchTrace)) != null) return matchedNode;
else if ((matchedNode = setMatch(path, node, inputThatTopic, starState, starIndex, inputStars, thatStars, topicStars, matchTrace)) != null) return matchedNode;
else if ((matchedNode = shortCutMatch(path, node, inputThatTopic, starState, starIndex, inputStars, thatStars, topicStars, matchTrace)) != null) return matchedNode;
else if ((matchedNode = caretMatch(path, node, inputThatTopic, starState, starIndex, inputStars, thatStars, topicStars, matchTrace)) != null) return matchedNode;
else if ((matchedNode = starMatch(path, node, inputThatTopic, starState, starIndex, inputStars, thatStars, topicStars, matchTrace)) != null) return matchedNode;
else {
return null;
}
}
/**
* print out match trace when search fails
*
* @param mode Which mode of search
* @param trace Match trace info
*/
void fail (String mode, String trace) {
// log.info("Match failed ("+mode+") "+trace);
}
/**
* a match is found if the end of the path is reached and the node is a leaf node
*
* @param path remaining path
* @param node current search node
* @param matchTrace trace of match for debugging purposes
* @return matching leaf node or null if no match found
*/
final Nodemapper nullMatch(Path path, Nodemapper node, String matchTrace) {
if (path == null && node != null && NodemapperOperator.isLeaf(node) && node.category != null) return node;
else {
fail("null", matchTrace);
return null;
}
}
final Nodemapper shortCutMatch(Path path, Nodemapper node, String inputThatTopic, String starState, int starIndex, String[] inputStars, String[] thatStars, String[] topicStars, String matchTrace) {
if (node != null && node.shortCut && path.word.equals("<THAT>") && node.category != null) {
String tail = Path.pathToSentence(path).trim();
//log.info("Shortcut tail = "+tail);
String that = tail.substring(tail.indexOf("<THAT>")+"<THAT>".length(), tail.indexOf("<TOPIC>")).trim();
String topic = tail.substring(tail.indexOf("<TOPIC>")+"<TOPIC>".length(), tail.length()).trim();
//log.info("Shortcut that = "+that+" topic = "+topic);
//log.info("Shortcut matched: "+node.category.inputThatTopic());
thatStars[0] = that;
topicStars[0] = topic;
return node;
}
else {
fail("shortCut", matchTrace);
return null;
}
}
final Nodemapper wordMatch(Path path, Nodemapper node, String inputThatTopic, String starState, int starIndex, String[] inputStars, String[] thatStars, String[] topicStars, String matchTrace) {
Nodemapper matchedNode;
try {
String uword = path.word.toUpperCase();
if (uword.equals("<THAT>")) {starIndex = 0; starState = "thatStar";}
else if (uword.equals("<TOPIC>")) {starIndex = 0; starState = "topicStar";}
//log.info("path.next= "+path.next+" node.get="+node.get(uword));
matchTrace += "["+uword+","+uword+"]";
if (path != null && NodemapperOperator.containsKey(node, uword) &&
(matchedNode = match(path.next, NodemapperOperator.get(node, uword), inputThatTopic, starState, starIndex, inputStars, thatStars, topicStars, matchTrace)) != null) {
return matchedNode;
} else {
fail("word", matchTrace);
return null;
}
} catch (Exception ex) {
// log.info("wordMatch: "+Path.pathToSentence(path)+": "+ex);
ex.printStackTrace();
return null;
}
}
final Nodemapper dollarMatch(Path path, Nodemapper node, String inputThatTopic, String starState, int starIndex, String[] inputStars, String[] thatStars, String[] topicStars, String matchTrace) {
String uword = "$"+path.word.toUpperCase();
Nodemapper matchedNode;
if (path != null && NodemapperOperator.containsKey(node, uword) && (matchedNode = match(path.next, NodemapperOperator.get(node, uword), inputThatTopic, starState, starIndex, inputStars, thatStars, topicStars, matchTrace)) != null) {
return matchedNode;
} else {
fail("dollar", matchTrace);
return null;
}
}
final Nodemapper starMatch(Path path, Nodemapper node, String input, String starState, int starIndex, String[] inputStars, String[] thatStars, String[] topicStars, String matchTrace) {
return wildMatch(path, node, input, starState, starIndex, inputStars, thatStars, topicStars, "*", matchTrace);
}
final Nodemapper underMatch(Path path, Nodemapper node, String input, String starState, int starIndex, String[] inputStars, String[] thatStars, String[] topicStars, String matchTrace) {
return wildMatch(path, node, input, starState, starIndex, inputStars, thatStars, topicStars, "_", matchTrace);
}
final Nodemapper caretMatch(Path path, Nodemapper node, String input, String starState, int starIndex, String[] inputStars, String[] thatStars, String[] topicStars, String matchTrace) {
Nodemapper matchedNode;
matchedNode = zeroMatch(path, node, input, starState, starIndex, inputStars, thatStars, topicStars, "^", matchTrace);
if (matchedNode != null) return matchedNode;
else return wildMatch(path, node, input, starState, starIndex, inputStars, thatStars, topicStars, "^", matchTrace);
}
final Nodemapper sharpMatch(Path path, Nodemapper node, String input, String starState, int starIndex, String[] inputStars, String[] thatStars, String[] topicStars, String matchTrace) {
//log.info("Entering sharpMatch with path.word="+path.word); NodemapperOperator.printKeys(node);
Nodemapper matchedNode;
matchedNode = zeroMatch(path, node, input, starState, starIndex, inputStars, thatStars, topicStars, "#", matchTrace);
if (matchedNode != null) return matchedNode;
else
return wildMatch(path, node, input, starState, starIndex, inputStars, thatStars, topicStars, "#", matchTrace);
}
final Nodemapper zeroMatch(Path path, Nodemapper node, String input, String starState, int starIndex,
String[] inputStars, String[] thatStars, String[] topicStars, String wildcard, String matchTrace) {
// log.info("Entering zeroMatch on "+path.word+" "+NodemapperOperator.get(node, wildcard));
matchTrace += "["+wildcard+",]";
if (path != null && NodemapperOperator.containsKey(node, wildcard)) {
setStars(bot.properties.get(MagicStrings.null_star), starIndex, starState, inputStars, thatStars, topicStars);
Nodemapper nextNode = NodemapperOperator.get(node, wildcard);
return match(path, nextNode, input, starState, starIndex+1, inputStars, thatStars, topicStars, matchTrace);
}
else {
fail("zero "+wildcard, matchTrace);
return null;
}
}
final Nodemapper wildMatch(Path path, Nodemapper node, String input, String starState, int starIndex,
String[] inputStars, String[] thatStars, String[] topicStars, String wildcard, String matchTrace) {
Nodemapper matchedNode;
if (path.word.equals("<THAT>") || path.word.equals("<TOPIC>")) {
fail("wild1 "+wildcard, matchTrace);
return null;
}
try {
if (path != null && NodemapperOperator.containsKey(node, wildcard)) {
matchTrace += "["+wildcard+","+path.word+"]";
String currentWord;
String starWords;
Path pathStart;
currentWord = path.word;
starWords = currentWord+" ";
pathStart = path.next;
Nodemapper nextNode = NodemapperOperator.get(node, wildcard);
if (NodemapperOperator.isLeaf(nextNode) && !nextNode.shortCut) {
matchedNode = nextNode;
starWords = Path.pathToSentence(path);
//log.info(starIndex+". starwords="+starWords);
setStars(starWords, starIndex, starState, inputStars, thatStars, topicStars);
return matchedNode;
}
else {
for (path = pathStart; path != null && !currentWord.equals("<THAT>") && !currentWord.equals("<TOPIC>"); path = path.next) {
matchTrace += "["+wildcard+","+path.word+"]";
if ((matchedNode = match(path, nextNode, input, starState, starIndex + 1, inputStars, thatStars, topicStars, matchTrace)) != null) {
setStars(starWords, starIndex, starState, inputStars, thatStars, topicStars);
return matchedNode;
}
else {
currentWord = path.word;
starWords += currentWord + " ";
}
}
fail("wild2 "+wildcard, matchTrace);
return null;
}
}
} catch (Exception ex) {
//log.info("wildMatch: "+Path.pathToSentence(path)+": "+ex);
}
fail("wild3 "+wildcard, matchTrace);
return null;
}
final Nodemapper setMatch(Path path, Nodemapper node, String input, String starState, int starIndex, String[] inputStars, String[] thatStars, String[] topicStars, String matchTrace) {
if (node.sets == null || path.word.equals("<THAT>") || path.word.equals("<TOPIC>")) return null;
//log.info("setMatch sets ="+node.sets);
for (String setName : node.sets) {
//log.info("setMatch trying type "+setName);
Nodemapper nextNode = NodemapperOperator.get(node, "<SET>"+setName.toUpperCase()+"</SET>");
AIMLSet aimlSet = bot.setMap.get(setName);
//log.info(aimlSet.setName + "="+ aimlSet);
Nodemapper matchedNode;
String currentWord = path.word;
String starWords = currentWord+" ";
int length = 1;
matchTrace += "[<set>"+setName+"</set>,"+path.word+"]";
//log.info("setMatch starWords =\""+starWords+"\"");
for (Path qath = path.next; qath != null && !currentWord.equals("<THAT>") && !currentWord.equals("<TOPIC>") && length <= aimlSet.maxLength; qath = qath.next) {
//log.info("qath.word = "+qath.word);
String phrase = bot.preProcessor.normalize(starWords.trim()).toUpperCase();
//log.info("setMatch trying \""+phrase+"\" in "+setName);
if (aimlSet.contains(phrase) && (matchedNode = match(qath, nextNode, input, starState, starIndex + 1, inputStars, thatStars, topicStars, matchTrace)) != null) {
setStars(starWords, starIndex, starState, inputStars, thatStars, topicStars);
//log.info("setMatch found "+phrase+" in "+setName);
return matchedNode;
}
// else if (qath.word.equals("<THAT>") || qath.word.equals("<TOPIC>")) return null;
else {
length = length + 1;
currentWord = qath.word;
starWords += currentWord + " ";
}
}
}
fail("set", matchTrace);
return null;
}
public void setStars(String starWords, int starIndex, String starState, String[] inputStars, String[] thatStars, String[] topicStars) {
if (starIndex < MagicNumbers.max_stars) {
starWords = starWords.trim();
if (starState.equals("inputStar")) inputStars[starIndex] = starWords;
else if (starState.equals("thatStar")) thatStars[starIndex] = starWords;
else if (starState.equals("topicStar")) topicStars[starIndex] = starWords;
}
}
public void printgraph () {
printgraph(root, "");
}
void printgraph(Nodemapper node, String partial) {
if (node == null) ;
else {
String template = "";
if (NodemapperOperator.isLeaf(node) || node.shortCut) {
template = Category.templateToLine(node.category.getTemplate());
template = template.substring(0, Math.min(16, template.length()));
if (node.shortCut) ;
else ;
}
for (String key : NodemapperOperator.keySet(node)) {
//log.info(key);
printgraph(NodemapperOperator.get(node, key), partial+"("+NodemapperOperator.size(node)+"["+node.height+"])--"+key+"-->");
}
}
}
public ArrayList<Category> getCategories() {
ArrayList<Category> categories = new ArrayList<Category>();
getCategories(root, categories);
//for (Category c : categories) log.info("getCategories: "+c.inputThatTopic()+" "+c.getTemplate());
return categories;
}
void getCategories(Nodemapper node, ArrayList<Category> categories) {
if (node == null) return;
else {
//String template = "";
if (NodemapperOperator.isLeaf(node) || node.shortCut) {
if (node.category != null) categories.add(node.category); // node.category == null when the category is deleted.
}
for (String key : NodemapperOperator.keySet(node)) {
//log.info(key);
getCategories(NodemapperOperator.get(node, key), categories);
}
}
}
int leafCnt;
int nodeCnt;
long nodeSize;
int singletonCnt;
int shortCutCnt;
int naryCnt;
public void nodeStats() {
leafCnt = 0;
nodeCnt = 0;
nodeSize = 0;
singletonCnt = 0;
shortCutCnt = 0;
naryCnt = 0;
nodeStatsGraph(root);
resultNote = nodeCnt+" nodes "+singletonCnt+" singletons "+leafCnt+" leaves "+shortCutCnt+" shortcuts "+naryCnt+" n-ary "+nodeSize+" branches "+(float)nodeSize/(float)nodeCnt+" average branching ";
// log.info(resultNote);
}
public void nodeStatsGraph(Nodemapper node) {
if (node != null) {
//log.info("Counting "+node.key+ " size="+NodemapperOperator.size(node));
nodeCnt++;
nodeSize += NodemapperOperator.size(node);
if (NodemapperOperator.size(node) == 1) singletonCnt += 1;
if (NodemapperOperator.isLeaf(node) && !node.shortCut) {
leafCnt++;
}
if (NodemapperOperator.size(node) > 1) naryCnt += 1;
if (node.shortCut) {shortCutCnt += 1;}
for (String key : NodemapperOperator.keySet(node)) {
nodeStatsGraph(NodemapperOperator.get(node, key));
}
}
}
public HashSet<String> getVocabulary () {
vocabulary = new HashSet<String>();
getBrainVocabulary(root);
for (String set : bot.setMap.keySet()) vocabulary.addAll(bot.setMap.get(set));
return vocabulary;
}
public void getBrainVocabulary(Nodemapper node) {
if (node != null) {
//log.info("Counting "+node.key+ " size="+NodemapperOperator.size(node));
for (String key : NodemapperOperator.keySet(node)) {
vocabulary.add(key);
getBrainVocabulary(NodemapperOperator.get(node, key));
}
}
}
}

View File

@ -0,0 +1,103 @@
package org.alicebot.ab;
//import org.slf4j.Logger;
//mport org.slf4j.LoggerFactory;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
/**
* History object to maintain history of input, that request and response
*
* @param <T> type of history object
*/
public class History<T> {
//private static final Logger log = LoggerFactory.getLogger(History.class);
private Object[] history;
private String name;
/**
* Constructor with default history name
*/
public History () {
this("unknown");
}
/**
* Constructor with history name
*
* @param name name of history
*/
public History(String name) {
this.name = name;
history = new Object[MagicNumbers.max_history];
}
/**
* add an item to history
*
* @param item history item to add
*/
public void add(T item) {
for (int i = MagicNumbers.max_history-1; i > 0; i--) {
history[i] = history[i-1];
}
history[0] = item;
}
/**
* get an item from history
*
* @param index history index
* @return history item
*/
public T get (int index) {
if (index < MagicNumbers.max_history) {
if (history[index] == null) return null;
else return (T)history[index];
}
else return null;
}
/**
* get a String history item
*
* @param index history index
* @return history item
*/
public String getString (int index) {
if (index < MagicNumbers.max_history) {
if (history[index] == null) return MagicStrings.unknown_history_item;
else return (String)history[index];
}
else return null;
}
/**
* print history
*/
public void printHistory() {
int i;
for (i = 0; get(i) != null; i++) {
// log.info(name+"History "+(i+1)+" = "+get(i));
// log.info("{}", String.valueOf(get(i).getClass()).contains("History"));
if (String.valueOf(get(i).getClass()).contains("History")) ((History)get(i)).printHistory();
}
}
}

View File

@ -0,0 +1,97 @@
package org.alicebot.ab;
import org.joda.time.Days;
import org.joda.time.Hours;
import org.joda.time.Months;
import org.joda.time.Years;
import org.joda.time.chrono.GregorianChronology;
import org.joda.time.chrono.LenientChronology;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
public class Interval {
//private static final Logger log = LoggerFactory.getLogger(Interval.class);
public static void test () {
String date1 = "23:59:59.00";
String date2 = "12:00:00.00";
String format = "HH:mm:ss.SS";
int hours = getHoursBetween(date2, date1, format);
// log.info("Hours = "+hours);
date1 = "January 30, 2013";
date2 = "August 2, 1960";
format = "MMMMMMMMM dd, yyyy";
int years = getYearsBetween(date2, date1, format);
// log.info("Years = "+years);
}
// http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html
public static int getHoursBetween(final String date1, final String date2, String format){
try {
final DateTimeFormatter fmt =
DateTimeFormat
.forPattern(format)
.withChronology(
LenientChronology.getInstance(
GregorianChronology.getInstance()));
return Hours.hoursBetween(
fmt.parseDateTime(date1),
fmt.parseDateTime(date2)
).getHours();
} catch (Exception ex) {
ex.printStackTrace();
return 0;
}
}
public static int getYearsBetween(final String date1, final String date2, String format){
try {
final DateTimeFormatter fmt =
DateTimeFormat
.forPattern(format)
.withChronology(
LenientChronology.getInstance(
GregorianChronology.getInstance()));
return Years.yearsBetween(
fmt.parseDateTime(date1),
fmt.parseDateTime(date2)
).getYears();
} catch (Exception ex) {
ex.printStackTrace();
return 0;
}
}
public static int getMonthsBetween(final String date1, final String date2, String format){
try {
final DateTimeFormatter fmt =
DateTimeFormat
.forPattern(format)
.withChronology(
LenientChronology.getInstance(
GregorianChronology.getInstance()));
return Months.monthsBetween(
fmt.parseDateTime(date1),
fmt.parseDateTime(date2)
).getMonths();
} catch (Exception ex) {
ex.printStackTrace();
return 0;
}
}
public static int getDaysBetween(final String date1, final String date2, String format){
try {
final DateTimeFormatter fmt =
DateTimeFormat
.forPattern(format)
.withChronology(
LenientChronology.getInstance(
GregorianChronology.getInstance()));
return Days.daysBetween(
fmt.parseDateTime(date1),
fmt.parseDateTime(date2)
).getDays();
} catch (Exception ex) {
ex.printStackTrace();
return 0;
}
}
}

View File

@ -0,0 +1,133 @@
package org.alicebot.ab;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//import net.reduls.sanmoku.Morpheme;
//import net.reduls.sanmoku.Tagger;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.atilika.kuromoji.Token;
//import org.atilika.kuromoji.Tokenizer;
/**
* Tokenize a Japanese language input by inserting spaces between words
*
* see http://atilika.org/
*/
public class JapaneseTokenizer {
//private static final Logger log = LoggerFactory
// .getLogger(JapaneseTokenizer.class);
//static final Tokenizer tokenizer = Tokenizer.builder().build();
static final Pattern tagPattern = Pattern.compile("(<.*>.*</.*>)|(<.*/>)");
static Set<Character.UnicodeBlock> japaneseUnicodeBlocks = new HashSet<Character.UnicodeBlock>() {{
add(Character.UnicodeBlock.HIRAGANA);
add(Character.UnicodeBlock.KATAKANA);
add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS);
}};
/*public static ArrayList<String> tokenize(String sentence) {
ArrayList<String> result = new ArrayList<String>();
//Tokenizer tokenizer = Tokenizer.builder().build();
for (Token token : tokenizer.tokenize(sentence)) {
result.add(token.getSurfaceForm());
}
return result;
}
public static String buildFragment(String fragment) {
ArrayList<String> tokens = tokenize(fragment);
String result = "";
for (String word : tokens) {
result += " "+word;
}
return result.trim();
}*/
/* public static String morphSentence (String sentence) {
Matcher matcher = tagPattern.matcher(sentence);
String result = "";
while (matcher.find()) {
int i = matcher.start();
int j = matcher.end();
String prefix, tag;
if (i > 0) prefix = sentence.substring(0, i-1); else prefix = "";
tag = sentence.substring(i, j);
result += " "+buildFragment(prefix)+" "+tag;
if (j < sentence.length()) sentence = sentence.substring(j, sentence.length()); else sentence = "";
System.out.print("Start index: " + matcher.start());
System.out.print(" End index: " + matcher.end() + " ");
log.info(matcher.group());
}
result += " "+buildFragment(sentence);
while (result.contains("$ ")) result = result.replace("$ ", "$");
while (result.contains(" ")) result = result.replace(" "," ");
return result.trim();
}*/ /*
public static String morphSentence (String sentence) {
String result = "";
for (char c : sentence.toCharArray()) {
if (japaneseUnicodeBlocks.contains(Character.UnicodeBlock.of(c))) {
//log.info(c + " is a Japanese character");
result = result+" "+c+" ";
} else {
//log.info(c + " is not a Japanese character");
result = result + c;
}
}
while (result.contains("$ ")) result = result.replace("$ ", "$");
while (result.contains(" ")) result = result.replace(" "," ");
return result.trim();
}
*/
/**
* Tokenize a fragment of the input that contains only text
*
* @param fragment fragment of input containing only text and no XML tags
* @return tokenized fragment
*/
// public static String buildFragment(String fragment) {
// String result = "";
// for(Morpheme e : Tagger.parse(fragment)) {
// result += e.surface+" ";
//
// log.info("Feature "+e.feature+" Surface="+e.surface);
// }
// return result.trim();
// }
/**
* Morphological analysis of an input sentence that contains an AIML pattern.
*
* @param sentence
* @return morphed sentence with one space between words, preserving XML markup and AIML $ operation
*/
// public static String morphSentence (String sentence) {
// if (!MagicBooleans.jp_morphological_analysis) return sentence;
// String result = "";
// Matcher matcher = tagPattern.matcher(sentence);
// while (matcher.find()) {
// int i = matcher.start();
// int j = matcher.end();
// String prefix, tag;
// if (i > 0) prefix = sentence.substring(0, i-1); else prefix = "";
// tag = sentence.substring(i, j);
// result += " "+buildFragment(prefix)+" "+tag;
// if (j < sentence.length()) sentence = sentence.substring(j, sentence.length()); else sentence = "";
// //System.out.print("Start index: " + matcher.start());
// //System.out.print("End index: " + matcher.end() + " ");
// //log.info(matcher.group());
// }
// result += " "+buildFragment(sentence);
// while (result.contains("$ ")) result = result.replace("$ ", "$");
// while (result.contains(" ")) result = result.replace(" "," ");
// return result.trim();
// }
}

View File

@ -0,0 +1,31 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
/**
* Global boolean values that control various actions in Program AB
*/
public class MagicBooleans {
public static boolean trace_mode = true;
public static boolean enable_external_sets = true;
public static boolean enable_external_maps = true;
public static boolean jp_morphological_analysis = false;
public static boolean fix_excel_csv = true;
}

View File

@ -0,0 +1,39 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
/**
* Integers with specific values in Program AB
*
*/
public class MagicNumbers {
public static int node_activation_cnt = 4;
public static int node_size = 4;
public static int displayed_input_sample_size = 6;
public static int max_history = 32;
public static int max_stars = 1000;
public static int max_graph_height = 100000;
public static int max_substitutions = 10000;
public static int max_recursion = 512;
public static int max_trace_length = 2048;
public static int max_loops = 10000;
public static int estimated_brain_size = 5000;
public static int max_natural_number_digits = 10000;
}

View File

@ -0,0 +1,101 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
/**
* Global values for many strings in Program AB
*/
public class MagicStrings {
// General global strings
public static String programNameVersion = "Program AB 0.0.4.3 beta -- AI Foundation Reference AIML 2.0 implementation";
public static String comment = "removed some recursion from Path";
public static String aimlif_split_char = ",";
public static String default_bot = "super";
public static String default_language = "EN";
public static String aimlif_split_char_name = "\\#Comma";
public static String aimlif_file_suffix = ".csv";
public static String ab_sample_file = "sample.txt";
// <sraix> defaults
public static String pannous_api_key = "guest";
public static String pannous_login = "test-user";
public static String sraix_failed = "SRAIXFAILED";
public static String sraix_no_hint = "nohint";
public static String sraix_event_hint = "event";
public static String sraix_pic_hint = "pic";
// AIML files
public static String unknown_aiml_file = "unknown_aiml_file.aiml";
public static String deleted_aiml_file = "deleted.aiml";
public static String learnf_aiml_file = "learnf.aiml";
public static String null_aiml_file = "null.aiml";
public static String inappropriate_aiml_file = "inappropriate.aiml";
public static String profanity_aiml_file = "profanity.aiml";
public static String insult_aiml_file = "insults.aiml";
public static String reductions_update_aiml_file = "reductions_update.aiml";
public static String predicates_aiml_file = "client_profile.aiml";
public static String update_aiml_file = "update.aiml";
public static String personality_aiml_file = "personality.aiml";
public static String sraix_aiml_file = "sraix.aiml";
public static String oob_aiml_file = "oob.aiml";
public static String unfinished_aiml_file = "unfinished.aiml";
// filter responses
public static String inappropriate_filter = "FILTER INAPPROPRIATE";
public static String profanity_filter = "FILTER PROFANITY";
public static String insult_filter = "FILTER INSULT";
// default templates
public static String deleted_template = "deleted";
public static String unfinished_template = "unfinished";
// AIML defaults
public static String unknown_history_item = "unknown";
public static String default_bot_response = "I have no answer for that.";
public static String error_bot_response = "Something is wrong with my brain.";
public static String schedule_error = "I'm unable to schedule that event.";
public static String system_failed = "Failed to execute system command.";
public static String unknown_predicate_value = "unknown";
public static String unknown_property_value = "unknown";
public static String unknown_map_value = "unknown";
public static String unknown_customer_id = "unknown";
public static String unknown_bot_name = "unknown";
public static String default_that = "unknown";
public static String default_topic = "unknown";
public static String template_failed = "Template failed.";
public static String too_much_recursion = "Too much recursion in AIML";
public static String too_much_looping = "Too much looping in AIML";
public static String blank_template = "blank template";
public static String null_input = "NORESP";
public static String null_star = "nullstar";
// sets and maps
public static String set_member_string = "ISA";
public static String remote_map_key = "external";
public static String remote_set_key = "external";
public static String natural_number_set_name = "number";
public static String map_successor = "successor";
public static String map_predecessor = "predecessor";
// paths
public static String root_path = "c:/ab";
public static String bot_path = root_path+"/bots";
public static String bot_name_path = bot_path+"/super";
public static String aimlif_path = bot_path+"/aimlif";
public static String aiml_path = bot_path+"/aiml";
public static String config_path = bot_path+"/config";
public static String log_path = bot_path+"/log";
public static String sets_path = bot_path+"/sets";
public static String maps_path = bot_path+"/maps";
}

View File

@ -0,0 +1,56 @@
package org.alicebot.ab;
import org.alicebot.ab.utils.MemoryUtils;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
/**
* Memory statistics for program instrumentation
*
*/
public class MemStats {
//private static final Logger log = LoggerFactory.getLogger(MemStats.class);
public static long prevHeapSize = 0;
/**
* print out some statistics about heap size
*/
public static void memStats () {
// Get current size of heap in bytes
long heapSize = MemoryUtils.totalMemory();
// Get maximum size of heap in bytes. The heap cannot grow beyond this size.
// Any attempt will result in an OutOfMemoryException.
long heapMaxSize = MemoryUtils.maxMemory();
// Get amount of free memory within the heap in bytes. This size will increase
// after garbage collection and decrease as new objects are created.
long heapFreeSize = MemoryUtils.freeMemory();
long diff = heapSize - prevHeapSize;
prevHeapSize = heapSize;
// log.info("Heap "+heapSize+" MaxSize "+heapMaxSize+" Free "+heapFreeSize+" Diff "+diff);
}
}

View File

@ -0,0 +1,46 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.util.ArrayList;
import java.util.HashMap;
/**
* Nodemapper data structure. In order to minimize memory overhead this class has no methods.
* Operations on Nodemapper objects are performed by NodemapperOperator class
*/
public class Nodemapper {
/* public static int idCnt=0;
public int id;*/
public Category category = null;
public int height = MagicNumbers.max_graph_height;
public StarBindings starBindings = null;
public HashMap<String, Nodemapper> map = null;
public String key = null;
public Nodemapper value = null;
public boolean shortCut = false;
public ArrayList<String> sets;
/* public Nodemapper () {
id = idCnt++;
}*/
}

View File

@ -0,0 +1,154 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
public class NodemapperOperator {
//private static final Logger log = LoggerFactory
// .getLogger(NodemapperOperator.class);
/**
* number of branches from node
*
* @param node Nodemapper object
* @return number of branches
*/
public static int size(Nodemapper node) {
HashSet set = new HashSet();
if (node.shortCut) set.add("<THAT>");
if (node.key != null) set.add(node.key);
if (node.map != null) set.addAll(node.map.keySet());
return set.size();
}
/**
* insert a new link from this node to another, by adding a key, value pair
*
* @param node Nodemapper object
* @param key key word
* @param value word maps to this next node
*/
public static void put(Nodemapper node, String key, Nodemapper value) {
if (node.map != null) {
node.map.put(key, value);
}
else { // node.type == unary_node_mapper
node.key = key;
node.value = value;
}
}
/**
* get the node linked to this one by the word key
*
* @param node Nodemapper object
* @param key key word to map
* @return the mapped node or null if the key is not found
*/
public static Nodemapper get(Nodemapper node, String key) {
if (node.map != null) {
return node.map.get(key);
}
else {// node.type == unary_node_mapper
if (key.equals(node.key)) return node.value;
else return null;
}
}
/**
* check whether a node contains a particular key
*
* @param node Nodemapper object
* @param key key to test
* @return true or false
*/
public static boolean containsKey(Nodemapper node, String key) {
//log.info("containsKey: Node="+node+" Map="+node.map);
if (node.map != null) {
return node.map.containsKey(key) ;
}
else {// node.type == unary_node_mapper
if (key.equals(node.key)) return true;
else return false;
}
}
/**
* print all node keys
*
* @param node Nodemapper object
*/
public static void printKeys (Nodemapper node) {
Set set = keySet(node);
Iterator iter = set.iterator();
while (iter.hasNext()) {
// log.info("" + iter.next());
}
}
/**
* get key set of a node
*
* @param node Nodemapper object
* @return set of keys
*/
public static Set<String> keySet(Nodemapper node) {
if (node.map != null) {
return node.map.keySet();
}
else {// node.type == unary_node_mapper
Set set = new HashSet<String>();
if (node.key != null) set.add(node.key);
return set;
}
}
/**
* test whether a node is a leaf
*
* @param node Nodemapper object
* @return true or false
*/
public static boolean isLeaf(Nodemapper node) {
return (node.category != null);
}
/**
* upgrade a node from a singleton to a multi-way map
*
* @param node Nodemapper object
*/
public static void upgrade(Nodemapper node) {
//log.info("Upgrading "+node.id);
//node.type = MagicNumbers.hash_node_mapper;
node.map = new HashMap<String, Nodemapper>();
node.map.put(node.key, node.value);
node.key = null;
node.value = null;
}
}

View File

@ -0,0 +1,156 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.util.Set;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* This is just a stub to make the contactaction.aiml file work on a PC
* with some extension tags that are defined for mobile devices.
*/
public class PCAIMLProcessorExtension implements AIMLProcessorExtension {
//private static final Logger log = LoggerFactory
// .getLogger(PCAIMLProcessorExtension.class);
public Set<String> extensionTagNames = Utilities.stringSet("contactid","multipleids","displayname","dialnumber","emailaddress","contactbirthday","addinfo");
@Override
public Set <String> extensionTagSet() {
return extensionTagNames;
}
private String newContact(Node node, ParseState ps) {
NodeList childList = node.getChildNodes();
String emailAddress="unknown";
String displayName="unknown";
String dialNumber="unknown";
String emailType="unknown";
String phoneType="unknown";
String birthday="unknown";
for (int i = 0; i < childList.getLength(); i++) {
if (childList.item(i).getNodeName().equals("birthday")) {
birthday = AIMLProcessor.evalTagContent(childList.item(i), ps, null);
}
if (childList.item(i).getNodeName().equals("phonetype")) {
phoneType = AIMLProcessor.evalTagContent(childList.item(i), ps, null);
}
if (childList.item(i).getNodeName().equals("emailtype")) {
emailType = AIMLProcessor.evalTagContent(childList.item(i), ps, null);
}
if (childList.item(i).getNodeName().equals("dialnumber")) {
dialNumber = AIMLProcessor.evalTagContent(childList.item(i), ps, null);
}
if (childList.item(i).getNodeName().equals("displayname")) {
displayName = AIMLProcessor.evalTagContent(childList.item(i), ps, null);
}
if (childList.item(i).getNodeName().equals("emailaddress")) {
emailAddress = AIMLProcessor.evalTagContent(childList.item(i), ps, null);
}
}
// log.info("Adding new contact "+displayName+" "+phoneType+" "+dialNumber+" "+emailType+" "+emailAddress+" "+birthday);
Contact contact = new Contact(displayName, phoneType, dialNumber, emailType, emailAddress, birthday);
return "";
}
private String contactId(Node node, ParseState ps) {
String displayName = AIMLProcessor.evalTagContent(node, ps, null);
String result = Contact.contactId(displayName);
//log.info("contactId("+displayName+")="+result);
return result;
}
private String multipleIds(Node node, ParseState ps){
String contactName = AIMLProcessor.evalTagContent(node, ps, null);
String result = Contact.multipleIds(contactName);
//log.info("multipleIds("+contactName+")="+result);
return result;
}
private String displayName(Node node, ParseState ps){
String id = AIMLProcessor.evalTagContent(node, ps, null);
String result = Contact.displayName(id);
//log.info("displayName("+id+")="+result);
return result;
}
private String dialNumber(Node node, ParseState ps) {
NodeList childList = node.getChildNodes();
String id="unknown";
String type="unknown";
for (int i = 0; i < childList.getLength(); i++) {
if (childList.item(i).getNodeName().equals("id")) {
id = AIMLProcessor.evalTagContent(childList.item(i), ps, null);
}
if (childList.item(i).getNodeName().equals("type")) {
type = AIMLProcessor.evalTagContent(childList.item(i), ps, null);
}
}
String result = Contact.dialNumber(type, id);
//log.info("dialNumber("+id+")="+result);
return result;
}
private String emailAddress(Node node, ParseState ps){
NodeList childList = node.getChildNodes();
String id="unknown";
String type="unknown";
for (int i = 0; i < childList.getLength(); i++) {
if (childList.item(i).getNodeName().equals("id")) {
id = AIMLProcessor.evalTagContent(childList.item(i), ps, null);
}
if (childList.item(i).getNodeName().equals("type")) {
type = AIMLProcessor.evalTagContent(childList.item(i), ps, null);
}
}
String result = Contact.emailAddress(type, id);
//log.info("emailAddress("+id+")="+result);
return result;
}
private String contactBirthday(Node node, ParseState ps){
String id = AIMLProcessor.evalTagContent(node, ps, null);
String result = Contact.birthday(id);
//log.info("birthday("+id+")="+result);
return result;
}
@Override
public String recursEval(Node node, ParseState ps) {
try {
String nodeName = node.getNodeName();
if (nodeName.equals("contactid"))
return contactId(node, ps);
else if (nodeName.equals("multipleids"))
return multipleIds(node, ps);
else if (nodeName.equals("dialnumber"))
return dialNumber(node, ps);
else if (nodeName.equals("addinfo"))
return newContact(node, ps);
else if (nodeName.equals("displayname"))
return displayName(node, ps);
else if (nodeName.equals("emailaddress"))
return emailAddress(node, ps);
else if (nodeName.equals("contactbirthday"))
return contactBirthday(node, ps) ;
else return (AIMLProcessor.genericXML(node, ps));
} catch (Exception ex) {
ex.printStackTrace();
return "";
}
}
}

View File

@ -0,0 +1,52 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
/**
ParseState is a helper class for AIMLProcessor
*/
public class ParseState {
public Nodemapper leaf;
public String input;
public String that;
public String topic;
public Chat chatSession;
public int depth;
public Predicates vars;
/**
* Constructor - class has public members
*
* @param depth depth in parse tree
* @param chatSession client session
* @param input client input
* @param that bot's last sentence
* @param topic current topic
* @param leaf node containing the category processed
*/
public ParseState(int depth, Chat chatSession, String input, String that, String topic, Nodemapper leaf) {
this.chatSession = chatSession;
this.input = input;
this.that = that;
this.topic = topic;
this.leaf = leaf;
this.depth = depth; // to prevent runaway recursion
this.vars = new Predicates();
}
}

View File

@ -0,0 +1,123 @@
package org.alicebot.ab;
import java.util.ArrayList;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
/**
* Linked list representation of Pattern Path and Input Path
*/
public class Path extends ArrayList<String>{
//private static final Logger log = LoggerFactory.getLogger(Path.class);
public String word;
public Path next;
public int length;
/**
* Constructor - class has public members
*/
private Path() {
next = null;
word = null;
length = 0;
}
/**
* convert a sentence (a string consisting of words separated by single spaces) into a Path
*
* @param sentence sentence to convert
* @return sentence in Path form
*/
public static Path sentenceToPath(String sentence) {
sentence = sentence.trim();
return arrayToPath(sentence.split(" "));
}
/**
* The inverse of sentenceToPath
*
* @param path input path
* @return sentence
*/
public static String pathToSentence (Path path) {
String result="";
for (Path p = path; p != null; p = p.next) {
result = result+" "+path.word;
}
return result.trim();
/* if (path == null) return "";
else return path.word+" "+pathToSentence(path.next);*/
}
/**
* convert an array of strings to a Path
*
* @param array array of strings
* @return sequence of strings as Path
*/
private static Path arrayToPath(String[] array) {
Path tail = null;
Path head = null;
for (int i = array.length-1; i >= 0; i--) {
head = new Path();
head.word = array[i];
head.next = tail;
if (tail == null) head.length = 1;
else head.length = tail.length + 1;
tail = head;
}
return head;
//return arrayToPath(array, 0);
}
/**
* recursively convert an array to a Path
*
* @param array array of strings
* @param index array index
* @return Path form
*/
private static Path arrayToPath(String[] array, int index) {
if (index >= array.length) return null;
else {
Path newPath = new Path();
newPath.word = array[index];
newPath.next = arrayToPath(array, index+1);
if (newPath.next == null) newPath.length = 1;
else newPath.length = newPath.next.length + 1;
return newPath;
}
}
/**
* print a Path
*/
public void print() {
String result = "";
for (Path p = this; p != null; p = p.next) {
result += p.word+",";
}
if (result.endsWith(",")) result = result.substring(0, result.length()-1);
// log.info(result);
}
}

View File

@ -0,0 +1,256 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/**
* AIML Preprocessor and substitutions
*/
public class PreProcessor {
//private static final Logger log = LoggerFactory
//.getLogger(PreProcessor.class);
public int normalCount = 0;
public int denormalCount = 0;
public int personCount = 0;
public int person2Count = 0;
public int genderCount = 0;
public String[] normalSubs = new String[MagicNumbers.max_substitutions];
public Pattern[] normalPatterns = new Pattern[MagicNumbers.max_substitutions];
public String[] denormalSubs = new String[MagicNumbers.max_substitutions];
public Pattern[] denormalPatterns = new Pattern[MagicNumbers.max_substitutions];
public String[] personSubs = new String[MagicNumbers.max_substitutions];
public Pattern[] personPatterns = new Pattern[MagicNumbers.max_substitutions];
public String[] person2Subs = new String[MagicNumbers.max_substitutions];
public Pattern[] person2Patterns = new Pattern[MagicNumbers.max_substitutions];
public String[] genderSubs = new String[MagicNumbers.max_substitutions];
public Pattern[] genderPatterns = new Pattern[MagicNumbers.max_substitutions];
/**
* Constructor given bot
*
* @param bot AIML bot
*/
public PreProcessor (Bot bot) {
normalCount = readSubstitutions(MagicStrings.config_path+"/normal.txt", normalPatterns, normalSubs);
denormalCount = readSubstitutions(MagicStrings.config_path+"/denormal.txt", denormalPatterns, denormalSubs);
personCount = readSubstitutions(MagicStrings.config_path +"/person.txt", personPatterns, personSubs);
person2Count = readSubstitutions(MagicStrings.config_path +"/person2.txt", person2Patterns, person2Subs);
genderCount = readSubstitutions(MagicStrings.config_path +"/gender.txt", genderPatterns, genderSubs);
// log.info("Preprocessor: "+normalCount+" norms "+personCount+" persons "+person2Count+" person2 ");
}
/**
* apply normalization substitutions to a request
*
* @param request client input
* @return normalized client input
*/
public String normalize (String request) {
return substitute(request, normalPatterns, normalSubs, normalCount);
}
/**
* apply denormalization substitutions to a request
*
* @param request client input
* @return normalized client input
*/
public String denormalize (String request) {
return substitute(request, denormalPatterns, denormalSubs, denormalCount);
}
/**
* personal pronoun substitution for {@code <person></person>} tag
* @param input sentence
* @return sentence with pronouns swapped
*/
public String person (String input) {
return substitute(input, personPatterns, personSubs, personCount);
}
/**
* personal pronoun substitution for {@code <person2></person2>} tag
* @param input sentence
* @return sentence with pronouns swapped
*/
public String person2 (String input) {
return substitute(input, person2Patterns, person2Subs, person2Count);
}
/**
* personal pronoun substitution for {@code <gender>} tag
* @param input sentence
* @return sentence with pronouns swapped
*/
public String gender (String input) {
return substitute(input, genderPatterns, genderSubs, genderCount);
}
/**
* Apply a sequence of subsitutions to an input string
*
* @param request input request
* @param patterns array of patterns to match
* @param subs array of substitution values
* @param count number of patterns and substitutions
* @return result of applying substitutions to input
*/
String substitute(String request, Pattern[] patterns, String[] subs, int count) {
String result = " "+request+" ";
try {
for (int i = 0; i < count; i++) {
String replacement = subs[i];
Pattern p = patterns[i];
Matcher m = p.matcher(result);
//log.info(i+" "+patterns[i].pattern()+"-->"+subs[i]);
if (m.find()) {
//log.info(m.group());
result = m.replaceAll(replacement);
}
//log.info(result);
}
while (result.contains(" ")) result = result.replace(" "," ");
result = result.trim();
//log.info("Normalized: "+result);
} catch (Exception ex) {
ex.printStackTrace();
}
return result.trim();
}
/**
* read substitutions from input stream
*
* @param in input stream
* @param patterns array of patterns
* @param subs array of substitution values
* @return number of patterns substitutions read
*/
public int readSubstitutionsFromInputStream(InputStream in, Pattern[] patterns, String[] subs) {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
//Read File Line By Line
int subCount = 0;
try {
while ((strLine = br.readLine()) != null) {
//log.info(strLine);
strLine = strLine.trim();
Pattern pattern = Pattern.compile("\"(.*?)\",\"(.*?)\"", Pattern.DOTALL);
Matcher matcher = pattern.matcher(strLine);
if (matcher.find() && subCount < MagicNumbers.max_substitutions) {
subs[subCount] = matcher.group(2);
String quotedPattern = Pattern.quote(matcher.group(1));
//log.info("quoted pattern="+quotedPattern);
patterns[subCount] = Pattern.compile(quotedPattern, Pattern.CASE_INSENSITIVE);
subCount++;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return subCount;
}
/**
* read substitutions from a file
*
* @param filename name of substitution file
* @param patterns array of patterns
* @param subs array of substitution values
* @return number of patterns and substitutions read
*/
int readSubstitutions(String filename, Pattern[] patterns, String[] subs) {
int subCount = 0;
try{
// Open the file that is the first
// command line parameter
File file = new File(filename);
if (file.exists()) {
FileInputStream fstream = new FileInputStream(filename);
// Get the object of DataInputStream
subCount = readSubstitutionsFromInputStream(fstream, patterns, subs);
//Close the input stream
fstream.close();
}
}catch (Exception e){//Catch exception if any
// log.error("Cannot read substitutions from '" + filename + "': " + e, e);
}
return (subCount);
}
/**
* Split an input into an array of sentences based on sentence-splitting characters.
*
* @param line input text
* @return array of sentences
*/
public String[] sentenceSplit(String line) {
line = line.replace("。",".");
line = line.replace("?","?");
line = line.replace("ï¼<EFBFBD>","!");
//log.info("Sentence split "+line);
String result[] = line.split("[\\.!\\?]");
for (int i = 0; i < result.length; i++) result[i] = result[i].trim();
return result;
}
/**
* normalize a file consisting of sentences, one sentence per line.
*
* @param infile input file
* @param outfile output file to write results
*/
public void normalizeFile (String infile, String outfile) {
try{
BufferedWriter bw = null;
FileInputStream fstream = new FileInputStream(infile);
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
bw = new BufferedWriter(new FileWriter(outfile)) ;
String strLine;
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
strLine = normalize(strLine); //.toUpperCase();
bw.write(strLine);
bw.newLine();
}
bw.close();
br.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}

View File

@ -0,0 +1,108 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/**
* Manage client predicates
*
*/
public class Predicates extends HashMap<String, String> {
private static final long serialVersionUID = 1L;
//private static final Logger log = LoggerFactory.getLogger(Predicates.class);
/**
* save a predicate value
*
* @param key predicate name
* @param value predicate value
* @return predicate value
*/
@Override
public String put(String key, String value) {
if (MagicBooleans.trace_mode) ;
return super.put(key, value);
}
/**
* get a predicate value
*
* @param key predicate name
* @return predicate value
*/
public String get(String key) {
String result = super.get(key);
if (result == null) return MagicStrings.unknown_predicate_value;
else return result;
}
/**
* Read predicate default values from an input stream
*
* @param in input stream
*/
public void getPredicateDefaultsFromInputStream (InputStream in) {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
try {
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
if (strLine.contains(":")) {
String property = strLine.substring(0, strLine.indexOf(":"));
String value = strLine.substring(strLine.indexOf(":")+1);
put(property, value);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
/** read predicate defaults from a file
*
* @param filename name of file
*/
public void getPredicateDefaults (String filename) {
try{
// Open the file that is the first
// command line parameter
File file = new File(filename);
if (file.exists()) {
FileInputStream fstream = new FileInputStream(filename);
// Get the object
getPredicateDefaultsFromInputStream(fstream);
fstream.close();
}
}catch (Exception e){//Catch exception if any
//log.error("Cannot get predicate defaults from '" + filename + "': " + e, e);
}
}
}

View File

@ -0,0 +1,94 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/**
* Bot Properties
*/
public class Properties extends HashMap<String, String> {
private static final long serialVersionUID = 1L;
//private static final Logger log = LoggerFactory.getLogger(Properties.class);
/**
* get the value of a bot property.
*
* @param key property name
* @return property value or a string indicating the property is undefined
*/
public String get(String key) {
String result = super.get(key);
if (result == null) return MagicStrings.unknown_property_value;
else return result;
}
/**
* Read bot properties from an input stream.
*
* @param in Input stream
*/
public void getPropertiesFromInputStream(InputStream in) {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
//Read File Line By Line
try {
while ((strLine = br.readLine()) != null) {
if (strLine.contains(":")) {
String property = strLine.substring(0, strLine.indexOf(":"));
String value = strLine.substring(strLine.indexOf(":")+1);
put(property, value);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* Read bot properties from a file.
*
* @param filename file containing bot properties
*/
public void getProperties (String filename) {
// log.info("Get Properties: "+filename);
try {
// Open the file that is the first
// command line parameter
File file = new File(filename);
if (file.exists()) {
// log.info("Exists: "+filename);
FileInputStream fstream = new FileInputStream(filename);
// Get the object
getPropertiesFromInputStream(fstream);
//Close the input stream
fstream.close();
}
} catch (Exception e){//Catch exception if any
// log.error("Cannot get properties from '" + filename + "': " + e, e);
}
}
}

View File

@ -0,0 +1,214 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.alicebot.ab.utils.CalendarUtils;
import org.alicebot.ab.utils.NetworkUtils;
import org.json.JSONArray;
import org.json.JSONObject;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
public class Sraix {
// private static final Logger log = LoggerFactory.getLogger(Sraix.class);
public static HashMap<String, String> custIdMap = new HashMap<String, String>();
private static String custid = "0"; // customer ID number for Pandorabots
public static String sraix(Chat chatSession, String input, String defaultResponse, String hint, String host, String botid, String apiKey, String limit) {
String response;
if (host != null && botid != null) {
response = sraixPandorabots(input, chatSession, host, botid);
}
else response = sraixPannous(input, hint, chatSession);
if (response.equals(MagicStrings.sraix_failed)) {
if (chatSession != null && defaultResponse == null) response = AIMLProcessor.respond(MagicStrings.sraix_failed, "nothing", "nothing", chatSession);
else if (defaultResponse != null) response = defaultResponse;
}
return response;
}
public static String sraixPandorabots(String input, Chat chatSession, String host, String botid) {
//log.info("Entering SRAIX with input="+input+" host ="+host+" botid="+botid);
String responseContent = pandorabotsRequest(input, host, botid);
if (responseContent == null) return MagicStrings.sraix_failed;
else return pandorabotsResponse(responseContent, chatSession, host, botid);
}
public static String pandorabotsRequest(String input, String host, String botid) {
try {
custid = "0";
String key = host+":"+botid;
if (custIdMap.containsKey(key)) custid = custIdMap.get(key);
//log.info("--> custid = "+custid);
String spec = NetworkUtils.spec(host, botid, custid, input);
//log.info("Spec = "+spec);
String responseContent = NetworkUtils.responseContent(spec);
return responseContent;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
public static String pandorabotsResponse (String sraixResponse, Chat chatSession, String host, String botid) {
int n1 = sraixResponse.indexOf("<that>");
int n2 = sraixResponse.indexOf("</that>");
String botResponse = MagicStrings.sraix_failed;
if (n2 > n1)
botResponse = sraixResponse.substring(n1+"<that>".length(), n2);
n1 = sraixResponse.indexOf("custid=");
if (n1 > 0) {
custid = sraixResponse.substring(n1+"custid=\"".length(), sraixResponse.length());
n2 = custid.indexOf("\"");
if (n2 > 0) custid = custid.substring(0, n2);
else custid = "0";
String key = host+":"+botid;
//log.info("--> Map "+key+" --> "+custid);
custIdMap.put(key, custid);
}
if (botResponse.endsWith(".")) botResponse = botResponse.substring(0, botResponse.length()-1); // snnoying Pandorabots extra "."
return botResponse;
}
public static String sraixPannous(String input, String hint, Chat chatSession) {
try {
if (hint == null) hint = MagicStrings.sraix_no_hint;
input = " "+input+" ";
input = input.replace(" point ", ".");
input = input.replace(" rparen ", ")");
input = input.replace(" lparen ","(");
input = input.replace(" slash ","/");
input = input.replace(" star ","*");
input = input.replace(" dash ","-");
input = input.trim();
input = input.replace(" ","+");
int offset = CalendarUtils.timeZoneOffset();
//log.info("OFFSET = "+offset);
String locationString = "";
if (chatSession.locationKnown) {
locationString = "&location="+chatSession.latitude+","+chatSession.longitude;
}
// https://weannie.pannous.com/api?input=when+is+daylight+savings+time+in+the+us&locale=en_US&login=pandorabots&ip=169.254.178.212&botid=0&key=CKNgaaVLvNcLhDupiJ1R8vtPzHzWc8mhIQDFSYWj&exclude=Dialogues,ChatBot&out=json
String url = "https://weannie.pannous.com/api?input="+input+"&locale=en_US&timeZone="+offset+locationString+"&login="+MagicStrings.pannous_login+"&ip="+NetworkUtils.localIPAddress()+"&botid=0&key="+MagicStrings.pannous_api_key+"&exclude=Dialogues,ChatBot&out=json";
// log.debug("Sraix url='"+url+"'");
String page = NetworkUtils.responseContent(url);
// log.debug( "Sraix: "+page);
String text="";
String imgRef="";
if (page == null || page.length() == 0) {
text = MagicStrings.sraix_failed;
}
else {
JSONArray outputJson = new JSONObject(page).getJSONArray("output");
if (outputJson.length() == 0) {
text = MagicStrings.sraix_failed;
}
else {
JSONObject firstHandler = outputJson.getJSONObject(0);
JSONObject actions = firstHandler.getJSONObject("actions");
if (actions.has("reminder")) {
Object obj = actions.get("reminder");
if (obj instanceof JSONObject) {
JSONObject sObj = (JSONObject) obj;
String date = sObj.getString("date");
date = date.substring(0, "2012-10-24T14:32".length());
//log.info("date="+date);
String duration = sObj.getString("duration");
//log.info("duration="+duration);
Pattern datePattern = Pattern.compile("(.*)-(.*)-(.*)T(.*):(.*)");
Matcher m = datePattern.matcher(date);
String year="", month="", day="", hour="", minute="";
if (m.matches()) {
year = m.group(1);
month = String.valueOf(Integer.parseInt(m.group(2))-1);
day = m.group(3);
hour = m.group(4);
minute = m.group(5);
text = "<year>"+year+"</year>" +
"<month>"+month+"</month>" +
"<day>"+day+"</day>" +
"<hour>"+hour+"</hour>" +
"<minute>"+minute+"</minute>" +
"<duration>"+duration+"</duration>";
}
else text = MagicStrings.schedule_error;
}
}
else if (actions.has("say") && !hint.equals(MagicStrings.sraix_pic_hint)) {
Object obj = actions.get("say");
if (obj instanceof JSONObject) {
JSONObject sObj = (JSONObject) obj;
text = sObj.getString("text");
if (sObj.has("moreText")) {
JSONArray arr = sObj.getJSONArray("moreText");
for (int i = 0; i < arr.length(); i++) {
text += " " + arr.getString(i);
}
}
} else {
text = obj.toString();
}
}
if (actions.has("show") && !text.contains("Wolfram")
&& actions.getJSONObject("show").has("images")) {
JSONArray arr = actions.getJSONObject("show").getJSONArray(
"images");
int i = (int)(arr.length() * Math.random());
//for (int j = 0; j < arr.length(); j++) log.info(arr.getString(j));
imgRef = arr.getString(i);
if (imgRef.startsWith("//")) imgRef = "http:"+imgRef;
imgRef = "<a href=\""+imgRef+"\"><img src=\""+imgRef+"\"/></a>";
//log.info("IMAGE REF="+imgRef);
}
}
if (hint.equals(MagicStrings.sraix_event_hint) && !text.startsWith("<year>")) return MagicStrings.sraix_failed;
else if (text.equals(MagicStrings.sraix_failed)) return AIMLProcessor.respond(MagicStrings.sraix_failed, "nothing", "nothing", chatSession);
else {
text = text.replace("&#39;","'");
text = text.replace("&apos;","'");
text = text.replaceAll("\\[(.*)\\]", "");
String[] sentences;
sentences = text.split("\\. ");
//log.info("Sraix: text has "+sentences.length+" sentences:");
String clippedPage = sentences[0];
for (int i = 1; i < sentences.length; i++) {
if (clippedPage.length() < 500) clippedPage = clippedPage + ". "+sentences[i];
//log.info(i+". "+sentences[i]);
}
clippedPage = clippedPage + " " + imgRef;
return clippedPage;
}
}
} catch (Exception ex) {
ex.printStackTrace();
// log.info("Sraix '" + input + "' failed");
}
return MagicStrings.sraix_failed;
} // sraixPannous
}

View File

@ -0,0 +1,37 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
/**
* structure to hold binding of wildcards in input pattern, that pattern and topicpattern
*/
public class StarBindings {
public Stars inputStars;
public Stars thatStars;
public Stars topicStars;
/** Constructor -- this class has public members
*
*/
public StarBindings () {
inputStars = new Stars();
thatStars = new Stars();
topicStars = new Stars();
}
}

View File

@ -0,0 +1,34 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.util.ArrayList;
/**
* Array of values matching wildcards
*/
public class Stars extends ArrayList<String> {
public String star (int i) {
if (i < size())
return get(i);
else return null;
}
}

View File

@ -0,0 +1,48 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
/**
* Specialized timer function for program instrumentation
*/
public class Timer {
private long startTimeMillis;
public Timer () {
start();
}
public void start() {
startTimeMillis = System.currentTimeMillis();
}
public long elapsedTimeMillis() {
return System.currentTimeMillis()-startTimeMillis+1;
}
public long elapsedRestartMs() {
long ms = System.currentTimeMillis()-startTimeMillis+1;
start();
return ms;
}
public float elapsedTimeSecs () {
return elapsedTimeMillis()/1000F;
}
public float elapsedTimeMins () {
return elapsedTimeSecs()/60F;
}
}

View File

@ -0,0 +1,168 @@
package org.alicebot.ab;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import org.alicebot.ab.utils.CalendarUtils;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
public class Utilities {
//private static final Logger log = LoggerFactory.getLogger(Utilities.class);
/**
* Excel sometimes adds mysterious formatting to CSV files.
* This function tries to clean it up.
*
* @param line line from AIMLIF file
* @return reformatted line
*/
public static String fixCSV (String line) {
while (line.endsWith(";")) line = line.substring(0, line.length()-1);
if (line.startsWith("\"")) line = line.substring(1, line.length());
if (line.endsWith("\"")) line = line.substring(0, line.length()-1);
line = line.replaceAll("\"\"", "\"");
return line;
}
public static String tagTrim(String xmlExpression, String tagName) {
String stag = "<"+tagName+">";
String etag = "</"+tagName+">";
if (xmlExpression.length() >= (stag+etag).length()) {
xmlExpression = xmlExpression.substring(stag.length());
xmlExpression = xmlExpression.substring(0, xmlExpression.length()-etag.length());
}
return xmlExpression;
}
public static HashSet<String> stringSet(String... strings) {
HashSet<String> set = new HashSet<String>();
for (String s : strings) set.add(s);
return set;
}
public static String getFileFromInputStream(InputStream in) {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
//Read File Line By Line
String contents = "";
try {
while ((strLine = br.readLine()) != null) {
if (strLine.length() == 0) contents += "\n";
else contents += strLine+"\n";
}
} catch (Exception ex) {
ex.printStackTrace();
}
return contents.trim();
}
public static String getFile (String filename) {
String contents = "";
try {
File file = new File(filename);
if (file.exists()) {
//log.info("Found file "+filename);
FileInputStream fstream = new FileInputStream(filename);
// Get the object
contents = getFileFromInputStream(fstream) ;
fstream.close();
}
} catch (Exception e){//Catch exception if any
// log.error("Cannot get file '" + filename + "': " + e, e);
}
//log.info("getFile: "+contents);
return contents;
}
public static String getCopyrightFromInputStream(InputStream in) {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
//Read File Line By Line
String copyright = "";
try {
while ((strLine = br.readLine()) != null) {
if (strLine.length() == 0) copyright += "\n";
else copyright += "<!-- "+strLine+" -->\n";
}
} catch (Exception ex) {
ex.printStackTrace();
}
return copyright;
}
public static String getCopyright (Bot bot, String AIMLFilename) {
String copyright = "";
String year = CalendarUtils.year();
String date = CalendarUtils.date();
try {
copyright = getFile(MagicStrings.config_path+"/copyright.txt") ;
String[] splitCopyright = copyright.split("\n");
copyright = "";
for (int i = 0; i < splitCopyright.length; i++) {
copyright += "<!-- "+splitCopyright[i]+" -->\n";
}
copyright = copyright.replace("[url]", bot.properties.get("url"));
copyright = copyright.replace("[date]", date);
copyright = copyright.replace("[YYYY]", year);
copyright = copyright.replace("[version]", bot.properties.get("version"));
copyright = copyright.replace("[botname]", bot.name.toUpperCase());
copyright = copyright.replace("[filename]", AIMLFilename);
copyright = copyright.replace("[botmaster]", bot.properties.get("botmaster"));
copyright = copyright.replace("[organization]", bot.properties.get("organization"));
} catch (Exception e){//Catch exception if any
// log.error("Cannot get copyright from '" + AIMLFilename + "': " + e, e);
}
//log.info("Copyright: "+copyright);
return copyright;
}
public static String getPannousAPIKey () {
String apiKey = getFile(MagicStrings.config_path+"/pannous-apikey.txt");
if (apiKey.equals("")) apiKey = MagicStrings.pannous_api_key;
return apiKey;
}
public static String getPannousLogin () {
String login = getFile(MagicStrings.config_path+"/pannous-login.txt");
if (login.equals("")) login = MagicStrings.pannous_login;
return login;
}
/**
* Returns if a character is one of Chinese-Japanese-Korean characters.
*
* @param c
* the character to be tested
* @return true if CJK, false otherwise
*/
public static boolean isCharCJK(final char c) {
if ((Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS)
|| (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A)
|| (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B)
|| (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS)
|| (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS)
|| (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_RADICALS_SUPPLEMENT)
|| (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION)
|| (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.ENCLOSED_CJK_LETTERS_AND_MONTHS)) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,177 @@
package org.alicebot.ab.cli;
/* Program AB Reference AIML 2.0 implementation
Copyright (C) 2013 ALICE A.I. Foundation
Contact: info@alicebot.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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.
*/
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import org.alicebot.ab.AB;
import org.alicebot.ab.AIMLProcessor;
import org.alicebot.ab.Bot;
import org.alicebot.ab.Category;
import org.alicebot.ab.Chat;
import org.alicebot.ab.Graphmaster;
import org.alicebot.ab.MagicBooleans;
import org.alicebot.ab.MagicStrings;
import org.alicebot.ab.PCAIMLProcessorExtension;
import org.alicebot.ab.Timer;
import org.alicebot.ab.utils.IOUtils;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
public class Main {
// private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main (String[] args) {
MagicStrings.root_path = System.getProperty("user.dir");
// log.info("Working Directory = " + MagicStrings.root_path);
AIMLProcessor.extension = new PCAIMLProcessorExtension();
mainFunction(args);
}
public static void mainFunction (String[] args) {
String botName = "super";
String action = "chat";
// log.info(MagicStrings.programNameVersion);
for (String s : args) {
// log.info(s);
String[] splitArg = s.split("=");
if (splitArg.length >= 2) {
String option = splitArg[0];
String value = splitArg[1];
if (option.equals("bot")) botName = value;
if (option.equals("action")) action = value;
if (option.equals("trace") && value.equals("true")) MagicBooleans.trace_mode = true;
else MagicBooleans.trace_mode = false;
}
}
// log.info("trace mode = "+MagicBooleans.trace_mode);
Graphmaster.enableShortCuts = true;
Timer timer = new Timer();
Bot bot = new Bot(botName, MagicStrings.root_path, action); //
//bot.preProcessor.normalizeFile("c:/ab/log1.txt", "c:/ab/data/lognormal.txt");
if (bot.brain.getCategories().size() < 100) bot.brain.printgraph();
if (action.equals("chat")) testChat(bot, MagicBooleans.trace_mode);
else if (action.equals("test")) testSuite(bot, MagicStrings.root_path+"/data/find.txt");
else if (action.equals("ab")) testAB(bot);
else if (action.equals("aiml2csv") || action.equals("csv2aiml")) convert(bot, action);
else if (action.equals("abwq")) AB.abwq(bot);
}
public static void convert(Bot bot, String action) {
if (action.equals("aiml2csv")) bot.writeAIMLIFFiles();
else if (action.equals("csv2aiml")) bot.writeAIMLFiles();
}
public static void testAB (Bot bot) {
MagicBooleans.trace_mode = true;
AB.ab(bot);
AB.terminalInteraction(bot) ;
}
public static void testShortCuts () {
//testChat(new Bot("alice"));
//Graphmaster.enableShortCuts = false;
//Bot bot = new Bot("alice");
//bot.brain.printgraph();
//bot.brain.nodeStats();
//Graphmaster.enableShortCuts = true;
//bot = new Bot("alice");
//bot.brain.printgraph();
//bot.brain.nodeStats();
}
public static void testChat (Bot bot, boolean traceMode) {
Chat chatSession = new Chat(bot);
// bot.preProcessor.normalizeFile("c:/ab/bots/super/aiml/thats.txt", "c:/ab/bots/super/aiml/normalthats.txt");
bot.brain.nodeStats();
MagicBooleans.trace_mode = traceMode;
String textLine="";
while (true) {
System.out.print("Human: ");
textLine = IOUtils.readInputTextLine();
if (textLine == null || textLine.length() < 1) textLine = MagicStrings.null_input;
if (textLine.equals("q")) System.exit(0);
else if (textLine.equals("wq")) {
bot.writeQuit();
System.exit(0);
}
else if (textLine.equals("ab")) testAB(bot);
else {
String request = textLine;
// log.debug("STATE="+request+":THAT="+chatSession.thatHistory.get(0).get(0)+":TOPIC="+chatSession.predicates.get("topic"));
String response = chatSession.multisentenceRespond(request);
while (response.contains("&lt;")) response = response.replace("&lt;","<");
while (response.contains("&gt;")) response = response.replace("&gt;",">");
// log.info("Robot: "+response);
}
}
}
public static void testBotChat () {
Bot bot = new Bot("alice");
// log.info(bot.brain.upgradeCnt+" brain upgrades");
bot.brain.nodeStats();
//bot.brain.printgraph();
Chat chatSession = new Chat(bot);
String request = "Hello. How are you? What is your name? Tell me about yourself.";
String response = chatSession.multisentenceRespond(request);
// log.info("Human: "+request);
// log.info("Robot: "+response);
}
public static void testSuite (Bot bot, String filename) {
try{
AB.passed.readAIMLSet(bot);
AB.testSet.readAIMLSet(bot);
// log.info("Passed "+AB.passed.size()+" samples.");
String textLine="";
Chat chatSession = new Chat(bot);
FileInputStream fstream = new FileInputStream(filename);
// Get the object
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
//Read File Line By Line
int count = 0;
HashSet<String> samples = new HashSet<String>();
while ((strLine = br.readLine())!= null) {
samples.add(strLine);
}
ArrayList<String> sampleArray = new ArrayList<String>(samples);
Collections.sort(sampleArray);
for (String request : sampleArray) {
if (request.startsWith("Human: ")) request = request.substring("Human: ".length(), request.length());
Category c = new Category(0, bot.preProcessor.normalize(request), "*", "*", MagicStrings.blank_template, MagicStrings.null_aiml_file);
if (AB.passed.contains(request)) ;
else if (!bot.deletedGraph.existsCategory(c) && !AB.passed.contains(request)) {
String response = chatSession.multisentenceRespond(request);
// log.info(count+". Human: "+request);
// log.info(count+". Robot: "+response);
textLine = IOUtils.readInputTextLine();
AB.terminalInteractionStep(bot, request, textLine, c);
count += 1;
}
}
//Close the input stream
br.close();
} catch (Exception e){//Catch exception if any
// log.error("testSuite Error: " + e, e);
}
}
}

View File

@ -0,0 +1,57 @@
package org.alicebot.ab.utils;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
public class CalendarUtils {
//private static final Logger log = LoggerFactory.getLogger(CalendarUtils.class);
public static int timeZoneOffset() {
Calendar cal = Calendar.getInstance();
int offset = (cal.get(Calendar.ZONE_OFFSET)+cal.get(Calendar.DST_OFFSET))/(60*1000);
return offset;
}
public static String year() {
Calendar cal = Calendar.getInstance();
return String.valueOf(cal.get(Calendar.YEAR));
}
public static String date() {
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
SimpleDateFormat dateFormat = new SimpleDateFormat("MMMMMMMMM dd, yyyy");
dateFormat.setCalendar(cal);
return dateFormat.format(cal.getTime());
}
public static String date(String jformat, String locale, String timezone) {
//HashSet<String> attributeNames = Utilities.stringSet("jformat","format","locale","timezone");
if (jformat == null) jformat = "EEE MMM dd HH:mm:ss zzz yyyy";
if (locale == null) locale = Locale.US.getISO3Country();
if (timezone == null) timezone = TimeZone.getDefault().getDisplayName();
//log.info("Format = "+format+" Locale = "+locale+" Timezone = "+timezone);
String dateAsString = new Date().toString();
try {
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat(jformat);
dateAsString = simpleDateFormat.format(new Date());
}
catch (Exception ex) {
// log.info("CalendarUtils.date Bad date: Format = {} Locale = {} Timezone = {}",
// jformat, locale, timezone);
}
// log.info("CalendarUtils.date: {}", dateAsString);
return dateAsString;
}
}

View File

@ -0,0 +1,71 @@
package org.alicebot.ab.utils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
public class DomUtils {
//private static final Logger log = LoggerFactory.getLogger(DomUtils.class);
public static Node parseFile(String fileName) throws Exception {
File file = new File(fileName);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
// from AIMLProcessor.evalTemplate and AIMLProcessor.validTemplate:
// dbFactory.setIgnoringComments(true); // fix this
Document doc = dBuilder.parse(file);
doc.getDocumentElement().normalize();
Node root = doc.getDocumentElement();
return root;
}
public static Node parseString(String string) throws Exception {
InputStream is = new ByteArrayInputStream(string.getBytes("UTF-16"));
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
// from AIMLProcessor.evalTemplate and AIMLProcessor.validTemplate:
// dbFactory.setIgnoringComments(true); // fix this
Document doc = dBuilder.parse(is);
doc.getDocumentElement().normalize();
Node root = doc.getDocumentElement();
return root;
}
/**
* convert an XML node to an XML statement
* @param node current XML node
* @return XML string
*/
public static String nodeToString(Node node) {
StringWriter sw = new StringWriter();
try {
Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
t.setOutputProperty(OutputKeys.INDENT, "no");
t.transform(new DOMSource(node), new StreamResult(sw));
} catch (TransformerException te) {
// log.error("nodeToString Transformer Exception: " + te, te);
}
return sw.toString();
}
}

View File

@ -0,0 +1,48 @@
package org.alicebot.ab.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
public class IOUtils {
//private static final Logger log = LoggerFactory.getLogger(IOUtils.class);
public static String readInputTextLine() {
BufferedReader lineOfText = new BufferedReader(new InputStreamReader(System.in));
String textLine = null;
try {
textLine = lineOfText.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return textLine;
}
public static String system(String evaluatedContents, String failedString) {
Runtime rt = Runtime.getRuntime();
// log.info("System {}", evaluatedContents);
try {
Process p = rt.exec(evaluatedContents);
InputStream istrm = p.getInputStream();
InputStreamReader istrmrdr = new InputStreamReader(istrm);
BufferedReader buffrdr = new BufferedReader(istrmrdr);
String result = "";
String data = "";
while ((data = buffrdr.readLine()) != null) {
result += data+"\n";
}
// log.info("Result = {}", result);
return result;
} catch (Exception ex) {
ex.printStackTrace();
return failedString;
}
}
}

View File

@ -0,0 +1,20 @@
package org.alicebot.ab.utils;
public class MemoryUtils {
public static long totalMemory() {
return Runtime.getRuntime().totalMemory();
}
public static long maxMemory() {
return Runtime.getRuntime().maxMemory();
}
public static long freeMemory() {
return Runtime.getRuntime().freeMemory();
}
}

View File

@ -0,0 +1,81 @@
package org.alicebot.ab.utils;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URI;
import java.net.URLEncoder;
import java.util.Enumeration;
//import org.apache.http.client.HttpClient;
//import org.apache.http.client.methods.HttpGet;
//import org.apache.http.impl.client.DefaultHttpClient;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
public class NetworkUtils {
//private static final Logger log = LoggerFactory
//.getLogger(NetworkUtils.class);
public static String localIPAddress() {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()) {
String ipAddress = inetAddress.getHostAddress().toString();
int p = ipAddress.indexOf("%");
if (p > 0) ipAddress = ipAddress.substring(0, p);
// log.info("--> localIPAddress = {}", ipAddress);
return ipAddress;
}
}
}
} catch (SocketException ex) {
ex.printStackTrace();
}
return "127.0.0.1";
}
public static String responseContent(String url) throws Exception {
//HttpClient client = new DefaultHttpClient();
//HttpGet request = new HttpGet();
//request.setURI(new URI(url));
// InputStream is = client.execute(request).getEntity().getContent();
//BufferedReader inb = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder("");
String line;
String NL = System.getProperty("line.separator");
// while ((line = inb.readLine()) != null) {
// sb.append(line).append(NL);
// }
// inb.close();
return sb.toString();
}
public static String spec(String host, String botid, String custid, String input) {
// log.trace("--> custid = {}", custid);
String spec = "";
if (custid.equals("0")) // get custid on first transaction with Pandorabots
spec = String.format("%s?botid=%s&input=%s",
"http://" + host + "/pandora/talk-xml",
botid,
URLEncoder.encode(input));
else spec = // re-use custid on each subsequent interaction
String.format("%s?botid=%s&custid=%s&input=%s",
"http://" + host + "/pandora/talk-xml",
botid,
custid,
URLEncoder.encode(input));
return spec;
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:drawable="@color/colorPrimary"/>
<item>
<bitmap
android:gravity="center"
android:src="@drawable/splash"/>
</item>
</layer-list>

View File

@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>

View File

@ -0,0 +1,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/gobutton_pressed"/>
<item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/gobutton_pressed"/>
<item android:state_focused="true" android:drawable="@drawable/gobutton_selected"/>
<item android:state_focused="false" android:state_pressed="false" android:drawable="@drawable/gobutton"/>
</selector>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DisplayMessageActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout4"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:focusableInTouchMode="true"
tools:context="com.fpghoti.androidbotinterface.MainActivity">
<TextView
android:id="@+id/output"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="16dp"
app:layout_constraintBottom_toTopOf="@+id/linearLayout3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linearLayout3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#fff"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/output">
<EditText
android:id="@+id/editText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:ems="10"
android:hint="Say Something!"
android:inputType="text"
android:paddingHorizontal="10dp"
android:text=""
app:layout_constraintEnd_toStartOf="@+id/imageButton2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/imageButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/sendbutton"
android:onClick="sendMessage"
android:padding="20dp"
android:scaleType="fitCenter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/editText"
app:layout_constraintTop_toTopOf="@+id/editText" />
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
</resources>

View File

@ -0,0 +1,7 @@
<resources>
<string name="app_name">Android Bot Interface</string>
<string name="edit_message">Enter a message</string>
<string name="button_send">Send</string>
<string name="EXTRA_MESSAGE"></string>
<string name="more_extra">Say Hello!</string>
</resources>

View File

@ -0,0 +1,15 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">@drawable/background_splash</item>
</style>
</resources>

View File

@ -0,0 +1,17 @@
package com.fpghoti.androidbotinterface;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

27
build.gradle Normal file
View File

@ -0,0 +1,27 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

15
gradle.properties Normal file
View File

@ -0,0 +1,15 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

172
gradlew vendored Normal file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
gradlew.bat vendored Normal file
View File

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

1
settings.gradle Normal file
View File

@ -0,0 +1 @@
include ':app'