From 54f6f72ad2f53d4f6b914ed89ee7b49768db428f Mon Sep 17 00:00:00 2001 From: Vinit kumar Date: Wed, 12 Mar 2025 23:38:13 +0530 Subject: [PATCH] feat: improve iterface, thanks vibe coding --- src/chatbot.c | 301 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 263 insertions(+), 38 deletions(-) diff --git a/src/chatbot.c b/src/chatbot.c index 6e44c9e..2156d0c 100644 --- a/src/chatbot.c +++ b/src/chatbot.c @@ -3,26 +3,112 @@ #include #include #include +#include +#include +#include +#include +#include #include "chatbot.h" -// hash table implementation from here -// https://gist.githubusercontent.com/tonious/1377667/raw/c814d0833c8699dc017871931a5c5bee11af0f64/hash.c - +// ANSI Color codes for prettier output +#define COLOR_RESET "\x1b[0m" +#define COLOR_GREEN "\x1b[32m" +#define COLOR_BLUE "\x1b[34m" +#define COLOR_CYAN "\x1b[36m" +#define COLOR_YELLOW "\x1b[33m" +#define COLOR_RED "\x1b[31m" + +#define MAX_RESPONSE_LENGTH 1024 +#define MAX_CONTEXT_LENGTH 5 +#define CONFIG_FILE "chatbot_responses.txt" +#define LOG_FILE "chatbot.log" +#define TYPING_DELAY 50000 // 50ms delay between characters + +// Forward declarations of structures struct entry_s { - char *key; - char *value; - struct entry_s *next; + char *key; + char *value; + struct entry_s *next; }; - typedef struct entry_s entry_t; struct hashtable_s { - int size; - struct entry_s **table; + int size; + struct entry_s **table; }; - typedef struct hashtable_s hashtable_t; +// Context structure to maintain conversation state +typedef struct { + char *messages[MAX_CONTEXT_LENGTH]; + int current; +} Context; + +// Function prototypes +hashtable_t *ht_create(int size); +int ht_hash(hashtable_t *hashtable, char *key); +entry_t *ht_newpair(char *key, char *value); +void ht_set(hashtable_t *hashtable, char *key, char *value); +char *ht_get(hashtable_t *hashtable, char *key); +void ht_destroy(hashtable_t *hashtable); + +void init_context(Context *ctx); +void add_to_context(Context *ctx, const char *message); +void free_context(Context *ctx); +void load_responses_from_file(hashtable_t *hashtable, const char *filename); +void log_conversation(const char *user_input, const char *response); +void print_with_typing_effect(const char *text); +char* get_contextual_response(hashtable_t *hashtable, Context *ctx, const char *input); +void save_conversation_history(const char *filename); +void print_help(void); +void print_welcome_message(void); +char* generate_response(hashtable_t *hashtable, const char *input); + +// Helper function to print welcome message +void print_welcome_message(void) { + printf("\n%s==================================%s\n", COLOR_CYAN, COLOR_RESET); + printf("%s Chatbot v1.0.0%s\n", COLOR_GREEN, COLOR_RESET); + printf("%s==================================%s\n", COLOR_CYAN, COLOR_RESET); + printf("\nWelcome! I'm here to chat with you.\n"); + printf("Commands:\n"); + printf(" - Type %sexit%s to quit\n", COLOR_YELLOW, COLOR_RESET); + printf(" - Press %sEnter%s twice to quit\n", COLOR_YELLOW, COLOR_RESET); + printf(" - Just type naturally to chat with me\n\n"); +} + +// Helper function to process input and generate response +char* generate_response(hashtable_t *hashtable, const char *input) { + static char response[MAX_RESPONSE_LENGTH]; + char input_copy[LINELENGTH]; + char *word; + int found = 0; + + strncpy(input_copy, input, LINELENGTH - 1); + input_copy[LINELENGTH - 1] = '\0'; + + // Try to match each word in the input + word = strtok(input_copy, SEPCHARS); + while (word != NULL) { + char *word_response = ht_get(hashtable, word); + if (word_response != NULL) { + strncpy(response, word_response, MAX_RESPONSE_LENGTH - 1); + response[MAX_RESPONSE_LENGTH - 1] = '\0'; + found = 1; + break; + } + word = strtok(NULL, SEPCHARS); + } + + if (!found) { + strncpy(response, "I'm not sure how to respond to that. Try asking something else!", MAX_RESPONSE_LENGTH - 1); + response[MAX_RESPONSE_LENGTH - 1] = '\0'; + } + + return response; +} + +// hash table implementation from here +// https://gist.githubusercontent.com/tonious/1377667/raw/c814d0833c8699dc017871931a5c5bee11af0f64/hash.c /* Create a new hashtable. */ hashtable_t *ht_create( int size ) { @@ -153,37 +239,176 @@ char *ht_get( hashtable_t *hashtable, char *key ) { } -int main(void) { +/* Free all resources used by the hashtable */ +void ht_destroy(hashtable_t *hashtable) { + if (hashtable == NULL) return; + + // Free all entries + for (int i = 0; i < hashtable->size; i++) { + entry_t *current = hashtable->table[i]; + while (current != NULL) { + entry_t *next = current->next; + free(current->key); + free(current->value); + free(current); + current = next; + } + } + + // Free the table and the hashtable struct + free(hashtable->table); + free(hashtable); +} + +void init_context(Context *ctx) { + for (int i = 0; i < MAX_CONTEXT_LENGTH; i++) { + ctx->messages[i] = NULL; + } + ctx->current = 0; +} - char line[LINELENGTH]; - char *word; - printf("$ Chatbot v1.0.0!\n"); +void add_to_context(Context *ctx, const char *message) { + // Free the oldest message if we're at capacity + if (ctx->messages[ctx->current] != NULL) { + free(ctx->messages[ctx->current]); + } + + // Add new message + ctx->messages[ctx->current] = strdup(message); + ctx->current = (ctx->current + 1) % MAX_CONTEXT_LENGTH; +} + +void free_context(Context *ctx) { + for (int i = 0; i < MAX_CONTEXT_LENGTH; i++) { + if (ctx->messages[i] != NULL) { + free(ctx->messages[i]); + ctx->messages[i] = NULL; + } + } +} - hashtable_t *hashtable = ht_create(65536); - ht_set(hashtable, "hi", "hello"); - ht_set(hashtable, "hey", "hello"); - ht_set(hashtable, "hear", "What you heard is right"); - ht_set(hashtable, "python", "Yo, I love Python"); - ht_set(hashtable, "light", "I like light"); - ht_set(hashtable, "What", "It is clear, ain't it?"); +void log_conversation(const char *user_input, const char *response) { + FILE *log_file = fopen(LOG_FILE, "a"); + if (log_file != NULL) { + time_t now; + time(&now); + char *date = ctime(&now); + date[strlen(date) - 1] = '\0'; // Remove newline + fprintf(log_file, "[%s] User: %s\n", date, user_input); + fprintf(log_file, "[%s] Bot: %s\n\n", date, response); + fclose(log_file); + } +} - while(1) { - printf("\n$ (user) "); - fgets(line, LINELENGTH, stdin); - if (strlen(line) <= 1) break; /*exit program*/ - word = strtok(line, SEPCHARS); /*Find first word */ +void print_with_typing_effect(const char *text) { + for (size_t i = 0; i < strlen(text); i++) { + putchar(text[i]); + fflush(stdout); + usleep(TYPING_DELAY); + } +} - while (word != NULL) { - if (strncasecmp(word, "exit", 150) == 0) { - exit(0); - } - // Some responses based on the keywords - if (ht_get(hashtable, word) != NULL) { - printf("\n$ (chatbot) %s\n", ht_get(hashtable, word)); - } else { - printf("\n$ (chatbot) %s\n", "Sorry, I don't know what to say about that" ); - } - word = strtok(NULL, SEPCHARS); +void load_responses_from_file(hashtable_t *hashtable, const char *filename) { + FILE *file = fopen(filename, "r"); + if (file == NULL) return; + + char line[MAX_RESPONSE_LENGTH]; + char *key, *value; + + while (fgets(line, sizeof(line), file)) { + line[strcspn(line, "\n")] = 0; + key = strtok(line, "|"); + value = strtok(NULL, ""); + + if (key && value) { + ht_set(hashtable, key, value); + } } - } + + fclose(file); +} + +char* get_contextual_response(hashtable_t *hashtable, Context *ctx, const char *input) { + static char response[MAX_RESPONSE_LENGTH]; + char *basic_response = generate_response(hashtable, input); + + // Check context for better responses + for (int i = 0; i < MAX_CONTEXT_LENGTH; i++) { + if (ctx->messages[i] != NULL && strstr(ctx->messages[i], "?") != NULL) { + // If previous message was a question, make response more contextual + snprintf(response, MAX_RESPONSE_LENGTH, "Regarding your previous question, %s", basic_response); + return response; + } + } + + return basic_response; +} + +void print_help(void) { + printf("\n%sAvailable Commands:%s\n", COLOR_CYAN, COLOR_RESET); + printf(" %s/help%s - Show this help message\n", COLOR_YELLOW, COLOR_RESET); + printf(" %s/exit%s - Exit the chatbot\n", COLOR_YELLOW, COLOR_RESET); + printf(" %s/clear%s - Clear the screen\n", COLOR_YELLOW, COLOR_RESET); + printf(" %s/history%s - Show conversation history\n", COLOR_YELLOW, COLOR_RESET); +} + +int main(void) { + char line[LINELENGTH]; + hashtable_t *hashtable = NULL; + + // Create and initialize hashtable + hashtable = ht_create(65536); + if (hashtable == NULL) { + fprintf(stderr, "%sError: Failed to create chatbot memory%s\n", COLOR_RED, COLOR_RESET); + return 1; + } + + // Initialize responses with more natural language + ht_set(hashtable, "hi", "Hello! How can I help you today?"); + ht_set(hashtable, "hey", "Hey there! What's on your mind?"); + ht_set(hashtable, "hello", "Hi! Nice to meet you!"); + ht_set(hashtable, "how", "I'm doing well, thanks for asking! How about you?"); + ht_set(hashtable, "what", "That's an interesting question! Let me think..."); + ht_set(hashtable, "why", "That's a good question! I think it's because..."); + ht_set(hashtable, "python", "Python is a great programming language! I love its simplicity and power."); + ht_set(hashtable, "programming", "Programming is fun! I especially enjoy helping people learn to code."); + ht_set(hashtable, "bye", "Goodbye! Have a great day!"); + ht_set(hashtable, "thanks", "You're welcome! Let me know if you need anything else."); + + // Display welcome message + print_welcome_message(); + + // Main chat loop + while(1) { + // Print prompt with color + printf("\n%s➜ %s", COLOR_GREEN, COLOR_RESET); + + // Get input with error handling + if (fgets(line, LINELENGTH, stdin) == NULL) { + printf("\n%sGoodbye!%s\n", COLOR_CYAN, COLOR_RESET); + break; + } + + // Remove trailing newline + size_t len = strlen(line); + if (len > 0 && line[len-1] == '\n') { + line[len-1] = '\0'; + len--; + } + + // Handle exit conditions + if (len == 0) break; + if (strcasecmp(line, "exit") == 0 || strcasecmp(line, "quit") == 0 || strcasecmp(line, "bye") == 0) { + printf("\n%sGoodbye! Have a great day!%s\n", COLOR_CYAN, COLOR_RESET); + break; + } + + // Generate and print response + char *response = generate_response(hashtable, line); + printf("%s❯ %s%s\n", COLOR_BLUE, response, COLOR_RESET); + } + + // Cleanup + ht_destroy(hashtable); + return 0; }