diff -r 1d6e762433fe -r 0acb8d9a3194 eliza.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eliza.php Mon Aug 25 12:34:26 2008 -0400 @@ -0,0 +1,626 @@ + + * @author Dan Fuhry + * @copyright (c) 1997-2008 George Dunlop. All rights reserved, portions copyright (C) 2008 Dan Fuhry. + */ + +class Psychotherapist +{ + private $maxKey = 36; + private $keyNotFound = 0; + private $keyword = array(); + private $maxresponses = 116; + private $response = array(); + + private $maxConj = 19; + private $max2ndConj = 7; + + private $conj1 = Array(); + private $conj2 = Array(); + private $conj3 = Array(); + private $conj4 = Array(); + + private $punct = Array(".", ",", "!", "?", ":", ";", "&", '"', "@", "#", "(", ")" ); + + /** + * Constructor. + */ + + public function __construct() + { + $this->keyNotFound = $this->maxKey - 1; + $this->keyword = $this->create_array($this->maxKey); + $this->response = $this->create_array($this->maxresponses); + $this->conj1 = $this->create_array($this->maxConj); + $this->conj2 = $this->create_array($this->maxConj); + $this->conj3 = $this->create_array($this->max2ndConj); + $this->conj4 = $this->create_array($this->max2ndConj); + + $this->table_setup(); + } + + /** + * Replacement for str_replace that provides more options. + * if type == 0 straight string replacement + * if type == 1 assumes padded strings and replaces whole words only + * if type == 2 non case sensitive assumes padded strings to compare whole word only + * if type == 3 non case sensitive straight string replacement + * @param string Haystack + * @param string Needle + * @param string Replacement + * @param int Mode - defaults to 0 + */ + + private function replaceStr($strng, $substr1, $substr2, $type = 0) + { + if ( $type == 0 ) + { + return str_replace($substr1, $substr2, $strng); + } + else if ( $type == 1 ) + { + return str_replace(" $substr1 ", " $substr2 ", $strng); + } + else if ( $type == 2 || $type == 3 ) + { + if ( $type == 2 ) + { + $substr1 = " $substr1 "; + $substr2 = " $substr2 "; + } + return preg_replace('/' . preg_quote($substr1) . '/i', $substr2, $strng); + } + else + { + throw new Exception("Invalid parameter"); + } + } + + /** + * Function to pad a string. head, tail & punctuation + * @param string + * @return string + */ + + private function padString($strng) + { + $punct =& $this->punct; + + $aString = " " . $strng . " "; + for ( $i = 0; $i < count($punct); $i++ ) + { + $aString = $this->replaceStr( $aString, $punct[$i], " " . $punct[$i] . " ", 0 ); + } + return $aString; + } + + /** + * Function to strip padding + */ + + private function unpadString($strng) + { + $punct =& $this->punct; + + $aString = $strng; + $aString = $this->replaceStr( $aString, " ", " ", 0 ); // compress spaces + + $aString = trim($aString, ' '); + + for ( $i = 0; $i < count($punct); $i++ ) + { + $aString = $this->replaceStr( $aString, " " . $punct[$i], $punct[$i], 0 ); + } + return $aString; + } + + /** + * Dress Input formatting i.e leading & trailing spaces and tail punctuation + * @param string + * @return string + */ + + function strTrim($strng) + { + static $ht = 0; + + if ( $ht == 0 ) + { + $loc = 0; + } // head clip + else + { + $loc = strlen($strng) - 1; + } // tail clip ht = 1 + if ( substr($strng, $loc, 1) == " " ) + { + $aString = substr($strng, - ( $ht - 1 ), strlen($strng) - $ht); + $aString = $this->strTrim($aString); + } + else + { + $flg = false; + for ( $i = 0; $i <= 5; $i++ ) + { + $flg = $flg || ( substr($strng, $loc, 1) == $this->punct[$i]); + } + if ( $flg ) + { + $aString = substr($strng, - ( $ht - 1 ), strlen($strng) - $ht); + } + else + { + $aString = $strng; + } + if ( $aString != $strng ) + { + $aString = $this->strTrim($aString); + } + } + if ( $ht == 0 ) + { + $ht = 1; + $aString = $this->strTrim($aString); + } + else + { + $ht = 0; + } + return $aString; + } + + /** + * adjust pronouns and verbs & such + * @param string + * @return string + */ + + private function conjugate($sStrg) + { + $sString = $sStrg; + for ( $i = 0; $i < $this->maxConj; $i++ ) + { // decompose + $sString = $this->replaceStr( $sString, $this->conj1[$i], "#@&" . $i, 2 ); + } + for( $i = 0; $i < $this->maxConj; $i++ ) + { // recompose + $sString = $this->replaceStr( $sString, "#@&" . $i, $this->conj2[$i], 2 ); + } + // post process the resulting string + for( $i = 0; $i < $this->max2ndConj; $i++ ) + { // decompose + $sString = $this->replaceStr( $sString, $this->conj3[$i], "#@&" . $i, 2 ); + } + for( $i = 0; $i < $this->max2ndConj; $i++ ) + { // recompose + $sString = $this->replaceStr( $sString, "#@&" . $i, $this->conj4[$i], 2 ); + } + return $sString; + } + + /** + * Build our response string + * get a random choice of response based on the key + * Then structure the response + * @param string + * @param int Key index + * @return string + */ + + function phrase( $sString, $keyidx ) + { + $idxmin = $this->keyword[$keyidx]->idx; + $idrange = $this->keyword[$keyidx]->end - $idxmin + 1; + while ( $pass < 5 ) + { + $choice = $this->keyword[$keyidx]->idx + mt_rand(0, $idrange); + if ( $choice == $this->keyword[$keyidx]->last ) + { + $pass++; + continue; + } + break; + } + $this->keyword[$keyidx]->last = $choice; + $rTemp = $this->response[$choice]; + $tempt = substr($rTemp, strlen($rTemp) - 1, 1); + if ( ( $tempt == "*" ) || ( $tempt == "@" ) ) + { + $sTemp = $this->padString($sString); + $wTemp = strtoupper($sTemp); + $strpstr = intval(strpos($wTemp, " {$this->keyword[$keyidx]->key} ")); + + $strpstr += strlen($this->keyword[$keyidx]->key) + 1; + $thisstr = $this->conjugate( substr($sTemp, $strpstr, strlen($sTemp)) ); + $thisstr = $this->strTrim( $this->unpadString($thisstr) ); + if( $tempt == "*" ) + { + $sTemp = $this->replaceStr( $rTemp, "<*", " " . $thisstr . "?", 0 ); + } + else + { + $sTemp = $this->replaceStr( $rTemp, "<@", " " . $thisstr . ".", 0 ); + } + } + else + { + $sTemp = $rTemp; + } + return $sTemp; + } + + /** + * returns array index of first key found + * @param string + */ + + private function testkey($wString) + { + for ( $keyid = 0; $keyid < count($this->keyword); $keyid++ ) + { + if ( strpos($wString, " {$this->keyword[$keyid]->key} ") !== false ) + { + return $keyid; + } + } + return false; + } + + /** + * + */ + + private function findkey($wString) + { + $keyid = $this->testkey($wString); + if( !$keyid ) + { + $keyid = $this->keyNotFound; + } + return $keyid; + } + + /** + * Process a line from the user. + * @param string User input + * @return string AI output + */ + + function listen($User) + { + static $wTopic = ""; // Last worthy responce + static $sTopic = ""; // Last worthy responce + static $greet = false; + static $wPrevious = ""; // so we can check for repeats + + $sInput = $User; + $sInput = $this->strTrim($sInput); // dress input formating + + if ( $sInput != "" ) + { + $wInput = $this->padString(strtoupper($sInput)); // Work copy + $foundkey = $this->maxKey; // assume it's a repeat input + if ( $wInput != $wPrevious ) + { // check if user repeats himself + $foundkey = $this->findkey($wInput); // look for a keyword. + } + if( $foundkey == $this->keyNotFound ) + { + if( !$greet ) + { + $greet = true; + return "Don't you ever say Hello?"; + } + else + { + $wPrevious = $wInput; // save input to check repeats + if (( strlen($sInput) < 10 ) && ( $wTopic != "" ) && ( $wTopic != $wPrevious )) + { + $lTopic = $this->conjugate( $sTopic ); + $sTopic = ""; + $wTopic = ""; + return 'OK... "' + $lTopic + '". Tell me more.'; + } + else + { + if ( strlen($sInput) < 15 ) + { + return "Tell me more..."; + } + else + { + return $this->phrase( $sInput, $foundkey ); + } + } + } + } + else + { + if ( strlen($sInput) > 12 ) + { + $sTopic = $sInput; + $wTopic = $wInput; + } + $greet = true; + $wPrevious = $wInput; // save input to check repeats + return $this->phrase( $sInput, $foundkey ); // Get our response + } + } + else + { + return "I can't help if you will not chat with me!"; + } + } + + /** + * Creates an array of the specified length, and fills it with null values. + * @param int Array size + * @return array + */ + + function create_array($len) + { + $ret = array(); + for ( $i = 0; $i < $len; $i++ ) + { + $ret[] = null; + } + return $ret; + } + + /** + * Sets up the tables of phrases, etc. + */ + + private function table_setup() + { + // build our data base here + + $this->conj1[0] = "are"; $this->conj2[0] = "am"; + $this->conj1[1] = "am"; $this->conj2[1] = "are"; + $this->conj1[2] = "were"; $this->conj2[2] = "was"; + $this->conj1[3] = "was"; $this->conj2[3] = "were"; + $this->conj1[4] = "I"; $this->conj2[4] = "you"; + $this->conj1[5] = "me"; $this->conj2[5] = "you"; + $this->conj1[6] = "you"; $this->conj2[6] = "me"; + $this->conj1[7] = "my"; $this->conj2[7] = "your"; + $this->conj1[8] = "your"; $this->conj2[8] = "my"; + $this->conj1[9] = "mine"; $this->conj2[9] = "your's"; + $this->conj1[10] = "your's"; $this->conj2[10] = "mine"; + $this->conj1[11] = "I'm"; $this->conj2[11] = "you're"; + $this->conj1[12] = "you're"; $this->conj2[12] = "I'm"; + $this->conj1[13] = "I've"; $this->conj2[13] = "you've"; + $this->conj1[14] = "you've"; $this->conj2[14] = "I've"; + $this->conj1[15] = "I'll"; $this->conj2[15] = "you'll"; + $this->conj1[16] = "you'll"; $this->conj2[16] = "I'll"; + $this->conj1[17] = "myself"; $this->conj2[17] = "yourself"; + $this->conj1[18] = "yourself"; $this->conj2[18] = "myself"; + + // array to post process correct our tenses of pronouns such as "I/me" + + $this->conj3[0] = "me am"; $this->conj4[0] = "I am"; + $this->conj3[1] = "am me"; $this->conj4[1] = "am I"; + $this->conj3[2] = "me can"; $this->conj4[2] = "I can"; + $this->conj3[3] = "can me"; $this->conj4[3] = "can I"; + $this->conj3[4] = "me have"; $this->conj4[4] = "I have"; + $this->conj3[5] = "me will"; $this->conj4[5] = "I will"; + $this->conj3[6] = "will me"; $this->conj4[6] = "will I"; + + + // Keywords + + $this->keyword[ 0]=new Psychotherapist_Key( "CAN YOU", 1, 3); + $this->keyword[ 1]=new Psychotherapist_Key( "CAN I", 4, 5); + $this->keyword[ 2]=new Psychotherapist_Key( "YOU ARE", 6, 9); + $this->keyword[ 3]=new Psychotherapist_Key( "YOU'RE", 6, 9); + $this->keyword[ 4]=new Psychotherapist_Key( "I DON'T", 10, 13); + $this->keyword[ 5]=new Psychotherapist_Key( "I FEEL", 14, 16); + $this->keyword[ 6]=new Psychotherapist_Key( "WHY DON'T YOU", 17, 19); + $this->keyword[ 7]=new Psychotherapist_Key( "WHY CAN'T I", 20, 21); + $this->keyword[ 8]=new Psychotherapist_Key( "ARE YOU", 22, 24); + $this->keyword[ 9]=new Psychotherapist_Key( "I CAN'T", 25, 27); + $this->keyword[10]=new Psychotherapist_Key( "I AM", 28, 31); + $this->keyword[11]=new Psychotherapist_Key( "I'M", 28, 31); + $this->keyword[12]=new Psychotherapist_Key( "YOU", 32, 34); + $this->keyword[13]=new Psychotherapist_Key( "I WANT", 35, 39); + $this->keyword[14]=new Psychotherapist_Key( "WHAT", 40, 48); + $this->keyword[15]=new Psychotherapist_Key( "HOW", 40, 48); + $this->keyword[16]=new Psychotherapist_Key( "WHO", 40, 48); + $this->keyword[17]=new Psychotherapist_Key( "WHERE", 40, 48); + $this->keyword[18]=new Psychotherapist_Key( "WHEN", 40, 48); + $this->keyword[19]=new Psychotherapist_Key( "WHY", 40, 48); + $this->keyword[20]=new Psychotherapist_Key( "NAME", 49, 50); + $this->keyword[21]=new Psychotherapist_Key( "CAUSE", 51, 54); + $this->keyword[22]=new Psychotherapist_Key( "SORRY", 55, 58); + $this->keyword[23]=new Psychotherapist_Key( "DREAM", 59, 62); + $this->keyword[24]=new Psychotherapist_Key( "HELLO", 63, 63); + $this->keyword[25]=new Psychotherapist_Key( "HI", 63, 63); + $this->keyword[26]=new Psychotherapist_Key( "MAYBE", 64, 68); + $this->keyword[27]=new Psychotherapist_Key( "NO", 69, 73); + $this->keyword[28]=new Psychotherapist_Key( "YOUR", 74, 75); + $this->keyword[29]=new Psychotherapist_Key( "ALWAYS", 76, 79); + $this->keyword[30]=new Psychotherapist_Key( "THINK", 80, 82); + $this->keyword[31]=new Psychotherapist_Key( "ALIKE", 83, 89); + $this->keyword[32]=new Psychotherapist_Key( "YES", 90, 92); + $this->keyword[33]=new Psychotherapist_Key( "FRIEND", 93, 98); + $this->keyword[34]=new Psychotherapist_Key( "COMPUTER", 99, 105); + $this->keyword[35]=new Psychotherapist_Key( "NO KEY FOUND", 106, 112); + $this->keyword[36]=new Psychotherapist_Key( "REPEAT INPUT", 113, 116); + + + $this->response[ 0]="ELIZA - PHP version ported from Javascript (George Dunlop) code by Dan Fuhry"; + $this->response[ 1]="Don't you believe that I can<*"; + $this->response[ 2]="Perhaps you would like to be able to<*"; + $this->response[ 3]="You want me to be able to<*"; + $this->response[ 4]="Perhaps you don't want to<*"; + $this->response[ 5]="Do you want to be able to<*"; + $this->response[ 6]="What makes you think I am<*"; + $this->response[ 7]="Does it please you to believe I am<*"; + $this->response[ 8]="Perhaps you would like to be<*"; + $this->response[ 9]="Do you sometimes wish you were<*"; + $this->response[ 10]="Don't you really<*"; + $this->response[ 11]="Why don't you<*"; + $this->response[ 12]="Do you wish to be able to<*"; + $this->response[ 13]="Does that trouble you?"; + $this->response[ 14]="Tell me more about such feelings."; + $this->response[ 15]="Do you often feel<*"; + $this->response[ 16]="Do you enjoy feeling<*"; + $this->response[ 17]="Do you really believe I don't<*"; + $this->response[ 18]="Perhaps in good time I will<@"; + $this->response[ 19]="Do you want me to<*"; + $this->response[ 20]="Do you think you should be able to<*"; + $this->response[ 21]="Why can't you<*"; + $this->response[ 22]="Why are you interested in whether or not I am<*"; + $this->response[ 23]="Would you prefer if I were not<*"; + $this->response[ 24]="Perhaps in your fantasies I am<*"; + $this->response[ 25]="How do you know you can't<*"; + $this->response[ 26]="Have you tried?"; + $this->response[ 27]="Perhaps you can now<*"; + $this->response[ 28]="Did you come to me because you are<*"; + $this->response[ 29]="How long have you been<*"; + $this->response[ 30]="Do you believe it is normal to be<*"; + $this->response[ 31]="Do you enjoy being<*"; + $this->response[ 32]="We were discussing you, not me."; + $this->response[ 33]="Oh... <*"; + $this->response[ 34]="You're not really talking about me, are you?"; + $this->response[ 35]="What would it mean to you if you got<*"; + $this->response[ 36]="Why do you want<*"; + $this->response[ 37]="Suppose you got<*"; + $this->response[ 38]="What if you never got<*"; + $this->response[ 39]="I sometimes also want<@"; + $this->response[ 40]="Why do you ask?"; + $this->response[ 41]="Does that question interest you?"; + $this->response[ 42]="What answer would please you the most?"; + $this->response[ 43]="What do you think?"; + $this->response[ 44]="Are such questions on your mind often?"; + $this->response[ 45]="What is it that you really want to know?"; + $this->response[ 46]="Have you asked anyone else?"; + $this->response[ 47]="Have you asked such questions before?"; + $this->response[ 48]="What else comes to mind when you ask that?"; + $this->response[ 49]="Names don't interest me."; + $this->response[ 50]="I don't care about names, please go on."; + $this->response[ 51]="Is that the real reason?"; + $this->response[ 52]="Don't any other reasons come to mind?"; + $this->response[ 53]="Does that reason explain anything else?"; + $this->response[ 54]="What other reasons might there be?"; + $this->response[ 55]="Please don't apologise!"; + $this->response[ 56]="Apologies are not necessary."; + $this->response[ 57]="What feelings do you have when you apologise?"; + $this->response[ 58]="Don't be so defensive!"; + $this->response[ 59]="What does that dream suggest to you?"; + $this->response[ 60]="Do you dream often?"; + $this->response[ 61]="What persons appear in your dreams?"; + $this->response[ 62]="Are you disturbed by your dreams?"; + $this->response[ 63]="How are you today.. What would you like to discuss?"; + $this->response[ 64]="You don't seem quite certain."; + $this->response[ 65]="Why the uncertain tone?"; + $this->response[ 66]="Can't you be more positive?"; + $this->response[ 67]="You aren't sure?"; + $this->response[ 68]="Don't you know?"; + $this->response[ 69]="Are you saying no just to be negative?"; + $this->response[ 70]="You are being a bit negative."; + $this->response[ 71]="Why not?"; + $this->response[ 72]="Are you sure?"; + $this->response[ 73]="Why no?"; + $this->response[ 74]="Why are you concerned about my<*"; + $this->response[ 75]="What about your own<*"; + $this->response[ 76]="Can you think of a specific example?"; + $this->response[ 77]="When?"; + $this->response[ 78]="What are you thinking of?"; + $this->response[ 79]="Really, always?"; + $this->response[ 80]="Do you really think so?"; + $this->response[ 81]="But you are not sure you<*"; + $this->response[ 82]="Do you doubt you<*"; + $this->response[ 83]="In what way?"; + $this->response[ 84]="What resemblence do you see?"; + $this->response[ 85]="What does the similarity suggest to you?"; + $this->response[ 86]="What other connections do you see?"; + $this->response[ 87]="Could there really be some connection?"; + $this->response[ 88]="How?"; + $this->response[ 89]="You seem quite positive."; + $this->response[ 90]="Are you Sure?"; + $this->response[ 91]="I see."; + $this->response[ 92]="I understand."; + $this->response[ 93]="Why do you bring up the topic of friends?"; + $this->response[ 94]="Do your friends worry you?"; + $this->response[ 95]="Do your friends pick on you?"; + $this->response[ 96]="Are you sure you have any friends?"; + $this->response[ 97]="Do you impose on your friends?"; + $this->response[ 98]="Perhaps your love for friends worries you."; + $this->response[ 99]="Do computers worry you?"; + $this->response[100]="Are you talking about me in particular?"; + $this->response[101]="Are you frightened by machines?"; + $this->response[102]="Why do you mention computers?"; + $this->response[103]="What do you think machines have to do with your problems?"; + $this->response[104]="Don't you think computers can help people?"; + $this->response[105]="What is it about machines that worries you?"; + $this->response[106]="Say, do you have any psychological problems?"; + $this->response[107]="What does that suggest to you?"; + $this->response[108]="I see."; + $this->response[109]="I'm not sure I understand you fully."; + $this->response[110]="Come, come, elucidate your thoughts."; + $this->response[111]="Can you elaborate on that?"; + $this->response[112]="That is quite interesting."; + $this->response[113]="Why did you repeat yourself?"; + $this->response[114]="Do you expect a different answer by repeating yourself?"; + $this->response[115]="Come, come, elucidate your thoughts."; + $this->response[116]="Please don't repeat yourself!"; + } + +} + +/** + * Keyword class + */ + +class Psychotherapist_Key +{ + /** + * Phrase to match + * @var string + */ + + public $key = ''; + + /** + * First response to use + * @var int + */ + + public $idx = 0; + + /** + * Last response to use + * @var int + */ + + public $end = 0; + + /** + * Response last used time + * @var int + */ + + public $last = 0; + + /** + * Constructor. + * @param string Key + * @param int Index + * @param int End + */ + + public function __construct($key, $idx, $end) + { + $this->key = $key; + $this->idx = $idx; + $this->end = $end; + } +} + +