duh
This commit is contained in:
parent
5360c4f8d0
commit
9c040edca1
5 changed files with 187 additions and 158 deletions
126
Conversation.cpp
126
Conversation.cpp
|
@ -38,16 +38,15 @@ void Conversation::sendReply(BMessage message) {
|
|||
|
||||
std::string Conversation::buildHistoryInfoLine() {
|
||||
|
||||
std::string info = "" + std::to_string(_messageHistory.size()) + " messages";
|
||||
|
||||
return info;
|
||||
std::string info = "" + std::to_string(_messageHistory.size()) + " messages";
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void Conversation::ClearHistory() {
|
||||
|
||||
printf("Cleared history\n");
|
||||
_messageHistory.clear();
|
||||
printf("Cleared history\n");
|
||||
_messageHistory.clear();
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -111,24 +111,36 @@ void Conversation::MessageReceived(BMessage *message) {
|
|||
} break;
|
||||
|
||||
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
|
||||
// that the request is done.
|
||||
BHttpBody body = _lastResult->Body();
|
||||
if (body.text.has_value()) {
|
||||
|
||||
// The following call will not block, because we have been notified
|
||||
// that the request is done.
|
||||
try {
|
||||
|
||||
try {
|
||||
printf("RequestCompleted\n");
|
||||
|
||||
//printf("full Reply as text:%s",body.text.value().String());
|
||||
auto fullBody =body.text.value().String();
|
||||
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();
|
||||
if (body.text.has_value()) {
|
||||
|
||||
// printf("full Reply as text:%s",body.text.value().String());
|
||||
auto fullBody = body.text.value().String();
|
||||
json parsed = json::parse(fullBody);
|
||||
printf("Parsed..\n");
|
||||
|
||||
std::string objType = parsed["object"];
|
||||
// printf("Reply of type object :%s\n", objType.c_str());
|
||||
// printf("Reply of type object :%s\n", objType.c_str());
|
||||
|
||||
if (objType == "list") {
|
||||
// printf("full Reply as text:%s",body.text.value().String());
|
||||
|
@ -143,19 +155,15 @@ void Conversation::MessageReceived(BMessage *message) {
|
|||
sendReply(msg);
|
||||
|
||||
// std::string content =
|
||||
//parsed["choices"][0]["message"]["content"];
|
||||
// parsed["choices"][0]["message"]["content"];
|
||||
|
||||
}
|
||||
|
||||
else if (objType == "chat.completion") {
|
||||
std::string content = parsed["choices"][0]["message"]["content"];
|
||||
|
||||
|
||||
_messageHistory.push_back({
|
||||
{"role", "assistant"},
|
||||
{"content", content}
|
||||
});
|
||||
|
||||
_messageHistory.push_back(
|
||||
{{"role", "assistant"}, {"content", content}});
|
||||
|
||||
// printf("we got content:%s",content.c_str());
|
||||
BMessage message(kSendReply);
|
||||
|
@ -164,23 +172,21 @@ void Conversation::MessageReceived(BMessage *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 ?";
|
||||
} else {
|
||||
BMessage message(kSendReply);
|
||||
message.AddString("text", BString(content.c_str()));
|
||||
message.AddString("text", "EMPTY BODY");
|
||||
sendReply(message);
|
||||
}
|
||||
|
||||
} else {
|
||||
BMessage message(kSendReply);
|
||||
message.AddString("text", "EMPTY BODY");
|
||||
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: {
|
||||
|
||||
|
@ -192,24 +198,24 @@ void Conversation::MessageReceived(BMessage *message) {
|
|||
|
||||
case UrlEvent::BytesWritten: {
|
||||
// _infoView->SetText("Some bytes written..");
|
||||
auto identifier = message->GetInt32(UrlEventData::Id, -1);
|
||||
if (_lastResult->Identity() == identifier) {
|
||||
off_t numBytes = message->GetInt64(UrlEventData::NumBytes, 0);
|
||||
off_t totalBytes = message->GetInt64(UrlEventData::TotalBytes, 0);
|
||||
// _progress->SetTo(numBytes);
|
||||
//_progress->SetMaxValue(totalBytes);
|
||||
}
|
||||
// auto identifier = message->GetInt32(UrlEventData::Id, -1);
|
||||
// if (_lastResult->Identity() == identifier) {
|
||||
// off_t numBytes = message->GetInt64(UrlEventData::NumBytes, 0);
|
||||
// off_t totalBytes = message->GetInt64(UrlEventData::TotalBytes, 0);
|
||||
// _progress->SetTo(numBytes);
|
||||
//_progress->SetMaxValue(totalBytes);
|
||||
//}
|
||||
} break;
|
||||
|
||||
case UrlEvent::DownloadProgress: {
|
||||
auto identifier = message->GetInt32(UrlEventData::Id, -1);
|
||||
if (_lastResult->Identity() == identifier) {
|
||||
off_t nn = message->GetInt64(UrlEventData::NumBytes, 0);
|
||||
off_t totalBytes = message->GetInt64(UrlEventData::TotalBytes, 0);
|
||||
//_progress->SetTo(nn);
|
||||
//_progress->SetMaxValue(totalBytes);
|
||||
//_infoView->SetText("Download Progress..");
|
||||
}
|
||||
// auto identifier = message->GetInt32(UrlEventData::Id, -1);
|
||||
// if (_lastResult->Identity() == identifier) {
|
||||
// off_t nn = message->GetInt64(UrlEventData::NumBytes, 0);
|
||||
// off_t totalBytes = message->GetInt64(UrlEventData::TotalBytes, 0);
|
||||
//_progress->SetTo(nn);
|
||||
//_progress->SetMaxValue(totalBytes);
|
||||
//_infoView->SetText("Download Progress..");
|
||||
//}
|
||||
} break;
|
||||
|
||||
default:
|
||||
|
@ -259,10 +265,7 @@ void Conversation::setModel(const std::string &model) {
|
|||
|
||||
void Conversation::ask(const std::string &prompt) {
|
||||
|
||||
_messageHistory.push_back({
|
||||
{"role", "user"},
|
||||
{"content", prompt}
|
||||
});
|
||||
_messageHistory.push_back({{"role", "user"}, {"content", prompt}});
|
||||
|
||||
// printf("Asking prompt: %s",prompt.c_str());
|
||||
|
||||
|
@ -272,8 +275,9 @@ void Conversation::ask(const std::string &prompt) {
|
|||
auto url = BUrl("https://api.openai.com/v1/chat/completions");
|
||||
BHttpRequest request = BHttpRequest(url);
|
||||
request.SetMethod(BHttpMethod::Post);
|
||||
//Allow up to 2 minute before timeout, it can be long depending on load or complexity of prompt
|
||||
request.SetTimeout(120*1000000);
|
||||
// Allow up to 2 minute before timeout, it can be long depending on load or
|
||||
// complexity of prompt
|
||||
request.SetTimeout(120 * 1000000);
|
||||
|
||||
BHttpFields fields = BHttpFields();
|
||||
fields.AddField("Authorization", buildBearerKey());
|
||||
|
@ -281,14 +285,12 @@ void Conversation::ask(const std::string &prompt) {
|
|||
// crash, we set it in request
|
||||
request.SetFields(fields);
|
||||
|
||||
// WE PASS THE WHOLE HISTORY to keep context, as recommended for this stateless API!
|
||||
// json bodyJson = {{"model", _activeModel},
|
||||
// WE PASS THE WHOLE HISTORY to keep context, as recommended for this
|
||||
// stateless API!
|
||||
// json bodyJson = {{"model", _activeModel},
|
||||
// {"messages", {{{"role", "user"}, {"content", prompt}}}}};
|
||||
|
||||
json bodyJson = {
|
||||
{"model", _activeModel},
|
||||
{"messages", _messageHistory}
|
||||
};
|
||||
json bodyJson = {{"model", _activeModel}, {"messages", _messageHistory}};
|
||||
|
||||
std::string body = bodyJson.dump();
|
||||
|
||||
|
|
BIN
DumBer
BIN
DumBer
Binary file not shown.
178
MainWindow.cpp
178
MainWindow.cpp
|
@ -5,7 +5,6 @@
|
|||
|
||||
#include "MainWindow.h"
|
||||
|
||||
|
||||
static int progressAnim = 0;
|
||||
static int progressColor = 0;
|
||||
static bool progressColorUp = false;
|
||||
|
@ -14,6 +13,7 @@ static bool progressColorUp = false;
|
|||
#include <Bitmap.h>
|
||||
#include <Button.h>
|
||||
#include <Catalog.h>
|
||||
#include <IconUtils.h>
|
||||
#include <LayoutBuilder.h>
|
||||
#include <Menu.h>
|
||||
#include <MenuBar.h>
|
||||
|
@ -36,7 +36,7 @@ static bool progressColorUp = false;
|
|||
#define B_TRANSLATION_CONTEXT "Window"
|
||||
|
||||
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) {
|
||||
|
||||
// Without this conversation would never get bmessages from HttpRequest
|
||||
|
@ -63,7 +63,6 @@ MainWindow::MainWindow()
|
|||
_progress->SetTo(0);
|
||||
_progress->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
|
||||
// Info view, only one line high
|
||||
_infoView = new BTextView("info");
|
||||
_infoView->SetText("...");
|
||||
|
@ -95,7 +94,6 @@ MainWindow::MainWindow()
|
|||
|
||||
_sendButton->MakeDefault(true);
|
||||
|
||||
|
||||
_answerView = new BTextView("answer", B_WILL_DRAW);
|
||||
_answerView->MakeEditable(false); // Disable editing
|
||||
_answerView->MakeSelectable(true); // Enable text selection
|
||||
|
@ -103,95 +101,126 @@ MainWindow::MainWindow()
|
|||
|
||||
_answerView->SetExplicitMinSize(BSize(B_SIZE_UNSET, askH * 2));
|
||||
|
||||
_answerScrollView =
|
||||
new BScrollView("scroll_view", _answerView, B_FRAME_EVENTS | B_WILL_DRAW, 0,
|
||||
false, true, B_FANCY_BORDER); // horizontal and vertical scrollbars
|
||||
_answerScrollView = new BScrollView(
|
||||
"scroll_view", _answerView, B_FRAME_EVENTS | B_WILL_DRAW, 0, false, true,
|
||||
B_FANCY_BORDER); // horizontal and vertical scrollbars
|
||||
|
||||
// Enable correct resizing behavior, otherwise we get no correct scrollbar after resizing
|
||||
_answerView->SetFlags(_answerView->Flags() | B_FULL_UPDATE_ON_RESIZE);
|
||||
_answerScrollView->SetFlags(_answerView->Flags() | B_FULL_UPDATE_ON_RESIZE);
|
||||
// Enable correct resizing behavior, otherwise we get no correct scrollbar
|
||||
// after resizing
|
||||
_answerView->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);
|
||||
imageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
//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));
|
||||
|
||||
BBitmap* oneImage = BTranslationUtils::GetBitmap('RAWT', 77, NULL);
|
||||
imageView->SetViewColor(ui_color(B_CONTROL_BORDER_COLOR));
|
||||
// Open the resource file
|
||||
BFile resourceFile("Resources.rdef", B_READ_ONLY);
|
||||
if (resourceFile.InitCheck() != B_OK) {
|
||||
fprintf(stderr, "Failed to open the resource file.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (oneImage) {
|
||||
imageView->SetViewBitmap(oneImage,B_FOLLOW_LEFT_TOP, B_TILE_BITMAP);
|
||||
printf("Image loaded!\n");
|
||||
}
|
||||
else {
|
||||
printf("Image NOT loaded!\n");
|
||||
}
|
||||
*/
|
||||
BResources resources(&resourceFile);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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 =
|
||||
new BStringView("questionLabel", "Your question: ");
|
||||
BStringView *headerAnswer = new BStringView("questionAnswer", "Answer: ");
|
||||
|
||||
rgb_color colorQuestion = {100, 100,150, 255};
|
||||
//rgb_color colorAnswer = {100, 100,150, 255};
|
||||
rgb_color colorQuestion = {100, 100, 150, 255};
|
||||
// rgb_color colorAnswer = {100, 100,150, 255};
|
||||
|
||||
//high color = txt
|
||||
headerQuestion->SetHighColor(colorQuestion);
|
||||
headerAnswer->SetHighColor(colorQuestion);
|
||||
// high color = txt
|
||||
headerQuestion->SetHighColor(colorQuestion);
|
||||
headerAnswer->SetHighColor(colorQuestion);
|
||||
|
||||
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
|
||||
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
|
||||
|
||||
.AddGlue(0.1)
|
||||
.Add(headerQuestion)
|
||||
.AddGroup(B_HORIZONTAL, 0, 1)
|
||||
.AddGlue(0.1)
|
||||
.Add(headerQuestion)
|
||||
.AddGroup(B_HORIZONTAL, 0, 1)
|
||||
|
||||
.Add(_inputField)
|
||||
.AddGlue(0.01)
|
||||
// .Add(imageView)
|
||||
.Add(_inputField)
|
||||
.AddGlue(0.01)
|
||||
// .Add(imageView)
|
||||
|
||||
.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 0)
|
||||
.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 0)
|
||||
|
||||
.AddGroup(B_HORIZONTAL, 0)
|
||||
.Add(_infoConversation)
|
||||
.AddGlue(0.1)
|
||||
.End()
|
||||
.AddGroup(B_HORIZONTAL, 0)
|
||||
.Add(_modelField)
|
||||
.AddGlue(0.1)
|
||||
.End()
|
||||
.AddGroup(B_HORIZONTAL, 0)
|
||||
.Add(_sendButton)
|
||||
.AddGlue(0.1)
|
||||
.End()
|
||||
.AddGroup(B_HORIZONTAL, 0)
|
||||
.Add(_infoConversation)
|
||||
.AddGlue(0.1)
|
||||
.End()
|
||||
.AddGroup(B_HORIZONTAL, 0)
|
||||
.Add(_modelField)
|
||||
.AddGlue(0.1)
|
||||
.End()
|
||||
.AddGroup(B_HORIZONTAL, 0)
|
||||
.Add(_sendButton)
|
||||
.AddGlue(0.1)
|
||||
.End()
|
||||
|
||||
.End()
|
||||
.End()
|
||||
|
||||
.End()
|
||||
.End()
|
||||
|
||||
.AddGlue(0.1)
|
||||
.Add(headerAnswer)
|
||||
.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 1.0)
|
||||
.AddGlue(0.1)
|
||||
.Add(headerAnswer)
|
||||
.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 1.0)
|
||||
|
||||
.Add(_answerScrollView, 1)
|
||||
.Add(_progress, 0.1)
|
||||
.Add(_infoView, 0.1)
|
||||
.End()
|
||||
.SetInsets(6, 6, 6, 6)
|
||||
.Add(_answerScrollView, 1)
|
||||
.Add(_progress, 0.1)
|
||||
.Add(_infoView, 0.1)
|
||||
.End()
|
||||
.SetInsets(6, 6, 6, 6)
|
||||
|
||||
.End();
|
||||
.End();
|
||||
|
||||
// Loop Just to animate progress in Bar
|
||||
BMessageRunner *runner = new BMessageRunner(this, // target BHandler
|
||||
new BMessage(kPulse),
|
||||
100000 // interval in μs (0 ms)
|
||||
//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
|
||||
BMessageRunner *runner = new BMessageRunner(this, // target BHandler
|
||||
new BMessage(kPulse),
|
||||
100000 // interval in μs (0 ms)
|
||||
);
|
||||
|
||||
updateHistoryInfo();
|
||||
updateHistoryInfo();
|
||||
|
||||
PostMessage(kCheckKey);
|
||||
PostMessage(kCheckKey);
|
||||
}
|
||||
|
||||
void MainWindow::checkValidKey() {
|
||||
|
@ -377,9 +406,9 @@ void MainWindow::MessageReceived(BMessage *message) {
|
|||
case kViewJSON: {
|
||||
|
||||
_infoView->SetText("Showing JSON");
|
||||
_answerView->SetText(lastJSON.c_str());
|
||||
progressAnim=0;
|
||||
} break;
|
||||
_answerView->SetText(lastJSON.c_str());
|
||||
progressAnim = 0;
|
||||
} break;
|
||||
|
||||
case kSendReply: {
|
||||
|
||||
|
@ -396,13 +425,10 @@ void MainWindow::MessageReceived(BMessage *message) {
|
|||
const char *text;
|
||||
const char *fullJSON;
|
||||
|
||||
|
||||
if (message->FindString("json", &fullJSON) == B_OK) {
|
||||
|
||||
lastJSON = std::string(fullJSON);
|
||||
|
||||
}
|
||||
|
||||
lastJSON = std::string(fullJSON);
|
||||
}
|
||||
|
||||
if (message->FindString("text", &text) == B_OK) {
|
||||
// printf("Received text: %s\n", text);
|
||||
|
@ -485,14 +511,12 @@ BMenuBar *MainWindow::_BuildMenu() {
|
|||
|
||||
menuBar->AddItem(menu);
|
||||
|
||||
menu->AddSeparatorItem();
|
||||
item = new BMenuItem(B_TRANSLATE("View full json" B_UTF8_ELLIPSIS),
|
||||
menu->AddSeparatorItem();
|
||||
item = new BMenuItem(B_TRANSLATE("View full json" B_UTF8_ELLIPSIS),
|
||||
new BMessage(kViewJSON));
|
||||
item->SetTarget(this);
|
||||
item->SetShortcut('J', B_COMMAND_KEY | B_SHIFT_KEY);
|
||||
menu->AddItem(item);
|
||||
|
||||
|
||||
|
||||
return menuBar;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@ resource app_version {
|
|||
};
|
||||
|
||||
|
||||
|
||||
resource(55) #'VICN' import "artwork/icons/kConsoleApp";
|
||||
|
||||
|
||||
resource vector_icon {
|
||||
$"6E6369660804016B0500020006023CADEB3D1051BD10513CADEB4C3551C6C7FF"
|
||||
$"00FFDB97FFFCAF29020006023A647ABA3F0A3A3F0A3A647AC92D47CA165100FF"
|
||||
|
@ -48,4 +52,3 @@ resource vector_icon {
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
BIN
artwork/icons/kConsoleApp
Normal file
BIN
artwork/icons/kConsoleApp
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue