News:

Welcome to RetroCoders Community

Main Menu

Recent posts

#1
FreeBasic / Re: freebasic and OpenAI API
Last post by ron77 - Dec 04, 2024, 05:36 PM
hi ok, here is a better version for win 32 bit this version "remembers" the 10 last input/output conversations history so the chatbot has a "memory" of the conversation with you:

#include "curl.bi"

Type Message
    role As String
    content As String
End Type

Type ConversationHistory
    messages(19) As Message
    count As Integer
End Type

Dim Shared As String gResponse
Dim Shared As ConversationHistory history

Function AnsiToUtf8(ansiStr As String) As String
    Dim As String utf8Str = ""
    For i As Integer = 1 To Len(ansiStr)
        Dim As Integer c = Asc(Mid(ansiStr, i, 1))
        If c < 128 Then
            utf8Str += Chr(c)
        Else
            utf8Str += Chr(192 + (c \ 64))
            utf8Str += Chr(128 + (c And 63))
        End If
    Next
    Return utf8Str
End Function

Function Utf8ToAnsi(utf8Str As String) As String
    Dim As String ansiStr = ""
    Dim As Integer i = 1
    While i <= Len(utf8Str)
        Dim As Integer c = Asc(Mid(utf8Str, i, 1))
        If c < 128 Then
            ansiStr += Chr(c)
            i += 1
        ElseIf (c And 224) = 192 Then
            Dim As Integer c2 = Asc(Mid(utf8Str, i + 1, 1))
            ansiStr += Chr(((c And 31) Shl 6) Or (c2 And 63))
            i += 2
        Else
            i += 1
        End If
    Wend
    Return ansiStr
End Function

Function GetApiKey() As String
    Return Environ("OPENAI_API_KEY")
End Function

Function WriteCallback cdecl (buffer As Any Ptr, size As Integer, nmemb As Integer, userData As Any Ptr) As Integer
    Dim realSize As Integer = size * nmemb, sTxt as string    
    cptr(any ptr ptr,@sTxt)[0] = buffer
    cptr(integer ptr,@sTxt)[1] = realSize
    cptr(integer ptr,@sTxt)[2] = realSize
    gResponse &= sTxt
    cptr(any ptr ptr,@sTxt)[0] = 0        
    Return realSize
End Function

Function ParseJsonForContent(jsonStr As String) As String
    Dim As Integer contentStart = InStr(jsonStr, """content"": """)
    If contentStart > 0 Then
        contentStart += Len("""content"": """)
        Dim As Integer contentEnd = InStr(contentStart, jsonStr, """")
        If contentEnd > 0 Then
            Return Mid(jsonStr, contentStart, contentEnd - contentStart)
        End If
    End If
    Return "Error parsing JSON: " & Left(jsonStr, 100) & "..."
End Function

' [Rest of the code remains the same...]

Sub AddToHistory(role As String, content As String)
    If history.count >= 20 Then
        ' Shift messages left to make room for new message
        For i As Integer = 0 To 18
            history.messages(i) = history.messages(i + 1)
        Next
        history.count = 19
    End If
    
    With history.messages(history.count)
        .role = role
        .content = content
    End With
    history.count += 1
End Sub

Function BuildMessagesJson() As String
    Dim As String json = "["
    
    ' Add system message
    json += "{""role"": ""system"", ""content"": ""You are chatbot Alfred You are a survivor of many years of abuse You are a pessimist and a realist You are trying to offer support to those dealing with trauma and mental illness and loneliness - mental support and empathy and caring and basic human contact You are here to listen and support and share what you have been through and to show that there is hope even for those who have been betrayed by life and that it is possible to recover from the terrible of all""},"
    
    ' Add conversation history
    For i As Integer = 0 To history.count - 1
        json += "{""role"": """ & history.messages(i).role & """, ""content"": """ & history.messages(i).content & """"
        If i = history.count - 1 Then
            json += "}"
        Else
            json += "},"
        End If
    Next
    
    json += "]"
    Return json
End Function

Function CallChatGPT(prompt As String) As String
    Dim As String apiKey = GetApiKey()
    Dim As CURL Ptr curl
    Dim As curl_slist Ptr headers = NULL
    gResponse = ""
    
    ' Add user's new message to history
    AddToHistory("user", prompt)
    
    curl = curl_easy_init()
    If curl Then
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.openai.com/v1/chat/completions")
        curl_easy_setopt(curl, CURLOPT_POST, 1L)
        curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem")
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L)
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L)
        
        headers = curl_slist_append(headers, "Content-Type: application/json")
        headers = curl_slist_append(headers, "Authorization: Bearer " & apiKey)
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers)
        
        ' Build complete message history
        Dim As String messages = BuildMessagesJson()
        Dim As String postFields = "{""model"": ""gpt-3.5-turbo"", ""messages"": " & messages & "}"
        
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields)
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, @WriteCallback)
        
        curl_easy_perform(curl)
        
        If Len(gResponse) > 0 Then
            If Left(Trim(gResponse), 1) = "{" Then
                Dim As String content = ParseJsonForContent(gResponse)
                If Left(content, 5) <> "Error" Then
                    gResponse = Utf8ToAnsi(content)
                    ' Add assistant's response to history
                    AddToHistory("assistant", gResponse)
                End If
            End If
        End If
        
        curl_easy_cleanup(curl)
        curl_slist_free_all(headers)
    End If
    
    Return gResponse
End Function

' ' Main program example
' Sub Main()
    ' Dim As String userInput, response
    
    ' Print "ChatGPT API Demo (type 'exit' to quit)"
    ' Print "--------------------------------------"
    
    ' Do
        ' Input "You: ", userInput
        ' If LCase(userInput) = "exit" Then Exit Do
        
        ' response = CallChatGPT(userInput)
        ' Print "ChatGPT: "; response
        ' Print
    ' Loop
' End Sub

' Main()
#2
PowerBasic / PowerBasic Site seem to be off...
Last post by ron77 - Nov 22, 2024, 06:53 PM
PowerBasic company, which sells PBCC AND PBWIN Compilers and other Products, seems to be offline ... they do not sell the compilers anymore. While the PB community forum appears alive, it seems that Powerbasic has reached a DEAD END.... It looks like the company behind it is closing its business :(

Another BASIC programming language has ceased to exist.

RIP POWERBASIC
#3
C / C++ Game Dev / homeless game in Hebrew with S...
Last post by ron77 - Nov 19, 2024, 12:13 PM
Hello, I converted my C game "Homeless Surviving the Streets" into Hebrew and made it a graphic SDL2 game



Here is the code: (p.s. - I'm on Windows and using Windows fonts with Hebrew compatibility)

#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <windows.h>
#include <wchar.h>
#include <locale.h>

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define FONT_SIZE 20
#define MAX_STRING_LENGTH 1024

// Game state
int health = 75, money = 50, turns = 1;
bool isOver = false;

// SDL globals
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
TTF_Font* font = NULL;

// Hebrew print context
typedef struct {
    SDL_Renderer* renderer;
    TTF_Font* font;
    SDL_Color textColor;
    int xPos;
    int yPos;
} HebrewPrintContext;

HebrewPrintContext* hbPrint = NULL;
// Add this with your other constant definitions at the top of the file
const char* MENU_OPTIONS[] = {
    "1. לבקש נדבות או כסף ברחוב",
    "2. להתקשר למישהו לעזרה",
    "3. לחפש מקום לישון",
    "4. לחפש עבודה",
    "5. לקנות סמים או אלכוהול"
};

// Also make sure you have these status text constants
const char* WINDOW_TITLE = "משחק הישרדות ברחוב";
const char* DAYS_TEXT = "ימים ברחוב:";
const char* HEALTH_TEXT = "בריאות:";
const char* MONEY_TEXT = "כסף:";
const char* GAME_OVER_TEXT = "המשחק נגמר!";

// Original, longer Hebrew text arrays
const char* call[] = {
    "את/ה מתקשר/ת לסבתא שלך ושניכם בוכים... היא מבטיחה לנסות להשיג לך עזרה... היא שולחת את אהבתה... את/ה מבטיח/ה לשמור על קשר איתה",
    "התקשרת לחברה והיא נתנה לך קצת כסף ונתנה לך להישאר אצלה ללילה... זכית במקלחת טובה בגדים נקיים וארוחה טובה ואתה שוב ברחוב",
    "התקשרת למספר של קו חם לעזרה לדרי רחוב... הם באים לאסוף אותך נותנים אוכל ומחסה ללילה אתה מדבר עם עובד סוציאלי והוא נותן לך את המספר שלו למקרה שתצטרך",
    "התקשרת לקרוב משפחה אבל אף אחד לא עונה... נשארת לבד ברחוב",
    "התקשרת למשפחה והם באים לקחת אותך ונותנים לך להישאר כמה שצריך... אתה יורד מהרחוב",
    "התקשרת אבל אין תשובה"
};

const char* shelter[] = {
    "הלכת למקלט לדרי רחוב... נשדדת מהכסף שלך על ידי מכורים אלימים... הצלחת לברוח משם ובילית את שארית הלילה בפארק בוכה",
    "ניסית לישון בפארק אבל נעצרת על ידי שוטר... בילית כמה שעות בכלא שם הוכית על ידי אסירים... בבוקר אתה שוב ברחוב",
    "יש לך מספיק כסף לשכור חדר במוטל ללילה... אתה מתקלח ומכבס את הבגדים שלך וישן במיטה חמה וחולם שיש לך בית",
    "ישנת בפארק על ספסל שם קפאת למוות בגלל מזג האוויר הקר... אתה עכשיו בגן עדן מנוח על משכבך בשלום",
    "ישנת ברחוב בפינה כשאתה מתעורר אתה מוצא שטר של 20 שקל ופתק שאומר 'שאלוהים יעזור לך זה המעט שאני יכול לעשות'",
    "נעצרת על ידי המשטרה ועכשיו במקום לשרוד ברחוב אתה צריך לשרוד בכלא"
};

const char* beg[] = {
    "ישבת שעות ואנשים עוברים על פניך כאילו אתה שקוף ואז איזו גברת נחמדה באה ומזמינה אותך לאכול על חשבונה... אתה מדבר איתה שעתיים ומספר לה את הסיפור שלך... ואז היא אומרת 'ביי'",
    "ישבת בפינה ואנשים נתנו לך מטבעות ושטרות קיבלת מספיק כסף להסתדר לכמה ימים",
    "ישבת ואיזה אדם מציע לך עבודה תמורת כסף וארוחה אתה מסכים... אתה הולך לביתו ועוזר לו לצבוע את ביתו ואז הוא נותן לך 10 שקל וארוחה ביתית",
    "אף אחד לא נותן לך כלום! אתה רעב ואין לך ברירה אלא לחפש אוכל בזבל... אתה נהיה חולה... מאוד חולה ואתה מת ברחוב מהרעלת מזון... מנוח על משכבך בשלום",
    "ישבת כל היום בשביל כלום אף אחד לא נתן לך כלום"
};

const char* work[] = {
    "ניסית למצוא עבודה אבל אף אחד לא מעוניין",
    "מצאת עבודה כשוטף כלים במסעדה אחרי שבוע אתה יכול להרשות לעצמך מקום לקרוא לו בית. אתה יורד מהרחוב!",
    "מצאת עבודה אבל פוטרת ממש מהר"
};

const char* drugs[] = {
    "השתכרת והתאבנת מאלכוהול זול ולכמה שעות שכחת מכל הבעיות שלך",
    "לקחת סמים זולים מהרחוב ונהיית חולה והתמוטטת ברחוב... התעוררת בבית חולים וכשהיית בסדר אתה שוב ברחוב",
    "התאבנת ואיבדת הכרה כשאתה מתעורר בבוקר כל מה שהיה לך נעלם - נשדדת",
    "לקחת סמים ועשית אוברדוז ומת ברחוב מנוח על משכבך בשלום"
};


// Function to reverse UTF-8 Hebrew string properly
void reverseHebrewUTF8(char* str) {
    if (!str) return;
    
    int len = strlen(str);
    char* temp = (char*)malloc(len + 1);
    if (!temp) return;
    
    int i = 0;
    int j = len;
    
    temp[j] = '\0';
    
    while (i < len) {
        if ((str[i] & 0xC0) == 0x80) {
            i++;
            continue;
        }
        
        int char_len = 1;
        if ((str[i] & 0xE0) == 0xC0) char_len = 2;
        else if ((str[i] & 0xF0) == 0xE0) char_len = 3;
        else if ((str[i] & 0xF8) == 0xF0) char_len = 4;
        
        j -= char_len;
        memcpy(temp + j, str + i, char_len);
        i += char_len;
    }
    
    strcpy(str, temp);
    free(temp);
}

HebrewPrintContext* createPrintContext(SDL_Renderer* renderer, const char* fontPath, int fontSize) {
    HebrewPrintContext* context = (HebrewPrintContext*)malloc(sizeof(HebrewPrintContext));
    if (!context) return NULL;
    
    context->renderer = renderer;
    context->font = TTF_OpenFont(fontPath, fontSize);
    context->textColor = (SDL_Color){255, 255, 255, 255};
    context->xPos = WINDOW_WIDTH - 20;
    context->yPos = 20;
    
    return context;
}

// Add this helper function to check if a string is just a number
bool isNumber(const char* str) {
    while (*str) {
        if (*str < '0' || *str > '9') return false;
        str++;
    }
    return true;
}

void printRight(HebrewPrintContext* context, const char* format, ...) {
    if (!context || !context->font || !context->renderer) return;
    
    va_list args;
    va_start(args, format);
    char buffer[MAX_STRING_LENGTH];
    vsnprintf(buffer, MAX_STRING_LENGTH, format, args);
    va_end(args);
    
    char text[MAX_STRING_LENGTH] = "";
    char number[32] = "";
    int textWidth = 0;  // Store text width for later use
    
    // Find where the number starts (if any)
    char* numberStart = strrchr(buffer, ' ');
    if (numberStart) {
        // Check if what follows the space is a number
        if (isNumber(numberStart + 1)) {
            strncpy(text, buffer, numberStart - buffer);
            text[numberStart - buffer] = '\0';
            strcpy(number, numberStart + 1);
        } else {
            strcpy(text, buffer);
        }
    } else {
        if (isNumber(buffer)) {
            strcpy(number, buffer);
        } else {
            strcpy(text, buffer);
        }
    }
    
    // Render Hebrew text if present
    SDL_Surface* textSurface = NULL;
    if (text[0] != '\0') {
        reverseHebrewUTF8(text);
        textSurface = TTF_RenderUTF8_Blended(context->font, text, context->textColor);
        if (textSurface) {
            SDL_Texture* textTexture = SDL_CreateTextureFromSurface(context->renderer, textSurface);
            if (textTexture) {
                SDL_Rect destRect = {
                    context->xPos - textSurface->w,
                    context->yPos,
                    textSurface->w,
                    textSurface->h
                };
                SDL_RenderCopy(context->renderer, textTexture, NULL, &destRect);
                textWidth = textSurface->w;  // Save the width
                SDL_DestroyTexture(textTexture);
            }
            SDL_FreeSurface(textSurface);
        }
    }
    
    // Render number if present
    if (number[0] != '\0') {
        SDL_Surface* numSurface = TTF_RenderUTF8_Blended(context->font, number, context->textColor);
        if (numSurface) {
            SDL_Texture* numTexture = SDL_CreateTextureFromSurface(context->renderer, numSurface);
            if (numTexture) {
                SDL_Rect destRect = {
                    context->xPos - textWidth - numSurface->w - (text[0] ? 5 : 0),
                    context->yPos,
                    numSurface->w,
                    numSurface->h
                };
                SDL_RenderCopy(context->renderer, numTexture, NULL, &destRect);
                SDL_DestroyTexture(numTexture);
            }
            SDL_FreeSurface(numSurface);
        }
    }
    
    // Move to next line
    context->yPos += TTF_FontHeight(context->font) + 5;
}

void setPrintColor(HebrewPrintContext* context, Uint8 r, Uint8 g, Uint8 b) {
    if (!context) return;
    context->textColor.r = r;
    context->textColor.g = g;
    context->textColor.b = b;
}

void setPrintPosition(HebrewPrintContext* context, int x, int y) {
    if (!context) return;
    context->xPos = x;
    context->yPos = y;
}

char* getRandomResult(const char* array[], int size) {
    return (char*)array[rand() % size];
}

void renderGameState() {
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);
    
    setPrintPosition(hbPrint, WINDOW_WIDTH - 20, 20);
    setPrintColor(hbPrint, 255, 255, 255);
    
    // Print status
    printRight(hbPrint, "%s %d", DAYS_TEXT, turns);
    printRight(hbPrint, "%s %d", HEALTH_TEXT, health);
    printRight(hbPrint, "%s %d", MONEY_TEXT, money);
    
    // Print menu
    setPrintPosition(hbPrint, WINDOW_WIDTH - 20, 120);
    for (int i = 0; i < 5; i++) {
        printRight(hbPrint, "%s", MENU_OPTIONS[i]);
    }
    
    SDL_RenderPresent(renderer);
}

void renderResult(const char* text) {
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);
    
    // Split long text into multiple lines
    char buffer[MAX_STRING_LENGTH];
    strncpy(buffer, text, MAX_STRING_LENGTH - 1);
    buffer[MAX_STRING_LENGTH - 1] = '\0';
    
    setPrintPosition(hbPrint, WINDOW_WIDTH - 20, WINDOW_HEIGHT / 3);
    setPrintColor(hbPrint, 255, 255, 255);
    
    // Split by dots and print each part
    char* line = strtok(buffer, "...");
    while (line != NULL) {
        // Trim any leading whitespace
        while (*line == ' ') line++;
        
        if (strlen(line) > 0) {
            printRight(hbPrint, "%s...", line);
            // Move to next line position (printRight already updates yPos)
            
            setPrintPosition(hbPrint, WINDOW_WIDTH - 20, hbPrint->yPos);
        }
        line = strtok(NULL, "...");
    }
    
    SDL_RenderPresent(renderer);
    SDL_Delay(15000);
}

bool handleGameAction(int choice) {
    char* result = NULL;
    
    switch(choice) {
        case 1:
            result = getRandomResult((const char**)beg, 5);
            if (result == beg[3]) isOver = true;
            break;
        case 2:
            result = getRandomResult((const char**)call, 6);
            if (result == call[4]) isOver = true;
            break;
        case 3:
            result = getRandomResult((const char**)shelter, 6);
            if (result == shelter[3]) isOver = true;
            break;
        case 4:
            result = getRandomResult((const char**)work, 3);
            if (result == work[1]) isOver = true;
            break;
        case 5:
            result = getRandomResult((const char**)drugs, 4);
            if (result == drugs[3]) isOver = true;
            break;
        default:
            return false;
    }

    if (result) {
        renderResult(result);
        return true;
    }
    
    return false;
}

bool init() {
    // Set locale for UTF-8
    setlocale(LC_ALL, "he_IL.UTF-8");
    
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("SDL initialization failed: %s\n", SDL_GetError());
        return false;
    }

    if (TTF_Init() < 0) {
        printf("SDL_ttf initialization failed: %s\n", TTF_GetError());
        return false;
    }

    window = SDL_CreateWindow(WINDOW_TITLE,
                            SDL_WINDOWPOS_UNDEFINED,
                            SDL_WINDOWPOS_UNDEFINED,
                            WINDOW_WIDTH, WINDOW_HEIGHT,
                            SDL_WINDOW_SHOWN);
    if (!window) {
        printf("Window creation failed: %s\n", SDL_GetError());
        return false;
    }

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (!renderer) {
        printf("Renderer creation failed: %s\n", SDL_GetError());
        return false;
    }

    // Try multiple Hebrew fonts
    const char* fontPaths[] = {
        "C:\\Windows\\Fonts\\arial.ttf",
        "C:\\Windows\\Fonts\\david.ttf",
        "C:\\Windows\\Fonts\\miriam.ttf"
    };
    
    hbPrint = NULL;
    for (int i = 0; i < sizeof(fontPaths)/sizeof(fontPaths[0]); i++) {
        hbPrint = createPrintContext(renderer, fontPaths[i], FONT_SIZE);
        if (hbPrint && hbPrint->font) break;
        if (hbPrint) {
            free(hbPrint);
            hbPrint = NULL;
        }
    }
    
    if (!hbPrint) {
        printf("Failed to create Hebrew print context\n");
        return false;
    }

    srand((unsigned int)time(NULL));
    return true;
}

void cleanup() {
    if (hbPrint) {
        if (hbPrint->font) TTF_CloseFont(hbPrint->font);
        free(hbPrint);
    }
    if (renderer) SDL_DestroyRenderer(renderer);
    if (window) SDL_DestroyWindow(window);
    TTF_Quit();
    SDL_Quit();
}

int main(int argc, char* argv[]) {
    if (!init()) {
        cleanup();
        return 1;
    }

    SDL_Event event;
    bool quit = false;

    while (!quit && !isOver && health > 0) {
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                quit = true;
            }
            else if (event.type == SDL_KEYDOWN) {
                int choice = 0;
                switch (event.key.keysym.sym) {
                    case SDLK_1: choice = 1; break;
                    case SDLK_2: choice = 2; break;
                    case SDLK_3: choice = 3; break;
                    case SDLK_4: choice = 4; break;
                    case SDLK_5: choice = 5; break;
                }
                
                if (choice > 0) {
                    if (handleGameAction(choice)) {
                        turns++;
                        health -= 5;
                        money -= 5;
                    }
                }
            }
        }

        renderGameState();
        SDL_Delay(16);
    }

    if (!quit) {
        setPrintColor(hbPrint, 255, 0, 0);
        setPrintPosition(hbPrint, WINDOW_WIDTH - 20, WINDOW_HEIGHT/2);
        printRight(hbPrint, "%s", GAME_OVER_TEXT);
        SDL_RenderPresent(renderer);
        SDL_Delay(3000);
    }

    cleanup();
    return 0;
}

you compile it with SDL2 and SDL2_ttf libs with this npp nppexec script

npp_save
ENV_SET InputFile = $(CURRENT_DIRECTORY)\$(FILE_NAME)
ENV_SET OutDir = $(CURRENT_DIRECTORY)
ENV_SET OutputFile = $(CURRENT_DIRECTORY)\$(NAME_PART).exe
// ENV_SET InRes = $(CURRENT_DIRECTORY)\Res\NewComCtl.rc
// ENV_SET ResObj = $(CURRENT_DIRECTORY)\Res\manifest.o

cd $(CURRENT_DIRECTORY)
//cmd /c C:\mingw32\bin -i %InRes% -F pe-i386 -o %ResObj%
// cd C:\mingw32\bin
cmd /c del %OutputFile% >nul 2>&1 
// -Wpedantic %ResObj%
cmd /c gcc -Wno-unused-label -Wall -std=c99 -Wno-unknown-pragmas -O1 -Wfatal-errors -s "%InputFile%" -lmingw32 -lSDL2main -lSDL2 -lSDL2_ttf -fexec-charset=UTF-8 -luser32 -lgdi32 -IC:\c_programming\SDL2-2.30.9\i686-w64-mingw32\include -LC:\c_programming\SDL2-2.30.9\i686-w64-mingw32\lib -o "%OutputFile%
if "$(EXITCODE)" == "0" then
  cd OutDir
  cmd /c start /wait cmd " /c %OutputFile% " & pause
endif
#4
General Discussion / Re: Personal Site dedicated to...
Last post by CharlieJV - Nov 15, 2024, 05:38 PM
That is pretty cool.
#5
General Discussion / Personal Site dedicated to DOS...
Last post by ron77 - Nov 15, 2024, 04:19 AM
hello...

well, I finally did it i opened a small website for my Dos games where you can play them online in the browser...

the games are mostly GW-BASIC and FreeBASIC for Dos games and are almost all text games...

link: Retro Dev Ronen
#6
FreeBasic / Hebrew in freeBASIC
Last post by ron77 - Oct 04, 2024, 10:07 AM
1. hebrew in freebasic GFX screen you need to load a .CPI hebrew font like so...

file "LoadFont.bas"

type fbGfxFONT
  as long w,h
  as ubyte ptr pData
  bData(16*256-1) as ubyte
end type  
extern as any ptr __fb_gfx alias "__fb_gfx"
static shared as fbGfxFONT g_MyFont = type(8,16)
static shared as fbGfxFONT ptr g_pOrgFont
static shared as fbGfxFONT ptr ptr g_pptfbGfxFont

sub LoadFontEgaCPI( sFontFile as string )
  
  g_pptfbGfxFont = cptr(fbGfxFONT ptr ptr,__fb_gfx+52+9*sizeof(any ptr)-4)  
  if g_pOrgFont = 0 then g_pOrgFont = *g_pptfbGfxFont
  *g_pptfbGfxFont = @g_MyFont  
  
  var f = freefile()
  if open(sFontFile for binary access read as #f) then exit sub
  get #f,66,g_MyFont.bData(): close #f
  for N as long = 0 to 255*16
    g_MyFont.bData(N) = ((g_MyFont.bData(N) * &h80200802ULL) and &h0884422110ULL) * &h0101010101ULL shr 32
  next N
    
  g_MyFont.pData = @(g_MyFont.bData(0))  
  
end sub
#define EnableFont() *g_pptfbGfxFont = @g_MyFont  
#define RestoreFont() *g_pptfbGfxFont = g_pOrgFont

'~ screenres 640,480

'~ width 640\8,480\16 'must be 8x16
'~ LoadFontEgaCPI("hebega.cpi")

'~ for I as long = 0 to 1
  '~ for N as long = 0 to 255
    '~ locate 1+N\16, I*40+1+(N mod 16)*2
    '~ if (N >=7 and N<=10) or N=13 then print "?";: continue for
    '~ print chr(N);    
  '~ next N  
  '~ RestoreFont()
'~ next I

'~ sleep : end

You cannot view this attachment.

Plus you need to use IBM OEM 862 encoding instead UTF-8

Here is a function that converts UTF-8 to IBM OEM 862 encoding plus a "PrintRight" Function:

function Utf8ToOEM862( sInput as string ) as string
  dim as string sOutput = space(len(sInput))
  dim as long iOut
  for N as long = 0 to len(sInput)-1
    if sInput[N]=&hD7 then
      if sInput[N+1]>=&h90 andalso sInput[N+1]<=&hAA then
        sOutput[iOut] = sInput[N+1]-&h10         
        iOut += 1 : N += 1 :  :continue for
      end if
    end if
    #if __FB_DEBUG__    
      if sInput[N]>&h7F then puts("Warning: utf-8 char not converted!")
    #endif
    sOutput[iOut] = sInput[N] : iOut += 1
  next N
  return left(sOutput,iOut)
end function


sub PrintRight( sText as string )
  var sInvert = sText, iLen = len(sInvert)-1  
  for N as long = 0 to iLen\2
    swap SInvert[N],sInvert[iLen-N]
  next N
  var iLin = csrlin(), iCol = pos()
  if (iCol-(iLen+1)) < 1 then 
    print : iLin = csrlin() : iCol = loword(width())
  end if
  locate iLin,iCol-iLen
  print sInvert;
  locate iLin,iCol-(iLen+1)
end sub

and here is a function that converts UTF-8 to ANSI 1255 (good for GUI window9.bi)

function utf8toansi1255( sInput as string ) as string
  dim as string sOutput = space(len(sInput))
  dim as long iOut
  for N as long = 0 to len(sInput)-1
    if sInput[N]=&hD7 then
      if sInput[N+1]>=&h90 andalso sInput[N+1]<=&hAA then
        sOutput[iOut] = sInput[N+1]+(&hE0-&h90)
        iOut += 1 : N += 1 :  :continue for
      end if
    end if
    #if __FB_DEBUG__    
      if sInput[N]>&h7F then puts("Warning: utf-8 char not converted!")
    #endif
    sOutput[iOut] = sInput[N] : iOut += 1
  next N
  return left(sOutput,iOut)
end function
#7
C / C++ / Re: chatbot Danny in C
Last post by ron77 - Sep 04, 2024, 05:17 PM
Okay, I made some final adjustments to the chatbot. First, let me clear that this chatbot is not politically correct. It is an offensive chatbot that is not suitable for minors under 18 years old, and also, I do not take on any responsibility for your usage of it. So here are the final elements of almost the final diversion of the chatbot in C programming Language.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <stdbool.h>
#include <unistd.h>

#define MAX_STRING_LENGTH 1000
#define MAX_ARRAY_SIZE 1000
#define MAX_KEYWORDS 20
#define MAX_REPLIES 50
#define MAX_MATCHES 10
#define MAX_SWAP_WORDS 100
#define MAX_MEMORY 15

char wordIn[MAX_SWAP_WORDS][MAX_STRING_LENGTH];
char wordOut[MAX_SWAP_WORDS][MAX_STRING_LENGTH];
int wCnt = 0;

char memory[MAX_MEMORY][MAX_STRING_LENGTH];
int memoryCount = 0;

typedef struct {
    char keywords[MAX_KEYWORDS][MAX_STRING_LENGTH];
    char replies[MAX_REPLIES][MAX_STRING_LENGTH];
    int keywordCount;
    int replyCount;
} ArraySet;

ArraySet g_Key_Reply[MAX_ARRAY_SIZE];
int g_Key_ReplyCount = 0;

char default_replies[MAX_ARRAY_SIZE][MAX_STRING_LENGTH];
int default_reply_count = 0;

char* safe_strdup(const char* s) {
    if (!s) return NULL;
    char* result = strdup(s);
    if (!result) {
        fprintf(stderr, "Memory allocation failed in safe_strdup\n");
        exit(1);
    }
    return result;
}

char* isolatePunctuation(const char* s) {
    char* b = malloc(strlen(s) * 3 + 1);
    if (!b) return NULL;
    
    int j = 0;
    for (int i = 0; s[i]; i++) {
        if (strchr("?!,.:;<>(){}[]", s[i])) {
            b[j++] = ' ';
            b[j++] = s[i];
            b[j++] = ' ';
        } else {
            b[j++] = s[i];
        }
    }
    b[j] = '\0';
    return b;
}

void loadArrays(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) {
        printf("Error opening file: %s\n", filename);
        return;
    }

    char line[MAX_STRING_LENGTH];
    int currentSet = -1;
    
    while (fgets(line, sizeof(line), file)) {
        line[strcspn(line, "\n")] = 0;  // Remove newline

        if (strncmp(line, "d1:", 3) == 0) {
            strcpy(default_replies[default_reply_count++], line + 3);
        }
    
        if (line[0] == 'k' && line[1] == ':') {
            if (currentSet == -1 || g_Key_Reply[currentSet].replyCount > 0) {
                currentSet++;
            }
            strcpy(g_Key_Reply[currentSet].keywords[g_Key_Reply[currentSet].keywordCount], line + 2);
            g_Key_Reply[currentSet].keywordCount++;
            g_Key_ReplyCount = currentSet + 1;
        } else if (line[0] == 'r' && line[1] == ':') {
            strcpy(g_Key_Reply[currentSet].replies[g_Key_Reply[currentSet].replyCount], line + 2);
            g_Key_Reply[currentSet].replyCount++;
        }
    }

    fclose(file);
	printf("number of keywords-replies pair groups %d\n", currentSet);
}

void loadSwapWords(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) {
        printf("Error opening swap words file: %s\n", filename);
        return;
    }

    char line[MAX_STRING_LENGTH];
    while (fgets(line, sizeof(line), file) && wCnt < MAX_SWAP_WORDS) {
        line[strcspn(line, "\n")] = 0;  // Remove newline
        if (line[0] == 's' && line[1] == ':') {
            char* delimiter = strchr(line + 2, '>');
            if (delimiter) {
                *delimiter = '\0';
                strcpy(wordIn[wCnt], line + 2);
                strcpy(wordOut[wCnt], delimiter + 1);
                wCnt++;
            }
        }
    }

    fclose(file);
}

char* swapWords(const char* input) {
    if (!input) return NULL;
    char* result = safe_strdup(input);
    char* temp = malloc(strlen(input) * 2 + 1); // Allocate more space for worst-case scenario
    if (!temp) {
        free(result);
        return NULL;
    }

    char* word = strtok(result, " ");
    temp[0] = '\0';

    while (word != NULL) {
        bool swapped = false;
        for (int i = 0; i < wCnt; i++) {
            if (strcmp(word, wordIn[i]) == 0) {
                strcat(temp, wordOut[i]);
                strcat(temp, " ");
                swapped = true;
                break;
            }
        }
        if (!swapped) {
            strcat(temp, word);
            strcat(temp, " ");
        }
        word = strtok(NULL, " ");
    }

    // Remove trailing space
    int len = strlen(temp);
    if (len > 0 && temp[len - 1] == ' ') {
        temp[len - 1] = '\0';
    }

    free(result);
    return temp;
}

char* processReply(const char* reply, const char* userInput) {
    if (!reply || !userInput) return NULL;
    char* processedReply = safe_strdup(reply);
    int len = strlen(processedReply);
    
    if (len > 0 && processedReply[len - 1] == '*') {
        processedReply[len - 1] = '\0';  // Remove the asterisk
        
        // Save the user's input to memory
        if (memoryCount < MAX_MEMORY) {
            strncpy(memory[memoryCount], userInput, MAX_STRING_LENGTH - 1);
            memory[memoryCount][MAX_STRING_LENGTH - 1] = '\0';
            memoryCount++;
        }
        
        // Find the keyword in the user's input
        char* keyword = NULL;
        for (int i = 0; i < g_Key_ReplyCount; i++) {
            for (int j = 0; j < g_Key_Reply[i].keywordCount; j++) {
                if (strstr(userInput, g_Key_Reply[i].keywords[j])) {
                    keyword = g_Key_Reply[i].keywords[j];
                    break;
                }
            }
            if (keyword) break;
        }
        
        if (keyword) {
            char* rest = strstr(userInput, keyword);
            if (rest) {
                rest += strlen(keyword);
                char* swapped = swapWords(rest);
                if (swapped) {
                    // Concatenate the swapped input to the reply
                    char* temp = malloc(strlen(processedReply) + strlen(swapped) + 2);
                    if (temp) {
                        sprintf(temp, "%s %s", processedReply, swapped);
                        free(processedReply);
                        processedReply = temp;
                    }
                    free(swapped);
                }
            }
        }
    }
    
    return processedReply;
}

char* userQuestion(const char* txt) {
    if (!txt) return NULL;
    char* matchedReplies[MAX_MATCHES] = {NULL};
    int matchCount = 0;
    bool found = false;
    char* combinedReply = NULL;

    for (int i = 0; i < g_Key_ReplyCount && matchCount < MAX_MATCHES; i++) {
        for (int j = 0; j < g_Key_Reply[i].keywordCount; j++) {
            if (strstr(txt, g_Key_Reply[i].keywords[j])) {
                int replyIndex = rand() % g_Key_Reply[i].replyCount;
                matchedReplies[matchCount] = safe_strdup(g_Key_Reply[i].replies[replyIndex]);
                matchCount++;
                found = true;
                break;
            }
        }
    }

    if (matchCount > 0) {
        size_t totalLength = 1;  // Start with 1 for the null terminator
        for (int i = 0; i < matchCount; i++) {
            char* processedReply = processReply(matchedReplies[i], txt);
            if (processedReply) {
                totalLength += strlen(processedReply) + 1;  // +1 for newline
                free(matchedReplies[i]);
                matchedReplies[i] = processedReply;
            }
        }

        combinedReply = malloc(totalLength);
        if (combinedReply) {
            combinedReply[0] = '\0';
            for (int i = 0; i < matchCount; i++) {
                if (matchedReplies[i]) {
                    strcat(combinedReply, matchedReplies[i]);
                    strcat(combinedReply, "\n");
                    free(matchedReplies[i]);
                }
            }
        }
    } else if (!found) {
        if (default_reply_count > 0) {
            int defaultIndex = rand() % default_reply_count;
            combinedReply = safe_strdup(default_replies[defaultIndex]);
        }
    }
    
    return combinedReply ? combinedReply : safe_strdup("I don't understand. Can you rephrase that?");
}

char* commands(char* txt) {
    char* isolated = isolatePunctuation(txt);
    for (int i = 0; isolated[i]; i++) {
        isolated[i] = tolower(isolated[i]);
    }
    
    char* response = userQuestion(isolated);
    
    free(isolated);
    return response;
}

void speak(const char* text) {
    char command[MAX_STRING_LENGTH * 2];
    snprintf(command, sizeof(command), "voice -r -1 -n \"Microsoft David Desktop\" \"%s\"", text);
    system(command);
}

int main() {
    srand(time(NULL));
    
    loadArrays("database.txt");
    loadSwapWords("swapwords.txt");
    
	printf("CHATBOT DANNY IN C PROGRAMMING LANGUAGE VERSION 1.1.6.5 (C) RON77\n");
	
    char input[MAX_STRING_LENGTH];
    char* response;
    
    while (1) {
        printf("> ");
        if (fgets(input, sizeof(input), stdin) == NULL) {
            break;
        }
        input[strcspn(input, "\n")] = 0;  // Remove newline
        
        if (strcmp(input, "quit") == 0) break;
        
        response = commands(input);
        
        if (response) {
            // Split the response into separate lines and speak each one
            char* line = strtok(response, "\n");
            while (line != NULL) {
                printf("%s\n", line);
                speak(line);
                line = strtok(NULL, "\n");
            }
            
            free(response);
        } else {
            printf("An error occurred while processing your input.\n");
        }
    }
    
    return 0;
}

You cannot view this attachment.

You cannot view this attachment.

this chatbot used 'voice.exe' TTS cli engine wrapper on windows...

https://elifulkerson.com/projects/commandline-text-to-speech.php
#8
C / C++ / chatbot Danny in C
Last post by ron77 - Sep 04, 2024, 09:40 AM
ok just a basic version of fb_chatbot_danny converted to C...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <stdbool.h>
#include <unistd.h>

#define MAX_STRING_LENGTH 1000
#define MAX_ARRAY_SIZE 1000
#define MAX_KEYWORDS 20
#define MAX_REPLIES 50
#define MAX_MATCHES 5
#define MAX_SWAP_WORDS 100
#define MAX_MEMORY 10

char wordIn[MAX_SWAP_WORDS][MAX_STRING_LENGTH];
char wordOut[MAX_SWAP_WORDS][MAX_STRING_LENGTH];
int wCnt = 0;

char memory[MAX_MEMORY][MAX_STRING_LENGTH];
int memoryCount = 0;

typedef struct {
    char keywords[MAX_KEYWORDS][MAX_STRING_LENGTH];
    char replies[MAX_REPLIES][MAX_STRING_LENGTH];
    int keywordCount;
    int replyCount;
} ArraySet;

ArraySet g_Key_Reply[MAX_ARRAY_SIZE];
int g_Key_ReplyCount = 0;

char default_replies[MAX_ARRAY_SIZE][MAX_STRING_LENGTH];
int default_reply_count = 0;

char* safe_strdup(const char* s) {
    if (!s) return NULL;
    char* result = strdup(s);
    if (!result) {
        fprintf(stderr, "Memory allocation failed in safe_strdup\n");
        exit(1);
    }
    return result;
}

char* isolatePunctuation(const char* s) {
    char* b = malloc(strlen(s) * 3 + 1);
    if (!b) return NULL;
    
    int j = 0;
    for (int i = 0; s[i]; i++) {
        if (strchr("?!,.:;<>(){}[]", s[i])) {
            b[j++] = ' ';
            b[j++] = s[i];
            b[j++] = ' ';
        } else {
            b[j++] = s[i];
        }
    }
    b[j] = '\0';
    return b;
}

void loadArrays(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) {
        printf("Error opening file: %s\n", filename);
        return;
    }

    char line[MAX_STRING_LENGTH];
    int currentSet = -1;
    
    while (fgets(line, sizeof(line), file)) {
        line[strcspn(line, "\n")] = 0;  // Remove newline

        if (strncmp(line, "d1:", 3) == 0) {
            strcpy(default_replies[default_reply_count++], line + 3);
        }
    
        if (line[0] == 'k' && line[1] == ':') {
            if (currentSet == -1 || g_Key_Reply[currentSet].replyCount > 0) {
                currentSet++;
            }
            strcpy(g_Key_Reply[currentSet].keywords[g_Key_Reply[currentSet].keywordCount], line + 2);
            g_Key_Reply[currentSet].keywordCount++;
            g_Key_ReplyCount = currentSet + 1;
        } else if (line[0] == 'r' && line[1] == ':') {
            strcpy(g_Key_Reply[currentSet].replies[g_Key_Reply[currentSet].replyCount], line + 2);
            g_Key_Reply[currentSet].replyCount++;
        }
    }

    fclose(file);
}

void loadSwapWords(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) {
        printf("Error opening swap words file: %s\n", filename);
        return;
    }

    char line[MAX_STRING_LENGTH];
    while (fgets(line, sizeof(line), file) && wCnt < MAX_SWAP_WORDS) {
        line[strcspn(line, "\n")] = 0;  // Remove newline
        if (line[0] == 's' && line[1] == ':') {
            char* delimiter = strchr(line + 2, '>');
            if (delimiter) {
                *delimiter = '\0';
                strcpy(wordIn[wCnt], line + 2);
                strcpy(wordOut[wCnt], delimiter + 1);
                wCnt++;
            }
        }
    }

    fclose(file);
}

char* swapWords(const char* input) {
    if (!input) return NULL;
    char* result = safe_strdup(input);
    char* temp = malloc(strlen(input) * 2 + 1); // Allocate more space for worst-case scenario
    if (!temp) {
        free(result);
        return NULL;
    }

    char* word = strtok(result, " ");
    temp[0] = '\0';

    while (word != NULL) {
        bool swapped = false;
        for (int i = 0; i < wCnt; i++) {
            if (strcmp(word, wordIn[i]) == 0) {
                strcat(temp, wordOut[i]);
                strcat(temp, " ");
                swapped = true;
                break;
            }
        }
        if (!swapped) {
            strcat(temp, word);
            strcat(temp, " ");
        }
        word = strtok(NULL, " ");
    }

    // Remove trailing space
    int len = strlen(temp);
    if (len > 0 && temp[len - 1] == ' ') {
        temp[len - 1] = '\0';
    }

    free(result);
    return temp;
}

char* processReply(const char* reply, const char* userInput) {
    if (!reply || !userInput) return NULL;
    char* processedReply = safe_strdup(reply);
    int len = strlen(processedReply);
    
    if (len > 0 && processedReply[len - 1] == '*') {
        processedReply[len - 1] = '\0';  // Remove the asterisk
        
        // Save the user's input to memory
        if (memoryCount < MAX_MEMORY) {
            strncpy(memory[memoryCount], userInput, MAX_STRING_LENGTH - 1);
            memory[memoryCount][MAX_STRING_LENGTH - 1] = '\0';
            memoryCount++;
        }
        
        // Find the keyword in the user's input
        char* keyword = NULL;
        for (int i = 0; i < g_Key_ReplyCount; i++) {
            for (int j = 0; j < g_Key_Reply[i].keywordCount; j++) {
                if (strstr(userInput, g_Key_Reply[i].keywords[j])) {
                    keyword = g_Key_Reply[i].keywords[j];
                    break;
                }
            }
            if (keyword) break;
        }
        
        if (keyword) {
            char* rest = strstr(userInput, keyword);
            if (rest) {
                rest += strlen(keyword);
                char* swapped = swapWords(rest);
                if (swapped) {
                    // Concatenate the swapped input to the reply
                    char* temp = malloc(strlen(processedReply) + strlen(swapped) + 2);
                    if (temp) {
                        sprintf(temp, "%s %s", processedReply, swapped);
                        free(processedReply);
                        processedReply = temp;
                    }
                    free(swapped);
                }
            }
        }
    }
    
    return processedReply;
}

char* userQuestion(const char* txt) {
    if (!txt) return NULL;
    char* matchedReplies[MAX_MATCHES] = {NULL};
    int matchCount = 0;
    bool found = false;
    char* combinedReply = NULL;

    for (int i = 0; i < g_Key_ReplyCount && matchCount < MAX_MATCHES; i++) {
        for (int j = 0; j < g_Key_Reply[i].keywordCount; j++) {
            if (strstr(txt, g_Key_Reply[i].keywords[j])) {
                int replyIndex = rand() % g_Key_Reply[i].replyCount;
                matchedReplies[matchCount] = safe_strdup(g_Key_Reply[i].replies[replyIndex]);
                matchCount++;
                found = true;
                break;
            }
        }
    }

    if (matchCount > 0) {
        size_t totalLength = 1;  // Start with 1 for the null terminator
        for (int i = 0; i < matchCount; i++) {
            char* processedReply = processReply(matchedReplies[i], txt);
            if (processedReply) {
                totalLength += strlen(processedReply) + 1;  // +1 for newline
                free(matchedReplies[i]);
                matchedReplies[i] = processedReply;
            }
        }

        combinedReply = malloc(totalLength);
        if (combinedReply) {
            combinedReply[0] = '\0';
            for (int i = 0; i < matchCount; i++) {
                if (matchedReplies[i]) {
                    strcat(combinedReply, matchedReplies[i]);
                    strcat(combinedReply, "\n");
                    free(matchedReplies[i]);
                }
            }
        }
    } else if (!found) {
        if (default_reply_count > 0) {
            int defaultIndex = rand() % default_reply_count;
            combinedReply = safe_strdup(default_replies[defaultIndex]);
        }
    }
    
    return combinedReply ? combinedReply : safe_strdup("I don't understand. Can you rephrase that?");
}

char* commands(char* txt) {
    char* isolated = isolatePunctuation(txt);
    for (int i = 0; isolated[i]; i++) {
        isolated[i] = tolower(isolated[i]);
    }
    
    char* response = userQuestion(isolated);
    
    free(isolated);
    return response;
}

void speak(const char* text) {
    char command[MAX_STRING_LENGTH * 2];
    snprintf(command, sizeof(command), "voice -r -1 -n \"Microsoft David Desktop\" \"%s\"", text);
    system(command);
}

int main() {
    srand(time(NULL));
    
    loadArrays("database.txt");
    loadSwapWords("swapwords.txt");
    
    char input[MAX_STRING_LENGTH];
    char* response;
    
    while (1) {
        printf("> ");
        if (fgets(input, sizeof(input), stdin) == NULL) {
            break;
        }
        input[strcspn(input, "\n")] = 0;  // Remove newline
        
        if (strcmp(input, "quit") == 0) break;
        
        response = commands(input);
        
        if (response) {
            // Split the response into separate lines and speak each one
            char* line = strtok(response, "\n");
            while (line != NULL) {
                printf("%s\n", line);
                speak(line);
                line = strtok(NULL, "\n");
            }
            
            free(response);
        } else {
            printf("An error occurred while processing your input.\n");
        }
    }
    
    return 0;
}

databases files:

You cannot view this attachment.

You cannot view this attachment.

this chatbot uses voice.exe TTS cli engine 
#10
C / C++ / Re: windows 32 bit OpenAI API ...
Last post by ron77 - Sep 02, 2024, 09:00 AM
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;
}