Initial commit
|
@ -0,0 +1,2 @@
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1 @@
|
||||||
|
/build
|
|
@ -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')
|
||||||
|
}
|
|
@ -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
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
After Width: | Height: | Size: 19 KiB |
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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";
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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++;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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("'","'");
|
||||||
|
text = text.replace("'","'");
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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("<")) response = response.replace("<","<");
|
||||||
|
while (response.contains(">")) response = response.replace(">",">");
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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>
|
|
@ -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>
|
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.5 KiB |
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 12 KiB |
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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" "$@"
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
include ':app'
|