This commit is contained in:
Santiago Lema 2025-05-10 04:48:28 -03:00
parent 5360c4f8d0
commit 9c040edca1
5 changed files with 187 additions and 158 deletions

View file

@ -41,7 +41,6 @@ std::string Conversation::buildHistoryInfoLine() {
std::string info = "" + std::to_string(_messageHistory.size()) + " messages"; std::string info = "" + std::to_string(_messageHistory.size()) + " messages";
return info; return info;
} }
void Conversation::ClearHistory() { void Conversation::ClearHistory() {
@ -71,7 +70,8 @@ Conversation::FilterTextModels(const json &modelsJson) {
} }
} }
std::sort(result.begin(), result.end(), std::greater<>()); // inverse alphabetical to get gpt-4 on top std::sort(result.begin(), result.end(),
std::greater<>()); // inverse alphabetical to get gpt-4 on top
return result; return result;
} }
@ -111,17 +111,29 @@ void Conversation::MessageReceived(BMessage *message) {
} break; } break;
case UrlEvent::RequestCompleted: { case UrlEvent::RequestCompleted: {
printf("RequestCompleted\n");
auto identifier = message->GetInt32(UrlEventData::Id, -1);
if (_lastResult->Identity() == identifier) {
// The following call will not block, because we have been notified // The following call will not block, because we have been notified
// that the request is done. // that the request is done.
try {
printf("RequestCompleted\n");
if (!_lastResult) {
printf("No Last Result (no connection?)..\n");
return;
}
auto identifier = message->GetInt32(UrlEventData::Id, -1);
if (_lastResult->Identity() == identifier) {
if (!_lastResult->HasBody()) {
printf("NO Body (no connection)..\n");
return;
}
BHttpBody body = _lastResult->Body(); BHttpBody body = _lastResult->Body();
if (body.text.has_value()) { if (body.text.has_value()) {
try {
// printf("full Reply as text:%s",body.text.value().String()); // printf("full Reply as text:%s",body.text.value().String());
auto fullBody = body.text.value().String(); auto fullBody = body.text.value().String();
json parsed = json::parse(fullBody); json parsed = json::parse(fullBody);
@ -150,12 +162,8 @@ void Conversation::MessageReceived(BMessage *message) {
else if (objType == "chat.completion") { else if (objType == "chat.completion") {
std::string content = parsed["choices"][0]["message"]["content"]; std::string content = parsed["choices"][0]["message"]["content"];
_messageHistory.push_back(
_messageHistory.push_back({ {{"role", "assistant"}, {"content", content}});
{"role", "assistant"},
{"content", content}
});
// printf("we got content:%s",content.c_str()); // printf("we got content:%s",content.c_str());
BMessage message(kSendReply); BMessage message(kSendReply);
@ -164,23 +172,21 @@ void Conversation::MessageReceived(BMessage *message) {
sendReply(message); sendReply(message);
} }
} catch (const std::exception &e) {
fprintf(stderr, "Error parsing JSON: %s\n", e.what());
std::string content = "Error parsing JSON, wrong model ?";
BMessage message(kSendReply);
message.AddString("text", BString(content.c_str()));
sendReply(message);
}
} else { } else {
BMessage message(kSendReply); BMessage message(kSendReply);
message.AddString("text", "EMPTY BODY"); message.AddString("text", "EMPTY BODY");
sendReply(message); sendReply(message);
} }
} }
} catch (const std::exception &e) {
fprintf(stderr, "Error parsing JSON: %s\n", e.what());
std::string content = "Error parsing JSON, wrong model ?";
BMessage message(kSendReply);
message.AddString("text", BString(content.c_str()));
sendReply(message);
} }
break; } break;
case UrlEvent::HttpStatus: { case UrlEvent::HttpStatus: {
@ -192,24 +198,24 @@ void Conversation::MessageReceived(BMessage *message) {
case UrlEvent::BytesWritten: { case UrlEvent::BytesWritten: {
// _infoView->SetText("Some bytes written.."); // _infoView->SetText("Some bytes written..");
auto identifier = message->GetInt32(UrlEventData::Id, -1); // auto identifier = message->GetInt32(UrlEventData::Id, -1);
if (_lastResult->Identity() == identifier) { // if (_lastResult->Identity() == identifier) {
off_t numBytes = message->GetInt64(UrlEventData::NumBytes, 0); // off_t numBytes = message->GetInt64(UrlEventData::NumBytes, 0);
off_t totalBytes = message->GetInt64(UrlEventData::TotalBytes, 0); // off_t totalBytes = message->GetInt64(UrlEventData::TotalBytes, 0);
// _progress->SetTo(numBytes); // _progress->SetTo(numBytes);
//_progress->SetMaxValue(totalBytes); //_progress->SetMaxValue(totalBytes);
} //}
} break; } break;
case UrlEvent::DownloadProgress: { case UrlEvent::DownloadProgress: {
auto identifier = message->GetInt32(UrlEventData::Id, -1); // auto identifier = message->GetInt32(UrlEventData::Id, -1);
if (_lastResult->Identity() == identifier) { // if (_lastResult->Identity() == identifier) {
off_t nn = message->GetInt64(UrlEventData::NumBytes, 0); // off_t nn = message->GetInt64(UrlEventData::NumBytes, 0);
off_t totalBytes = message->GetInt64(UrlEventData::TotalBytes, 0); // off_t totalBytes = message->GetInt64(UrlEventData::TotalBytes, 0);
//_progress->SetTo(nn); //_progress->SetTo(nn);
//_progress->SetMaxValue(totalBytes); //_progress->SetMaxValue(totalBytes);
//_infoView->SetText("Download Progress.."); //_infoView->SetText("Download Progress..");
} //}
} break; } break;
default: default:
@ -259,10 +265,7 @@ void Conversation::setModel(const std::string &model) {
void Conversation::ask(const std::string &prompt) { void Conversation::ask(const std::string &prompt) {
_messageHistory.push_back({ _messageHistory.push_back({{"role", "user"}, {"content", prompt}});
{"role", "user"},
{"content", prompt}
});
// printf("Asking prompt: %s",prompt.c_str()); // printf("Asking prompt: %s",prompt.c_str());
@ -272,7 +275,8 @@ void Conversation::ask(const std::string &prompt) {
auto url = BUrl("https://api.openai.com/v1/chat/completions"); auto url = BUrl("https://api.openai.com/v1/chat/completions");
BHttpRequest request = BHttpRequest(url); BHttpRequest request = BHttpRequest(url);
request.SetMethod(BHttpMethod::Post); request.SetMethod(BHttpMethod::Post);
//Allow up to 2 minute before timeout, it can be long depending on load or complexity of prompt // Allow up to 2 minute before timeout, it can be long depending on load or
// complexity of prompt
request.SetTimeout(120 * 1000000); request.SetTimeout(120 * 1000000);
BHttpFields fields = BHttpFields(); BHttpFields fields = BHttpFields();
@ -281,14 +285,12 @@ void Conversation::ask(const std::string &prompt) {
// crash, we set it in request // crash, we set it in request
request.SetFields(fields); request.SetFields(fields);
// WE PASS THE WHOLE HISTORY to keep context, as recommended for this stateless API! // WE PASS THE WHOLE HISTORY to keep context, as recommended for this
// stateless API!
// json bodyJson = {{"model", _activeModel}, // json bodyJson = {{"model", _activeModel},
// {"messages", {{{"role", "user"}, {"content", prompt}}}}}; // {"messages", {{{"role", "user"}, {"content", prompt}}}}};
json bodyJson = { json bodyJson = {{"model", _activeModel}, {"messages", _messageHistory}};
{"model", _activeModel},
{"messages", _messageHistory}
};
std::string body = bodyJson.dump(); std::string body = bodyJson.dump();

BIN
DumBer

Binary file not shown.

View file

@ -5,7 +5,6 @@
#include "MainWindow.h" #include "MainWindow.h"
static int progressAnim = 0; static int progressAnim = 0;
static int progressColor = 0; static int progressColor = 0;
static bool progressColorUp = false; static bool progressColorUp = false;
@ -14,6 +13,7 @@ static bool progressColorUp = false;
#include <Bitmap.h> #include <Bitmap.h>
#include <Button.h> #include <Button.h>
#include <Catalog.h> #include <Catalog.h>
#include <IconUtils.h>
#include <LayoutBuilder.h> #include <LayoutBuilder.h>
#include <Menu.h> #include <Menu.h>
#include <MenuBar.h> #include <MenuBar.h>
@ -36,7 +36,7 @@ static bool progressColorUp = false;
#define B_TRANSLATION_CONTEXT "Window" #define B_TRANSLATION_CONTEXT "Window"
MainWindow::MainWindow() MainWindow::MainWindow()
: BWindow(BRect(50, 50, 600, 400), B_TRANSLATE("DumBer"), B_TITLED_WINDOW, : BWindow(BRect(50, 50, 600, 400), B_TRANSLATE("DumBer"), B_DOCUMENT_WINDOW,
B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE) { B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE) {
// Without this conversation would never get bmessages from HttpRequest // Without this conversation would never get bmessages from HttpRequest
@ -63,7 +63,6 @@ MainWindow::MainWindow()
_progress->SetTo(0); _progress->SetTo(0);
_progress->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); _progress->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
// Info view, only one line high // Info view, only one line high
_infoView = new BTextView("info"); _infoView = new BTextView("info");
_infoView->SetText("..."); _infoView->SetText("...");
@ -95,7 +94,6 @@ MainWindow::MainWindow()
_sendButton->MakeDefault(true); _sendButton->MakeDefault(true);
_answerView = new BTextView("answer", B_WILL_DRAW); _answerView = new BTextView("answer", B_WILL_DRAW);
_answerView->MakeEditable(false); // Disable editing _answerView->MakeEditable(false); // Disable editing
_answerView->MakeSelectable(true); // Enable text selection _answerView->MakeSelectable(true); // Enable text selection
@ -103,32 +101,56 @@ MainWindow::MainWindow()
_answerView->SetExplicitMinSize(BSize(B_SIZE_UNSET, askH * 2)); _answerView->SetExplicitMinSize(BSize(B_SIZE_UNSET, askH * 2));
_answerScrollView = _answerScrollView = new BScrollView(
new BScrollView("scroll_view", _answerView, B_FRAME_EVENTS | B_WILL_DRAW, 0, "scroll_view", _answerView, B_FRAME_EVENTS | B_WILL_DRAW, 0, false, true,
false, true, B_FANCY_BORDER); // horizontal and vertical scrollbars B_FANCY_BORDER); // horizontal and vertical scrollbars
// Enable correct resizing behavior, otherwise we get no correct scrollbar after resizing // Enable correct resizing behavior, otherwise we get no correct scrollbar
// after resizing
_answerView->SetFlags(_answerView->Flags() | B_FULL_UPDATE_ON_RESIZE); _answerView->SetFlags(_answerView->Flags() | B_FULL_UPDATE_ON_RESIZE);
_answerScrollView->SetFlags(_answerView->Flags() | B_FULL_UPDATE_ON_RESIZE); _answerScrollView->SetFlags(_answerView->Flags() | B_FULL_UPDATE_ON_RESIZE);
/* /*
BView *imageView = new BView("icon_view", B_WILL_DRAW | B_FOLLOW_NONE); //TRYING TO load image from resources and failing...
BView *imageView = new BView("icon_view", B_WILL_DRAW | B_FOLLOW_ALL);
imageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); imageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
BBitmap* oneImage = BTranslationUtils::GetBitmap('RAWT', 77, NULL); // Open the resource file
imageView->SetViewColor(ui_color(B_CONTROL_BORDER_COLOR)); BFile resourceFile("Resources.rdef", B_READ_ONLY);
if (resourceFile.InitCheck() != B_OK) {
fprintf(stderr, "Failed to open the resource file.\n");
return;
}
if (oneImage) { BResources resources(&resourceFile);
imageView->SetViewBitmap(oneImage,B_FOLLOW_LEFT_TOP, B_TILE_BITMAP);
printf("Image loaded!\n"); // Load the icon resource
size_t theSize;
const uint8 *iconData =
(const uint8 *)resources.LoadResource('VICN', 55, &theSize);
if (iconData == nullptr) {
fprintf(stderr, "Failed to load the icon resource.\n");
} else {
printf("loaded size:%zu", theSize);
} }
else {
printf("Image NOT loaded!\n"); // Create a BBitmap
BBitmap *bitmap =
new BBitmap(BRect(0, 0, 96, 96), B_RGBA32); // Adjust size as needed
if (bitmap == nullptr) {
fprintf(stderr, "Failed to create a BBitmap.\n");
} }
// Convert the icon data to the Bitmap
if (!BIconUtils::GetVectorIcon(iconData, theSize, bitmap)) {
fprintf(stderr, "Failed to convert the icon to a BBitmap.\n");
// delete bitmap; // Clean up in case of failure
}
// Now you can use the bitmap as needed...
// delete bitmap; // Clean up when done
*/ */
BStringView *headerQuestion = BStringView *headerQuestion =
new BStringView("questionLabel", "Your question: "); new BStringView("questionLabel", "Your question: ");
BStringView *headerAnswer = new BStringView("questionAnswer", "Answer: "); BStringView *headerAnswer = new BStringView("questionAnswer", "Answer: ");
@ -181,12 +203,19 @@ BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
.End(); .End();
//imageView->SetViewColor(ui_color(B_CONTROL_BORDER_COLOR));
//if (bitmap) {
// imageView->SetViewBitmap(bitmap, 0, 0);
// printf("Image loaded!\n");
//} else {
// printf("Image NOT loaded!\n");
//}
// Loop Just to animate progress in Bar // Loop Just to animate progress in Bar
BMessageRunner *runner = new BMessageRunner(this, // target BHandler BMessageRunner *runner = new BMessageRunner(this, // target BHandler
new BMessage(kPulse), new BMessage(kPulse),
100000 // interval in μs (0ms) 100000 // interval in μs (0ms)
); );
updateHistoryInfo(); updateHistoryInfo();
@ -396,14 +425,11 @@ void MainWindow::MessageReceived(BMessage *message) {
const char *text; const char *text;
const char *fullJSON; const char *fullJSON;
if (message->FindString("json", &fullJSON) == B_OK) { if (message->FindString("json", &fullJSON) == B_OK) {
lastJSON = std::string(fullJSON); lastJSON = std::string(fullJSON);
} }
if (message->FindString("text", &text) == B_OK) { if (message->FindString("text", &text) == B_OK) {
// printf("Received text: %s\n", text); // printf("Received text: %s\n", text);
// Do something with text (e.g., set it to a BTextView) // Do something with text (e.g., set it to a BTextView)
@ -492,7 +518,5 @@ BMenuBar *MainWindow::_BuildMenu() {
item->SetShortcut('J', B_COMMAND_KEY | B_SHIFT_KEY); item->SetShortcut('J', B_COMMAND_KEY | B_SHIFT_KEY);
menu->AddItem(item); menu->AddItem(item);
return menuBar; return menuBar;
} }

View file

@ -18,6 +18,10 @@ resource app_version {
}; };
resource(55) #'VICN' import "artwork/icons/kConsoleApp";
resource vector_icon { resource vector_icon {
$"6E6369660804016B0500020006023CADEB3D1051BD10513CADEB4C3551C6C7FF" $"6E6369660804016B0500020006023CADEB3D1051BD10513CADEB4C3551C6C7FF"
$"00FFDB97FFFCAF29020006023A647ABA3F0A3A3F0A3A647AC92D47CA165100FF" $"00FFDB97FFFCAF29020006023A647ABA3F0A3A3F0A3A647AC92D47CA165100FF"
@ -48,4 +52,3 @@ resource vector_icon {

BIN
artwork/icons/kConsoleApp Normal file

Binary file not shown.