hi all, well i converted my chatbot from C to C3 here is the code:
module c3_danny_std;
import std;
import libc;
import std::math::random;
extern fn char* strdup(char* s);
const int MAX_STRING_LENGTH = 1000;
const int MAX_ARRAY_SIZE = 1000;
const int MAX_KEYWORDS = 50;
const int MAX_REPLIES = 50;
const int MAX_MATCHES = 10;
const int MAX_SWAP_WORDS = 100;
const int MAX_MEMORY = 15;
/*
s:are>am
s:am>are
s:were>was
s:was>were
s:you>i
s:i>you
s:your>my
s:my>your
s:i've>you've
s:you've>i've
s:i'm>you're
s:you're>i'm
s:me>you
s:i'll>you'll
s:you'll>i'll
*/
String[] word_in = {
"are",
"am",
"were",
"was",
"you",
"i",
"your",
"my",
"i've",
"you've",
"i'm",
"you're",
"me",
"i'll",
"you'll",
};
String[] word_out = {
"am",
"are",
"was",
"were",
"i",
"you",
"my",
"your",
"you've",
"i've",
"you're",
"i'm",
"you",
"you'll",
"i'll",
};
String[MAX_SWAP_WORDS] wordIn;
String[MAX_SWAP_WORDS] wordOut;
int wCnt = 0;
String[MAX_MEMORY] memory;
int memoryCount = 0;
struct ArraySet {
String[MAX_KEYWORDS] keywords;
String[MAX_REPLIES] replies;
int keywordCount;
int replyCount;
}
ArraySet[MAX_ARRAY_SIZE] g_Key_Reply;
int g_Key_ReplyCount = 0;
String[MAX_ARRAY_SIZE] default_replies;
int default_reply_count = 0;
fn char* safe_strdup(char* s) {
if (!s) return null;
char* result = strdup(s);
if (!result) {
io::printfn("%s Memory allocation failed in safe_strdup\n", &std::io::stderr);
return null;
}
return result;
}
fn char* isolatePunctuation(char* s) {
char* b = malloc(libc::strlen((ZString)s) * 3 + 1);
if (!b) return null;
int j = 0;
for (int i = 0; s[i]; i++) {
if (libc::strchr("?!,.:;<>(){}[]", s[i])) {
b[j++] = ' ';
b[j++] = s[i];
b[j++] = ' ';
} else {
b[j++] = s[i];
}
}
b[j] = '\0';
return b;
}
fn void loadArrays(String filename) {
File! f = io::file::open(filename, "r");
if (catch error = f) {
io::printfn("Error opening file: %s: %s\n", filename, error);
return;
}
defer (void)f.close();
// String line; no needs for this
int currentSet = -1;
while (try line = io::treadline(&f)) { // line is created here automatically
if (line.len < 3) {
// Skip lines that aren't long enough
continue;
}
if (f.eof()) break;
if (line[0..2] == "d1:") { //(strncmp(line, "d1:", 3) == 0) {
default_replies[default_reply_count++] = line[3..]; //strcpy(default_replies[default_reply_count++], line + 3);
}
if (line[0..1] == "k:") { //(line[0] == 'k' && line[1] == ':') {
if (currentSet == -1 || g_Key_Reply[currentSet].replyCount > 0) {
currentSet++;
}
if (currentSet >= MAX_ARRAY_SIZE) {
io::printfn("Error: too many keyword-reply pairs\n");
break;
}
if (g_Key_Reply[currentSet].keywordCount < 50) {
String keyword = string::tformat(" %s ", line[2..]);
g_Key_Reply[currentSet].keywords[g_Key_Reply[currentSet].keywordCount] = keyword; //line[2..];//strcpy(g_Key_Reply[currentSet].keywords[g_Key_Reply[currentSet].keywordCount], line + 2);
g_Key_Reply[currentSet].keywordCount++;
g_Key_ReplyCount = currentSet + 1;
// g_Key_Reply[currentSet].replyCount = 0;
} else {
io::printfn("Error: too many keywords for keyword-reply pair %d\n", currentSet);
}
} else if (line[0..1] == "r:") { //(line[0] == 'r' && line[1] == ':') {
if (g_Key_Reply[currentSet].replyCount < 50) {
g_Key_Reply[currentSet].replies[g_Key_Reply[currentSet].replyCount] = line[2..];//strcpy(g_Key_Reply[currentSet].replies[g_Key_Reply[currentSet].replyCount], line + 2);
g_Key_Reply[currentSet].replyCount++;
// g_Key_Reply[currentSet].keywordCount = 0;
} else {
io::printfn("Error: too many replies for keyword %s\n", g_Key_Reply[currentSet].keywords[g_Key_Reply[currentSet].keywordCount - 1]);
}
}
}
//fclose(file);
io::printfn("number of keywords-replies pair groups %d\n", currentSet);
}
fn void loadSwapWords(String filename) {
File! f = io::file::open(filename, "r");
if (catch error = f) {
io::printfn("Error opening file: %s: %s\n", filename, error);
return;
}
defer (void)f.close();
String line;
while ((line = io::treadline(&f)!!) && wCnt < MAX_SWAP_WORDS) {
if (line.len < 3) {
// Skip lines that aren't long enough
continue;
}
if (f.eof()) break;
//line[strcspn(line, "\n")] = 0; // Remove newline
if (line[0..1] == "s:") { //(line[0] == 's' && line[1] == ':') {
int indexOfdelimiter = (int)line.index_of(">")!!;
// if (indexOfdelimiter != null) {
wordIn[wCnt] = line[2..indexOfdelimiter];//strcpy(wordIn[wCnt], line + 2);
wordOut[wCnt] = line[indexOfdelimiter + 1..line.len-1];//strcpy(wordOut[wCnt], delimiter + 1);
wCnt++;
// }
// char* delimiter = strchr(line + 2, '>');
// if (delimiter) {
// *delimiter = '\0';
// strcpy(wordIn[wCnt], line + 2);
// strcpy(wordOut[wCnt], delimiter + 1);
// wCnt++;
// }
}
}
//fclose(file);
}
fn String swapWords(String input) {
if (input == "") return "";
// DString output;
String output;
// output.temp_init();
String[] words = input.tsplit(" ");
String temp = "";
foreach (j, word: words) {
String result = word;
bool swapped = false;
foreach (i, swap_word: word_in) {
if (word == word_in[i]) {
result = word_out[i];
break;
}
}
output = String.tconcat(output, result);
// if (j < words.len - 1) output.append(" ");
if (j < words.len - 1) output = String.tconcat(output, " ");
}
// return output.str_view();
return output;
}
fn String processReply(String reply, String userInput) {
if (reply == "" || userInput == "") return reply;
if (reply[reply.len - 1] == '*') {
// If the reply doesn't end with an asterisk, don't swap words
// return reply;
// } else {
reply = reply[0:reply.len-1]; // Remove the asterisk
// reply = reply[0..reply.len-2];
}
String keyword = "";
for (int i = 0; i < g_Key_ReplyCount; i++) {
for (int j = 0; j < g_Key_Reply[i].keywordCount; j++) {
if (userInput.contains(g_Key_Reply[i].keywords[j])) {
keyword = g_Key_Reply[i].keywords[j];
break;
}
}
if (keyword != "") break;
}
if (keyword != "") {
int keywordIndex = (int)userInput.index_of(keyword)!!;
String tail = userInput[keywordIndex + keyword.len..];
String swappedTail = swapWords(tail);
if (swappedTail != "") {
reply = String.tconcat(reply, " ");
reply = String.tconcat(reply, swappedTail);
}
}
// }
return reply;
}
// fn String userQuestion(String txt) {
// String[MAX_MATCHES] matchedReplies;
// int matchCount = 0;
// bool isMatch = false;
// String finalReply = "";
// // Find matching replies
// for (int i = 0; i < g_Key_ReplyCount && matchCount < MAX_MATCHES; i++) {
// bool foundInGroup = false;
// for (int j = 0; j < g_Key_Reply[i].keywordCount; j++) {
// if (txt.contains(g_Key_Reply[i].keywords[j])) {
// if (!foundInGroup) {
// int replyIndex = random::rand(g_Key_Reply[i].replyCount);
// matchedReplies[matchCount++] = g_Key_Reply[i].replies[replyIndex];
// foundInGroup = true;
// isMatch = true;
// }
// }
// }
// }
// // Process replies
// if (matchCount > 0 && isMatch && matchCount <= MAX_MATCHES) {
// foreach (reply : matchedReplies[0..matchCount]) {
// String processed = processReply(reply, txt);
// if (processed != "") {
// if (finalReply != "") {
// finalReply = String.tconcat(finalReply, " ");
// }
// finalReply = String.tconcat(finalReply, processed);
// }
// }
// return finalReply.trim();
// }
// // Default reply
// return default_replies[random::rand(default_reply_count)];
// }
fn String userQuestion(String txt) {
String response = "I don't understand. Can you rephrase that?";
String[MAX_MATCHES] matchedReplies;
int matchCount = 0;
bool isMatch = false;
String combinedReply = "";
for (int i = 0; i < g_Key_ReplyCount && matchCount < MAX_MATCHES; i++) {
for (int j = 0; j < g_Key_Reply[i].keywordCount; j++) {
if (txt.contains(g_Key_Reply[i].keywords[j])) {
int replyIndex = random::rand(g_Key_Reply[i].replyCount);
matchedReplies[matchCount++] = g_Key_Reply[i].replies[replyIndex];
isMatch = true;
break;
}
}
}
if (matchCount > 0 && isMatch && matchCount <= MAX_MATCHES) {
for (int i = 0 ; i < matchCount ; i++) {
String reply = matchedReplies[i];
if (reply[reply.len-1] == '*') {
combinedReply = String.tconcat(combinedReply, processReply(reply, txt));
} else {
combinedReply = String.tconcat(combinedReply, reply);
}
combinedReply = String.tconcat(combinedReply, " ");
}
response = combinedReply;
} else if (!isMatch) {
int defaultIndex = random::rand(default_reply_count);
response = default_replies[defaultIndex];
}
return response;
}
fn String commands(String txt) {
// String isolated = isolatePunctuation(txt);
// for (int i = 0; isolated[i]; i++) {
// isolated[i] = tolower(isolated[i]);
// }
String text = string::tformat(" %s ", txt);
String response = userQuestion(text);
// free(isolated);
return response;
}
fn void speak(String text) {
String command;
command = "voice -r -1 -n \"Microsoft David Desktop\" ";
String text2 = string::tformat("\"%s\"",text);
// command = string::tformat("%s \"%s\"", command, text2);
command = String.tconcat(command, text2);
// command = String.tconcat(text2, "\"");
// String.tconcat(command, text2);
libc::system((ZString)command);
}
fn int main() {
libc::srand((uint)libc::time(null));
loadArrays("./database.txt");
// loadSwapWords("./swapwords.txt");
// for (int i = 0; i < wCnt; i++) {
// io::printfn("wordIn[%d] = %s, wordOut[%d] = %s\n", i, wordIn[i], i, wordOut[i]);
// }
io::printfn("CHATBOT DANNY IN C3 PROGRAMMING LANGUAGE VERSION 1.1.6.5 (C) RON77\n");
String input;
String response;
while (true) {
io::printf("> ");
//if (fgets(input, sizeof(input), stdin) == NULL) {
input = io::treadline()!!;
// input[strcspn(input, "\n")] = 0; // Remove newline
if (input == "quit") break;
response = commands(input);
if (response != "") {
// Split the response into separate lines and speak each one
String line = response;
while (line != "") {
io::printn(line);
io::printn("\n");
speak(line);
line = "";
}
// free(response);
} else {
io::printfn("An error occurred while processing your input.\n");
}
}
return 0;
}
The database.txt can be found here, as well as the 'voice.exe' TTS cli engine for Windows...
https://retrocoders.phatcode.net/index.php?topic=840.0 (https://retrocoders.phatcode.net/index.php?topic=840.0)