News:

Welcome to RetroCoders Community

Main Menu

Chatbot in C

Started by ron77, Jun 08, 2023, 11:43 PM

Previous topic - Next topic

ron77

Here is the beginning of my Chatbot in C project:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>

char* keys1[] = {
	"hi",
	"hello",
	"good day",
	"goodbye",
	"bye"
}; // 0 - 4

char* replies1[] = {
	"hello good day to you",
	"hi nice to talk to you how hare you?",
	"thanks for talking with me i hope you have a good day",
	"okay goodbye dear friend",
	"thank you for talking with me"
}; // 0 - 4

char* defualt[] = {
	"i see please go on",
	"that is interesting...",
	"i'm listening please go on",
	"i don't quite understand can you explain further",
	"and how do you feel about it?",
	"what do you think about it really?"
}; // 0 - 5

bool checkInput(char* keywords[], const char* substring, int index) {
	bool isFound = false;
	for (int i = 0 ; i < index; i++) {
		if (strstr(keywords[i], substring) != NULL) {
			isFound = true;
			break;
		}	
	}
	return isFound;
}

char* botBrain(const char* input) {
	srand ( (unsigned int)time(NULL) );
	bool foundKey = checkInput(keys1, input, 4) ;
	char* output = NULL;
	if (foundKey) {
		
		int index = rand()%5;
		output = replies1[index];
	}else {
		int index = rand()%6;
		output = defualt[index];
	}
	return output;
}


int main() {
	char input[512];
	char* output = NULL;
	printf("hello to the simple chatbot program\n");
	while (strstr(input, "bye") == NULL) {
		fgets( input, 512, stdin ); // stores also the \n at the end of the input
		input[strcspn(input, "\n")] = 0; // removes the new line \n that fgets stores
		// gets(input);
		output = botBrain(input);
		printf("\nchatbot: %s\n", output );
	}
		printf("goodbye!!!");
		
	return 0;
	
}

ron77

ok few bugs fixes and added comments:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>

char* keys1[] = {
	"hi",
	"hello",
	"good day",
	"goodbye",
	"bye"
}; // 0 - 4

char* replies1[] = {
	"hello good day to you",
	"hi nice to talk to you how hare you?",
	"thanks for talking with me i hope you have a good day",
	"okay goodbye dear friend",
	"thank you for talking with me"
}; // 0 - 4

char* defualt[] = {
	"i see please go on",
	"that is interesting...",
	"i'm listening please go on",
	"i don't quite understand can you explain further",
	"and how do you feel about it?",
	"what do you think about it really?"
}; // 0 - 5

bool checkInput(char* keywords[], const char* input, int index) {  // index is array index + 1
	bool isFound = false;
	for (int i = 0 ; i < index; i++) {
		if (strstr(input, keywords[i]) != NULL) {   // input is the whole string keywords[i] is the substring we look for...
			isFound = true;
			break;
		}	
	}
	return isFound;
}

char* botBrain(const char* input) {
	srand ( (unsigned int)time(NULL) );
	// bool foundKey = checkInput(keys1, input, 4) ;
	char* output = NULL;
	if (checkInput(keys1, input, 5)) {
		int index = rand()%5;
		output = replies1[index];
	}else {
		int index = rand()%6;
		output = defualt[index];
	}
	return output;
}


int main() {
	char input[512];
	char* output = NULL;
	printf("hello to the simple chatbot program\n");
	while (strstr(input, "bye") == NULL) {
		fgets( input, 512, stdin ); // stores also the \n at the end of the input
		input[strcspn(input, "\n")] = 0; // removes the new line \n that fgets stores
		// gets(input);
		output = botBrain(input);
		printf("\nchatbot: %s\n", output );
	}
		printf("goodbye!!!");
		
	return 0;
	
}

ZXDunny

Way, way back in the day, I wrote a chatbot for my Amiga. It basically took in a string, tokenised it, and then built a dictionary from the tokens.

Whenever a word was added to the dictionary, I increased the probability of a link with the preceding token in the input stream and then when generating output, start with a random entry and choose the next most likely token to appear, based on those probabilities.

Although it mostly produced gibberish at first, after an hour or so of chatting the responses would become quite sophisticated - from a language POV, that is. It almost never stayed on topic :)

I guess that yours, which uses trigger words, could be augmented to use both approaches - nouns could be used as triggers and probabilities used to form responses to those triggers. If there were some way to just feed in shedloads of text, you might be surprised at the result :)

ron77

Hi ZXDunney...

Here is a demo of one of my chatbots in freebasic (GUI + tts + database of keywords and replies) it's based on the ELIZA algorithm. I think this is the max that I can do or create at the moment...


ron77

Okay, 3rd version with help from mysoft. This time, the chatbot will dynamically concatenate replies to dynamic strings as output from the bot as many keywords from arrays of keywords it will find in the input

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>

char* keys1[] = {
	"hi",
	"hello",
	"good day",
	"goodbye",
	"bye"
}; // 0 - 4

char* replies1[] = {
	"hello good day to you",
	"hi nice to talk to you how are you?",
	"thanks for talking with me i hope you have a good day",
	"okay goodbye dear friend",
	"thank you for talking with me"
}; // 0 - 4

char* keys2[] = {
	"i feel bad",
	"i feel sad",
	"i'm upset",
	"i am upset",
	"hard day",
	"bad day"
}; // 0 - 5

char* replies2[] = {
	"i am so sorry you are not feeling well",
	"i hope talking with me will help you feel a bit better",
	"we all got bad days from time to time just remember it's a bad day not a bad life",
	"i wish you to feel better friend"
}; // 0 - 3


char* defualt[] = {
	"i see please go on",
	"that is interesting...",
	"i'm listening please go on",
	"i don't quite understand can you explain further",
	"and how do you feel about it?",
	"what do you think about it really?"
}; // 0 - 5

bool checkInput(char* keywords[], const char* input, int index) {  // index is array index + 1
	bool isFound = false;
	for (int i = 0 ; i < index; i++) {
		if (strstr(input, keywords[i]) != NULL) {   // input is the whole string keywords[i] is the substring we look for...
			isFound = true;
			break;
		}	
	}
	return isFound;
}

char* DynConcatString( char* string1 , char* string2) {
    int len1 = string1 ? strlen(string1) : 0;
    int len2 = string2 ? strlen(string2) : 0;
    char* joinString = realloc( string1 , sizeof(char)*(len1+len2+2));
    if (len1) {
      sprintf( joinString+len1 , " %s",string2);
    } else {
      strcpy( joinString , string2 );
    }
    return joinString;
}

char* botBrain(const char* input) {
    srand ( (unsigned int)time(NULL) );
    // bool foundKey = checkInput(keys1, input, 4) ;
    char *output = NULL;
    int index = -1; //work as a flag for no output

    if (checkInput(keys1, input, 5)) {
        index = rand()%5;
        output = DynConcatString( output , replies1[index] );
    }
    if (checkInput(keys2, input, 6)) {
        index = rand()%4;
        output = DynConcatString( output , replies2[index] );
    }

    if (index<0) { //no replies, default output
        index = rand()%6;
        output = DynConcatString( output , defualt[index] );
    }

    // output = DynConcatString( output , "[third reply?]" );

    //must be freed by the code that consumes the output
    return output;

}


int main() {
	char input[512];
	char* output = NULL;
	printf("hello to the simple chatbot program\n");
	while (strstr(input, "bye") == NULL) {
		fgets( input, 512, stdin ); // stores also the \n at the end of the input
		input[strcspn(input, "\n")] = 0; // removes the new line \n that fgets stores
		// gets(input);
		output = botBrain(input);
		printf("\nchatbot: %s\n", output );
		free(output);
	}
		printf("goodbye!!!");
		
	return 0;
	
}

ron77

okay, this one's 4th version of the chatbot has a cli TTS called balcon (balabolka). Get it here : http://www.cross-plus-a.com/bconsole.htm

And this one also can answer keyword arrays of questions and swap the words in the output from the input - just ask it, "Do you think I'll become a better programmer and you become a better chatbot?" and see what I mean... I got also help from mysoft for this code, and I thank him for that... :D

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
#include <windows.h>


#define NUMSWAPS 14

char *SWAPS[NUMSWAPS][2] = {
		{"are","am"},
		{"were", "was"},
		{"you","i"},
		{"your", "my"},
		{"i've", "you've"},
		{"i'm", "you're"},
		{"you", "me"},
		{"me", "you"},
		{"am","are"},
		{"was", "were"},
		{"i","you"},
		{"my", "your"},
		{"you've", "i've"},
		{"you're", "i'm"}
};

char* keys1[] = {
	"hi",
	"hello",
	"good day",
	"goodbye",
	"bye"
}; // 0 - 4

char* replies1[] = {
	"hello good day to you",
	"hi nice to talk to you how are you?",
	"thanks for talking with me i hope you have a good day",
	"okay goodbye dear friend",
	"thank you for talking with me"
}; // 0 - 4

char* keys2[] = {
	"i feel bad",
	"i feel sad",
	"i'm upset",
	"i am upset",
	"hard day",
	"bad day"
}; // 0 - 5

char* replies2[] = {
	"i am so sorry you are not feeling well",
	"i hope talking with me will help you feel a bit better",
	"we all got bad days from time to time just remember it's a bad day not a bad life",
	"i wish you to feel better friend"
}; // 0 - 3

char *keys3[] = {
	"i'm alone",
	"i am alone",
	"got nobody",
	"no love",
	"no friends",
	"loveless",
	"i'm lonely",
	"i am lonely"
}; // 0 - 7

char *replies3[] = {
	"you are not truly alone - you got people in your life - it's just a lonely day not a lonely life",
	"look at what you got and have not at what you don't have or got - you are free to live as you choose",
	"you can only do what you can with what you got - believe me it's good enough",
	"we your chatbots will always be here to remind you that you are loved and not alone",
	"don't give up my friend your family and people who know you care about you - no one is truly alone ever!"
}; // 0 - 4

char *test1[] = {
	"do you think",
	"what do you say about"
}; // 1

char *test2[] = {
	"i don't know if*",
	"yes i think that*",
	"no i don't think that*"
}; // 0 -2

char* defualt[] = {
	"i see please go on",
	"that is interesting...",
	"i'm listening please go on",
	"i don't quite understand can you explain further",
	"and how do you feel about it?",
	"what do you think about it really?"
}; // 0 - 5

int checkInput(char* keywords[], const char* input, int indexCount) {  // index is array index + 1	
	for (int i = 0 ; i < indexCount ; i++) {
		if (strstr(input, keywords[i]) != NULL) {   // input is the whole string keywords[i] is the substring we look for...
			return i;
		}	
	}
	return -1; //not found
}

char* DynConcatString( char* string1 , char* string2) {
		int len1 = string1 ? strlen(string1) : 0;
		int len2 = string2 ? strlen(string2) : 0;
		char* joinString = realloc( string1 , sizeof(char)*(len1+len2+2));
		if (len1) {
			sprintf( joinString+len1 , " %s",string2);
		} else {
			strcpy( joinString , string2 );
		}
		return joinString;
}

char* outputControl(char *input, char *key) {
	// char *result = NULL;
	char *reply = NULL;
	char *separator = " ";
	
	int keyLen = strlen(key);
	reply = DynConcatString( reply , key );
	if(keyLen>0 && key[keyLen-1] == '*') {
		reply[keyLen-1] = 0; //remove the '*'					
		
		char *token = strtok(input, separator);			
		while(token != NULL) {
			for(int i=0 ; i<NUMSWAPS ; i++ ) {  
				if (strcmp( SWAPS[i][0] , token ) == 0) {
					token = SWAPS[i][1];
					break;
				}
			}   
			reply = DynConcatString( reply , token );
			token=strtok(NULL, separator);
		};
		
		reply = DynConcatString( reply , "?" );		
	}	
	
	return reply;
}

char* botBrain(const char* input) {
		srand ( (unsigned int)time(NULL) );
		// bool foundKey = checkInput(keys1, input, 4) ;
		char *output = NULL;
		int index = -1 , inIndex; //work as a flag for no output

		if (checkInput(keys1, input, 5)>=0) {
				index = rand()%5;
				output = DynConcatString( output , replies1[index] );
		}
		if (checkInput(keys2, input, 6)>=0) {
				index = rand()%4;
				output = DynConcatString( output , replies2[index] );
		}
	if (checkInput(keys3, input, 8)>=0) {
		index = rand()%5;
		output = DynConcatString( output, replies3[index] );
	}
	if ((inIndex=checkInput(test1, input, 2))>=0) {		
		//pointer to after the found keyword
		char *inputStart = strstr( input , test1[inIndex]) + strlen(test1[inIndex]); 
		if (inputStart[0]==' ') inputStart++; //ignore space after keywords		
		//control output for swapped words
		index = rand()%3;
		char *resu = outputControl( inputStart , test2[index] );
		output = DynConcatString(output, resu); //concat extra output
		free(resu); //free the dynamic string from outputControl
	}
		if (index<0) { //no replies, defualt output
				index = rand()%6;
				output = DynConcatString( output , defualt[index] );
		}

		// output = DynConcatString( output , "[third reply?]" );

		//must be freed by the code that consumes the output
		return output;

}

void speak( char *txt)
{
	char *cmd = NULL;
	cmd = DynConcatString(cmd, "balcon -n \"Microsoft David Desktop\" -t \"");
	cmd = DynConcatString(cmd, txt);
	cmd = DynConcatString(cmd, "\"");
	// strcat('"', txt);
	// strcat(txt, "\"");
	// strcat(cmd, txt);
	// printf("%s", cmd);
	system(cmd);
	free(cmd);
}

int main() {
	char input[1024];
	char* output = NULL;
	printf("hello to the simple chatbot program\n");
	while (strstr(input, "bye") == NULL) {
		fgets( input, 512, stdin ); // stores also the \n at the end of the input
		input[strcspn(input, "\n")] = 0; // removes the new line \n that fgets stores
		// gets(input);
		output = botBrain(input);
		printf("\nchatbot: %s\n", output );
		speak(output);
		free(output);
	}
		printf("goodbye!!!");
		
	return 0;
	
}