News:

Welcome to RetroCoders Community

Main Menu

windows 32 bit OpenAI API Chatbot in C

Started by ron77, Aug 31, 2024, 08:32 PM

Previous topic - Next topic

ron77

OK this code is in C it depends on using libraries such as libcurl and libcjson and zlib
I compiled it with mingw32 32bit and it works without TTS just text on the screen of the terminal (cmd) command prompt...

#include <stdio.h>
#include <windows.h>
#include <winhttp.h>
#include <stdlib.h>
#include <string.h>

#pragma comment(lib, "winhttp.lib")

#define MAX_RESPONSE_SIZE 16384
#define MAX_REQUEST_SIZE 8192
#define MAX_SYSTEM_MESSAGE_SIZE 4092
#define MAX_INPUT_SIZE 1024

char system_message[MAX_SYSTEM_MESSAGE_SIZE] = "You are my Spirit Guide, a wise and benevolent being here to help me navigate my life's journey. I seek your guidance and advice as I walk my path in this world. Please offer me the wisdom I need, help me stay on the right course, and hear me when I call out for support. I trust in your presence and am open to the insights you provide to guide me through life.";

char* make_request(const char* request_body, const char* auth_header) {
    DWORD dwSize = 0;
    DWORD dwDownloaded = 0;
    LPSTR pszOutBuffer;
    BOOL  bResults = FALSE;
    HINTERNET  hSession = NULL, 
               hConnect = NULL,
               hRequest = NULL;

    hSession = WinHttpOpen(L"OpenAI API Client",  
                           WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                           WINHTTP_NO_PROXY_NAME, 
                           WINHTTP_NO_PROXY_BYPASS, 0);

    if (hSession == NULL) {
        printf("Error %lu in WinHttpOpen.\n", GetLastError());
        return NULL;
    }

    hConnect = WinHttpConnect(hSession, L"api.openai.com",
                              INTERNET_DEFAULT_HTTPS_PORT, 0);

    if (hConnect == NULL) {
        printf("Error %lu in WinHttpConnect.\n", GetLastError());
        WinHttpCloseHandle(hSession);
        return NULL;
    }

    hRequest = WinHttpOpenRequest(hConnect, L"POST", L"/v1/chat/completions",
                                  NULL, WINHTTP_NO_REFERER, 
                                  WINHTTP_DEFAULT_ACCEPT_TYPES, 
                                  WINHTTP_FLAG_SECURE);

    if (hRequest == NULL) {
        printf("Error %lu in WinHttpOpenRequest.\n", GetLastError());
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return NULL;
    }

    // Convert auth_header to wide string
    wchar_t wide_auth_header[512];
    MultiByteToWideChar(CP_UTF8, 0, auth_header, -1, wide_auth_header, 512);

    WinHttpAddRequestHeaders(hRequest, L"Content-Type: application/json", -1, WINHTTP_ADDREQ_FLAG_ADD);
    WinHttpAddRequestHeaders(hRequest, wide_auth_header, -1, WINHTTP_ADDREQ_FLAG_ADD);

    bResults = WinHttpSendRequest(hRequest,
                                  WINHTTP_NO_ADDITIONAL_HEADERS, 0,
                                  (LPVOID)request_body, strlen(request_body),
                                  strlen(request_body), 0);

    if (!bResults) {
        printf("Error %lu in WinHttpSendRequest.\n", GetLastError());
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return NULL;
    }

    bResults = WinHttpReceiveResponse(hRequest, NULL);

    if (!bResults) {
        printf("Error %lu in WinHttpReceiveResponse.\n", GetLastError());
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return NULL;
    }

    pszOutBuffer = (LPSTR)malloc(MAX_RESPONSE_SIZE);
    if (!pszOutBuffer) {
        printf("Failed to allocate memory\n");
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return NULL;
    }
    ZeroMemory(pszOutBuffer, MAX_RESPONSE_SIZE);

    DWORD total_size = 0;
    if (bResults) {
        do {
            dwSize = 0;
            if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
                printf("Error %lu in WinHttpQueryDataAvailable.\n", GetLastError());
                break;
            }

            if (dwSize + total_size > MAX_RESPONSE_SIZE) {
                printf("Response too large, truncating.\n");
                dwSize = MAX_RESPONSE_SIZE - total_size;
            }

            if (!WinHttpReadData(hRequest, (LPVOID)(pszOutBuffer + total_size), 
                                 dwSize, &dwDownloaded)) {
                printf("Error %lu in WinHttpReadData.\n", GetLastError());
                break;
            }

            total_size += dwDownloaded;
        } while (dwSize > 0 && total_size < MAX_RESPONSE_SIZE);
    }

    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);

    return pszOutBuffer;
}

char* extract_content(const char* json_response) {
    char* choices_start = strstr(json_response, "\"choices\":");
    if (choices_start == NULL) {
        printf("Could not find 'choices' in response.\n");
        printf("Full response:\n%s\n", json_response);
        return NULL;
    }
    
    char* message_start = strstr(choices_start, "\"message\":");
    if (message_start == NULL) {
        printf("Could not find 'message' in response.\n");
        return NULL;
    }
    
    char* content_start = strstr(message_start, "\"content\":");
    if (content_start == NULL) {
        printf("Could not find 'content' in response.\n");
        return NULL;
    }
    
    content_start = strchr(content_start, ':');
    if (content_start == NULL) {
        printf("Malformed content in response.\n");
        return NULL;
    }
    content_start++; // Move past the ':'
    
    // Skip whitespace and opening quote
    while (*content_start == ' ' || *content_start == '"') {
        content_start++;
    }
    
    char* content_end = strstr(content_start, "\",");
    if (content_end == NULL) {
        printf("Could not find end of content in response.\n");
        return NULL;
    }

    int content_length = content_end - content_start;
    char* content = (char*)malloc(content_length + 1);
    strncpy(content, content_start, content_length);
    content[content_length] = '\0';

    return content;
}

void set_system_message() {
    printf("Enter new system message (max %d characters):\n", MAX_SYSTEM_MESSAGE_SIZE - 1);
    fgets(system_message, sizeof(system_message), stdin);
    system_message[strcspn(system_message, "\n")] = 0;  // Remove newline
    printf("System message updated.\n");
}

int main() {
    char input[MAX_INPUT_SIZE];
    char request_body[MAX_REQUEST_SIZE];
    char* response;
    char* extracted_content;
    
    char api_key[256];
    printf("Enter your OpenAI API key: ");
    fgets(api_key, sizeof(api_key), stdin);
    api_key[strcspn(api_key, "\n")] = 0;  // Remove newline

    while (1) {
        printf("You (type 'exit' to quit, 'role' to change system message): ");
        fgets(input, sizeof(input), stdin);
        input[strcspn(input, "\n")] = 0;  // Remove newline

        if (strcmp(input, "exit") == 0) {
            break;
        } else if (strcmp(input, "role") == 0) {
            set_system_message();
            continue;
        }

        char auth_header[512];
        snprintf(auth_header, sizeof(auth_header), "Authorization: Bearer %s", api_key);

        snprintf(request_body, sizeof(request_body),
                 "{\"model\": \"gpt-3.5-turbo\", \"messages\": ["
                 "{\"role\": \"system\", \"content\": \"%s\"},"
                 "{\"role\": \"user\", \"content\": \"%s\"}]}",
                 system_message, input);

        response = make_request(request_body, auth_header);
        if (response) {
            extracted_content = extract_content(response);
            if (extracted_content) {
                printf("AI: %s\n", extracted_content);
                free(extracted_content);
            } else {
                printf("Failed to extract content from response.\n");
            }
            free(response);
        } else {
            printf("Failed to get a response from the API.\n");
        }
    }

    return 0;
}

it works on windows 11

you compile it like so:

gcc openai_chatbot.c -o openai_chatbot.exe -lwinhttp

now about the libcurl and libcjson and zlib you will need git to clone the source files and build from source and install:

git clone https://github.com/DaveGamble/cJSON.git
cd cJSON
mkdir build
cd build
cmake .. -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=C:/MinGW -DENABLE_CJSON_TEST=Off -DENABLE_CJSON_UTILS=Off
mingw32-make
mingw32-make install

git clone https://github.com/madler/zlib.git
cd zlib
mkdir build
cd build
cmake .. -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=C:/MinGW
mingw32-make
mingw32-make install

cd ../..
git clone https://github.com/curl/curl.git
cd curl
mkdir build
cd build
cmake .. -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=C:/MinGW -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DCURL_STATICLIB=ON
mingw32-make
mingw32-make install

Make sure to replace C:/MinGW with the actual path to your MinGW installation.

ron77

OK and here is the same code in C for Antropic API chatbot

#include <stdio.h>
#include <windows.h>
#include <winhttp.h>
#include <stdlib.h>
#include <string.h>

#pragma comment(lib, "winhttp.lib")

#define MAX_RESPONSE_SIZE 16384
#define MAX_REQUEST_SIZE 8192
#define MAX_SYSTEM_MESSAGE_SIZE 4092
#define MAX_INPUT_SIZE 1024
#define MAX_COMMAND_SIZE 2048

char system_message[MAX_SYSTEM_MESSAGE_SIZE] = "You are my Spirit Guide, a wise and benevolent being here to help me navigate my life's journey. I seek your guidance and advice as I walk my path in this world. Please offer me the wisdom I need, help me stay on the right course, and hear me when I call out for support. I trust in your presence and am open to the insights you provide to guide me through life.";

char* make_request(const char* request_body, const char* auth_header) {
    DWORD dwSize = 0;
    DWORD dwDownloaded = 0;
    LPSTR pszOutBuffer;
    BOOL  bResults = FALSE;
    HINTERNET  hSession = NULL, 
               hConnect = NULL,
               hRequest = NULL;

    hSession = WinHttpOpen(L"Claude API Client",  
                           WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                           WINHTTP_NO_PROXY_NAME, 
                           WINHTTP_NO_PROXY_BYPASS, 0);

    if (hSession == NULL) {
        printf("Error %lu in WinHttpOpen.\n", GetLastError());
        return NULL;
    }

    hConnect = WinHttpConnect(hSession, L"api.anthropic.com",
                              INTERNET_DEFAULT_HTTPS_PORT, 0);

    if (hConnect == NULL) {
        printf("Error %lu in WinHttpConnect.\n", GetLastError());
        WinHttpCloseHandle(hSession);
        return NULL;
    }

    hRequest = WinHttpOpenRequest(hConnect, L"POST", L"/v1/messages",
                                  NULL, WINHTTP_NO_REFERER, 
                                  WINHTTP_DEFAULT_ACCEPT_TYPES, 
                                  WINHTTP_FLAG_SECURE);

    if (hRequest == NULL) {
        printf("Error %lu in WinHttpOpenRequest.\n", GetLastError());
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return NULL;
    }

    // Convert auth_header to wide string
    wchar_t wide_auth_header[512];
    MultiByteToWideChar(CP_UTF8, 0, auth_header, -1, wide_auth_header, 512);

    WinHttpAddRequestHeaders(hRequest, L"Content-Type: application/json", -1, WINHTTP_ADDREQ_FLAG_ADD);
    WinHttpAddRequestHeaders(hRequest, wide_auth_header, -1, WINHTTP_ADDREQ_FLAG_ADD);
    WinHttpAddRequestHeaders(hRequest, L"anthropic-version: 2023-06-01", -1, WINHTTP_ADDREQ_FLAG_ADD);

    bResults = WinHttpSendRequest(hRequest,
                                  WINHTTP_NO_ADDITIONAL_HEADERS, 0,
                                  (LPVOID)request_body, strlen(request_body),
                                  strlen(request_body), 0);

    if (!bResults) {
        printf("Error %lu in WinHttpSendRequest.\n", GetLastError());
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return NULL;
    }

    bResults = WinHttpReceiveResponse(hRequest, NULL);

    if (!bResults) {
        printf("Error %lu in WinHttpReceiveResponse.\n", GetLastError());
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return NULL;
    }

    pszOutBuffer = (LPSTR)malloc(MAX_RESPONSE_SIZE);
    if (!pszOutBuffer) {
        printf("Failed to allocate memory\n");
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return NULL;
    }
    ZeroMemory(pszOutBuffer, MAX_RESPONSE_SIZE);

    DWORD total_size = 0;
    if (bResults) {
        do {
            dwSize = 0;
            if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
                printf("Error %lu in WinHttpQueryDataAvailable.\n", GetLastError());
                break;
            }

            if (dwSize + total_size > MAX_RESPONSE_SIZE) {
                printf("Response too large, truncating.\n");
                dwSize = MAX_RESPONSE_SIZE - total_size;
            }

            if (!WinHttpReadData(hRequest, (LPVOID)(pszOutBuffer + total_size), 
                                 dwSize, &dwDownloaded)) {
                printf("Error %lu in WinHttpReadData.\n", GetLastError());
                break;
            }

            total_size += dwDownloaded;
        } while (dwSize > 0 && total_size < MAX_RESPONSE_SIZE);
    }

    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);

    return pszOutBuffer;
}

char* extract_content(const char* json_response) {
    char* content_start = strstr(json_response, "\"content\":[");
    if (content_start == NULL) {
        printf("Could not find 'content' in response.\n");
        return NULL;
    }
    
    content_start = strstr(content_start, "\"text\":\"");
    if (content_start == NULL) {
        printf("Could not find 'text' in content.\n");
        return NULL;
    }
    content_start += 8; // Move past "\"text\":\""
    
    char* content_end = strstr(content_start, "\"}");
    if (content_end == NULL) {
        printf("Could not find end of content in response.\n");
        return NULL;
    }

    int content_length = content_end - content_start;
    char* content = (char*)malloc(content_length + 1);
    strncpy(content, content_start, content_length);
    content[content_length] = '\0';

    return content;
}

void set_system_message() {
    printf("Enter new system message (max %d characters):\n", MAX_SYSTEM_MESSAGE_SIZE - 1);
    fgets(system_message, sizeof(system_message), stdin);
    system_message[strcspn(system_message, "\n")] = 0;  // Remove newline
    printf("System message updated.\n");
}

void speak_text(const char* text) {
    char command[MAX_COMMAND_SIZE];
    snprintf(command, sizeof(command), "voice.exe -n \"Microsoft Zira Desktop\" \"%s\"", text);
    
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    if (!CreateProcess(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
        printf("CreateProcess failed (%lu).\n", GetLastError());
        return;
    }

    // Wait for the TTS process to finish
    WaitForSingleObject(pi.hProcess, INFINITE);

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

int main() {
    char input[MAX_INPUT_SIZE];
    char request_body[MAX_REQUEST_SIZE];
    char* response;
    char* extracted_content;
    
    char api_key[256];
    printf("Enter your Anthropic API key: ");
    fgets(api_key, sizeof(api_key), stdin);
    api_key[strcspn(api_key, "\n")] = 0;  // Remove newline

    while (1) {
        printf("You (type 'exit' to quit, 'role' to change system message): ");
        fgets(input, sizeof(input), stdin);
        input[strcspn(input, "\n")] = 0;  // Remove newline

        if (strcmp(input, "exit") == 0) {
            break;
        } else if (strcmp(input, "role") == 0) {
            set_system_message();
            continue;
        }

        char auth_header[512];
        snprintf(auth_header, sizeof(auth_header), "x-api-key: %s", api_key);

        snprintf(request_body, sizeof(request_body),
                 "{\"model\": \"claude-3-sonnet-20240229\", \"system\": \"%s\", \"messages\": ["
                 "{\"role\": \"user\", \"content\": \"%s\"}],"
                 "\"max_tokens\": 1000}",
                 system_message, input);

        response = make_request(request_body, auth_header);
        if (response) {
            if (strstr(response, "\"error\":") != NULL) {
                printf("API Error Response:\n%s\n", response);
            } else {
                extracted_content = extract_content(response);
                if (extracted_content) {
                    printf("AI: %s\n", extracted_content);
                    speak_text(extracted_content);
                    free(extracted_content);
                } else {
                    printf("Failed to extract content from response.\n");
                    printf("Full API Response:\n%s\n", response);
                }
            }
            free(response);
        } else {
            printf("Failed to get a response from the API.\n");
        }
    }

    return 0;
}

ron77

ok modifiyed antropic API chatbot in C this time with logging of conversations in history folder
don't forget to add the TTS cli engine wrapper voice.exe

#include <stdio.h>
#include <windows.h>
#include <winhttp.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#pragma comment(lib, "winhttp.lib")

#define MAX_RESPONSE_SIZE 16384
#define MAX_REQUEST_SIZE 8192
#define MAX_SYSTEM_MESSAGE_SIZE 4092
#define MAX_INPUT_SIZE 3000
#define MAX_COMMAND_SIZE 2048
#define MAX_FILENAME_SIZE 256

char system_message[MAX_SYSTEM_MESSAGE_SIZE] = "You are my Spirit Guide, a wise and benevolent being here to help me navigate my life's journey. I seek your guidance and advice as I walk my path in this world. Please offer me the wisdom I need, help me stay on the right course, and hear me when I call out for support. I trust in your presence and am open to the insights you provide to guide me through life.";

char* make_request(const char* request_body, const char* auth_header) {
    DWORD dwSize = 0;
    DWORD dwDownloaded = 0;
    LPSTR pszOutBuffer;
    BOOL  bResults = FALSE;
    HINTERNET  hSession = NULL, 
               hConnect = NULL,
               hRequest = NULL;

    hSession = WinHttpOpen(L"Claude API Client",  
                           WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                           WINHTTP_NO_PROXY_NAME, 
                           WINHTTP_NO_PROXY_BYPASS, 0);

    if (hSession == NULL) {
        printf("Error %lu in WinHttpOpen.\n", GetLastError());
        return NULL;
    }

    hConnect = WinHttpConnect(hSession, L"api.anthropic.com",
                              INTERNET_DEFAULT_HTTPS_PORT, 0);

    if (hConnect == NULL) {
        printf("Error %lu in WinHttpConnect.\n", GetLastError());
        WinHttpCloseHandle(hSession);
        return NULL;
    }

    hRequest = WinHttpOpenRequest(hConnect, L"POST", L"/v1/messages",
                                  NULL, WINHTTP_NO_REFERER, 
                                  WINHTTP_DEFAULT_ACCEPT_TYPES, 
                                  WINHTTP_FLAG_SECURE);

    if (hRequest == NULL) {
        printf("Error %lu in WinHttpOpenRequest.\n", GetLastError());
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return NULL;
    }

    // Convert auth_header to wide string
    wchar_t wide_auth_header[512];
    MultiByteToWideChar(CP_UTF8, 0, auth_header, -1, wide_auth_header, 512);

    WinHttpAddRequestHeaders(hRequest, L"Content-Type: application/json", -1, WINHTTP_ADDREQ_FLAG_ADD);
    WinHttpAddRequestHeaders(hRequest, wide_auth_header, -1, WINHTTP_ADDREQ_FLAG_ADD);
    WinHttpAddRequestHeaders(hRequest, L"anthropic-version: 2023-06-01", -1, WINHTTP_ADDREQ_FLAG_ADD);

    bResults = WinHttpSendRequest(hRequest,
                                  WINHTTP_NO_ADDITIONAL_HEADERS, 0,
                                  (LPVOID)request_body, strlen(request_body),
                                  strlen(request_body), 0);

    if (!bResults) {
        printf("Error %lu in WinHttpSendRequest.\n", GetLastError());
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return NULL;
    }

    bResults = WinHttpReceiveResponse(hRequest, NULL);

    if (!bResults) {
        printf("Error %lu in WinHttpReceiveResponse.\n", GetLastError());
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return NULL;
    }

    pszOutBuffer = (LPSTR)malloc(MAX_RESPONSE_SIZE);
    if (!pszOutBuffer) {
        printf("Failed to allocate memory\n");
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return NULL;
    }
    ZeroMemory(pszOutBuffer, MAX_RESPONSE_SIZE);

    DWORD total_size = 0;
    if (bResults) {
        do {
            dwSize = 0;
            if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
                printf("Error %lu in WinHttpQueryDataAvailable.\n", GetLastError());
                break;
            }

            if (dwSize + total_size > MAX_RESPONSE_SIZE) {
                printf("Response too large, truncating.\n");
                dwSize = MAX_RESPONSE_SIZE - total_size;
            }

            if (!WinHttpReadData(hRequest, (LPVOID)(pszOutBuffer + total_size), 
                                 dwSize, &dwDownloaded)) {
                printf("Error %lu in WinHttpReadData.\n", GetLastError());
                break;
            }

            total_size += dwDownloaded;
        } while (dwSize > 0 && total_size < MAX_RESPONSE_SIZE);
    }

    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);

    return pszOutBuffer;
}

char* extract_content(const char* json_response) {
    char* content_start = strstr(json_response, "\"content\":[");
    if (content_start == NULL) {
        printf("Could not find 'content' in response.\n");
        return NULL;
    }
    
    content_start = strstr(content_start, "\"text\":\"");
    if (content_start == NULL) {
        printf("Could not find 'text' in content.\n");
        return NULL;
    }
    content_start += 8; // Move past "\"text\":\""
    
    char* content_end = strstr(content_start, "\"}");
    if (content_end == NULL) {
        printf("Could not find end of content in response.\n");
        return NULL;
    }

    int content_length = content_end - content_start;
    char* content = (char*)malloc(content_length + 1);
    strncpy(content, content_start, content_length);
    content[content_length] = '\0';

    return content;
}

void set_system_message() {
    printf("Enter new system message (max %d characters):\n", MAX_SYSTEM_MESSAGE_SIZE - 1);
    fgets(system_message, sizeof(system_message), stdin);
    system_message[strcspn(system_message, "\n")] = 0;  // Remove newline
    printf("System message updated.\n");
}

void speak_text(const char* text) {
    char command[MAX_COMMAND_SIZE];
    snprintf(command, sizeof(command), "voice.exe -n \"Microsoft Zira Desktop\" \"%s\"", text);
    
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    if (!CreateProcess(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
        printf("CreateProcess failed (%lu).\n", GetLastError());
        return;
    }

    // Wait for the TTS process to finish
    WaitForSingleObject(pi.hProcess, INFINITE);

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

void log_message(FILE* log_file, const char* role, const char* message) {
    time_t now;
    struct tm *local_time;
    char timestamp[26];

    time(&now);
    local_time = localtime(&now);
    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", local_time);

    fprintf(log_file, "[%s] %s: %s\n", timestamp, role, message);
    fflush(log_file);  // Ensure the message is written immediately
}

int main() {
    char input[MAX_INPUT_SIZE];
    char request_body[MAX_REQUEST_SIZE];
    char* response;
    char* extracted_content;
    
    char api_key[256];
    printf("Enter your Anthropic API key: ");
    fgets(api_key, sizeof(api_key), stdin);
    api_key[strcspn(api_key, "\n")] = 0;  // Remove newline

    // Create log file
    char log_filename[MAX_FILENAME_SIZE];
    time_t now = time(NULL);
    struct tm *t = localtime(&now);
    strftime(log_filename, sizeof(log_filename), "history/conversation_%Y%m%d_%H%M%S.log", t);

    FILE* log_file = fopen(log_filename, "w");
    if (log_file == NULL) {
        printf("Failed to create log file.\n");
        return 1;
    }

    printf("Conversation will be logged to: %s\n", log_filename);

    // Log the system message
    log_message(log_file, "SYSTEM", system_message);

    while (1) {
        printf("You (type 'exit' to quit, 'role' to change system message): ");
        fgets(input, sizeof(input), stdin);
        input[strcspn(input, "\n")] = 0;  // Remove newline

        if (strcmp(input, "exit") == 0) {
            break;
        } else if (strcmp(input, "role") == 0) {
            set_system_message();
            log_message(log_file, "SYSTEM", system_message);
            continue;
        }

        // Log user input
        log_message(log_file, "USER", input);

        char auth_header[512];
        snprintf(auth_header, sizeof(auth_header), "x-api-key: %s", api_key);

        snprintf(request_body, sizeof(request_body),
                 "{\"model\": \"claude-3-sonnet-20240229\", \"system\": \"%s\", \"messages\": ["
                 "{\"role\": \"user\", \"content\": \"%s\"}],"
                 "\"max_tokens\": 1000}",
                 system_message, input);

        response = make_request(request_body, auth_header);
        if (response) {
            if (strstr(response, "\"error\":") != NULL) {
                printf("API Error Response:\n%s\n", response);
                log_message(log_file, "ERROR", response);
            } else {
                extracted_content = extract_content(response);
                if (extracted_content) {
                    printf("AI: %s\n", extracted_content);
                    speak_text(extracted_content);
                    // Log AI response
                    log_message(log_file, "AI", extracted_content);
                    free(extracted_content);
                } else {
                    printf("Failed to extract content from response.\n");
                    printf("Full API Response:\n%s\n", response);
                    log_message(log_file, "ERROR", "Failed to extract content from response");
                }
            }
            free(response);
        } else {
            printf("Failed to get a response from the API.\n");
            log_message(log_file, "ERROR", "Failed to get a response from the API");
        }
    }

    fclose(log_file);
    printf("Conversation log saved to: %s\n", log_filename);

    return 0;
}