handles history
This commit is contained in:
parent
dfb077be70
commit
85be8d6ef4
7 changed files with 452 additions and 212 deletions
367
MainWindow.cpp
367
MainWindow.cpp
|
@ -6,9 +6,11 @@
|
|||
#include "MainWindow.h"
|
||||
|
||||
static int progressAnim = 0;
|
||||
|
||||
static int progressColor = 0;
|
||||
static bool progressColorUp = false;
|
||||
|
||||
#include <Application.h>
|
||||
#include <Bitmap.h>
|
||||
#include <Button.h>
|
||||
#include <Catalog.h>
|
||||
#include <LayoutBuilder.h>
|
||||
|
@ -17,10 +19,11 @@ static int progressAnim = 0;
|
|||
#include <MimeType.h>
|
||||
#include <ScrollView.h>
|
||||
#include <StringView.h>
|
||||
|
||||
#include <View.h>
|
||||
#include <TranslationUtils.h>
|
||||
|
||||
#include <Alert.h>
|
||||
#include <MessageRunner.h>
|
||||
#include <View.h>
|
||||
|
||||
#include "Conversation.h"
|
||||
|
||||
|
@ -28,15 +31,13 @@ static int progressAnim = 0;
|
|||
#define B_TRANSLATION_CONTEXT "Window"
|
||||
|
||||
MainWindow::MainWindow()
|
||||
: BWindow(BRect(100, 100, 600, 400), B_TRANSLATE("BeDumb"), B_TITLED_WINDOW,
|
||||
: BWindow(BRect(50, 50, 600, 400), B_TRANSLATE("DumBer"), B_TITLED_WINDOW,
|
||||
B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE) {
|
||||
|
||||
|
||||
//Without this conversation would never get bmessages from HttpRequest
|
||||
LockLooper();
|
||||
AddHandler(_conversation);
|
||||
UnlockLooper();
|
||||
|
||||
// Without this conversation would never get bmessages from HttpRequest
|
||||
LockLooper();
|
||||
AddHandler(_conversation);
|
||||
UnlockLooper();
|
||||
|
||||
BMenuBar *menuBar = _BuildMenu();
|
||||
|
||||
|
@ -47,18 +48,21 @@ MainWindow::MainWindow()
|
|||
_inputField->MakeEditable(true);
|
||||
_inputField->MakeSelectable(true);
|
||||
_inputField->SetWordWrap(true);
|
||||
|
||||
|
||||
_modelMenu = new BPopUpMenu("Models");
|
||||
_modelField = new BMenuField("model_field", NULL, _modelMenu);
|
||||
_modelField->SetEnabled(false);
|
||||
|
||||
_progress = new BStatusBar("prog");
|
||||
_progress->SetMaxValue(100);
|
||||
_progress->SetTo(0);
|
||||
_progress->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
BStringView *header = new BStringView("biglabel", "Let's Be Dumber!");
|
||||
BFont font;
|
||||
header->GetFont(&font);
|
||||
font.SetSize(20);
|
||||
header->SetFont(&font);
|
||||
// BStringView *header = new BStringView("biglabel", "Let's Be Dumber!");
|
||||
// BFont font;
|
||||
// header->GetFont(&font);
|
||||
// font.SetSize(20);
|
||||
// header->SetFont(&font);
|
||||
|
||||
// Info view, only one line high
|
||||
_infoView = new BTextView("info");
|
||||
|
@ -68,115 +72,275 @@ MainWindow::MainWindow()
|
|||
_infoView->MakeSelectable(false);
|
||||
_infoView->SetWordWrap(false);
|
||||
|
||||
|
||||
_infoConversation = new BTextView("convers");
|
||||
_infoConversation->SetText("(No history)");
|
||||
_infoConversation->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
_infoConversation->MakeEditable(false);
|
||||
_infoConversation->MakeSelectable(false);
|
||||
_infoConversation->SetWordWrap(false);
|
||||
|
||||
|
||||
float lineHeight = _infoView->LineHeight(0);
|
||||
_infoView->SetExplicitMinSize(BSize(B_SIZE_UNSET, lineHeight));
|
||||
_infoView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, lineHeight));
|
||||
|
||||
float askH = lineHeight * 5;
|
||||
_infoConversation->SetExplicitMinSize(BSize(B_SIZE_UNSET, lineHeight));
|
||||
_infoConversation->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, lineHeight));
|
||||
|
||||
float askH = lineHeight * 2;
|
||||
_inputField->SetExplicitMinSize(BSize(B_SIZE_UNSET, askH));
|
||||
|
||||
|
||||
BButton *sendButton =
|
||||
_sendButton =
|
||||
new BButton("send", B_TRANSLATE("Send"), new BMessage(kSendPrompt),
|
||||
B_WILL_DRAW | B_NAVIGABLE);
|
||||
|
||||
_sendButton->MakeDefault(true);
|
||||
|
||||
_answerView = new BTextView("answer", B_WILL_DRAW | B_FOLLOW_ALL);
|
||||
_answerView->MakeEditable(false); // Disable editing
|
||||
_answerView->MakeSelectable(true); // Enable text selection
|
||||
_answerView->SetWordWrap(true);
|
||||
|
||||
_answerView->SetExplicitMinSize(BSize(B_SIZE_UNSET, askH*2));
|
||||
|
||||
BScrollView *scrollView =
|
||||
new BScrollView("scroll_view", _answerView, B_FOLLOW_ALL | B_WILL_DRAW, 0,
|
||||
false, true); // horizontal and vertical scrollbars
|
||||
|
||||
|
||||
//BView *imageView = new BView("icon_view", B_WILL_DRAW | B_FOLLOW_NONE);
|
||||
//imageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
|
||||
BStringView *headerQuestion = new BStringView("questionLabel", "Your question: ");
|
||||
BStringView *headerAnswer = new BStringView("questionAnswer", "Answer: ");
|
||||
|
||||
|
||||
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
|
||||
|
||||
.AddGlue(0.1)
|
||||
.Add(header)
|
||||
|
||||
.AddGlue(0.1)
|
||||
.Add(headerQuestion)
|
||||
.AddGroup(B_HORIZONTAL, 0, 1)
|
||||
.Add(_inputField,0.25)
|
||||
.AddGroup(B_HORIZONTAL, 0, 0)
|
||||
.AddGlue()
|
||||
|
||||
.AddGroup(B_VERTICAL, 0, 1)
|
||||
// .Add(imageView)
|
||||
|
||||
// .AddGlue()
|
||||
|
||||
.AddGroup(B_HORIZONTAL, 0, 1) // left-align cnv
|
||||
.Add(_infoConversation)
|
||||
.AddGlue()
|
||||
.End()
|
||||
.AddGlue()
|
||||
|
||||
|
||||
.AddGroup(B_HORIZONTAL, 0, 1) // left-align _modelField
|
||||
.Add(_modelField)
|
||||
.AddGlue()
|
||||
.End()
|
||||
|
||||
.AddGroup(B_HORIZONTAL, 0, 1) // left-align _sendButton
|
||||
.Add(_sendButton)
|
||||
.AddGlue()
|
||||
.End()
|
||||
|
||||
.End()
|
||||
.SetInsets(12, 6, 12, 0)
|
||||
|
||||
.AddGroup(B_HORIZONTAL, 0, 1)
|
||||
.Add(_inputField)
|
||||
.AddGroup(B_HORIZONTAL, 0, 1)
|
||||
.Add(sendButton)
|
||||
.End()
|
||||
.End()
|
||||
|
||||
.AddGlue(0.1)
|
||||
.Add(scrollView)
|
||||
.Add(headerAnswer)
|
||||
.Add(scrollView,1)
|
||||
.Add(_progress)
|
||||
.Add(_infoView)
|
||||
|
||||
.SetInsets(5, 5, 5, 5)
|
||||
.SetInsets(6, 6, 6, 6)
|
||||
|
||||
.End();
|
||||
|
||||
// Just to animate progress
|
||||
BMessageRunner *runner = new BMessageRunner(this, // target BHandler
|
||||
new BMessage(kPulse),
|
||||
100000 // interval in μs (0 ms)
|
||||
|
||||
|
||||
|
||||
//Just to animate progress
|
||||
BMessageRunner* runner = new BMessageRunner(
|
||||
this, // target BHandler
|
||||
new BMessage(kPulse),
|
||||
50000 // interval in μs (0 ms)
|
||||
);
|
||||
);
|
||||
|
||||
PostMessage(kCheckKey);
|
||||
// BBitmap* image = BTranslationUtils::GetBitmapFile("/boot/system/data/icons/hicolor/64x64/apps/kdevelop.png");
|
||||
//imageView->SetViewBitmap(image);
|
||||
|
||||
// imageView->SetViewColor(B_TRANSPARENT_COLOR);
|
||||
|
||||
updateHistoryInfo();
|
||||
|
||||
|
||||
PostMessage(kCheckKey);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::checkValidKey() {
|
||||
|
||||
if (!_conversation->validKey)
|
||||
{
|
||||
_infoView->SetText("MISSING API KEY");
|
||||
ShowMissingKeyAlertAndQuit();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_infoView->SetText("API Key loaded.");
|
||||
_conversation->loadModels();
|
||||
}
|
||||
if (!_conversation->validKey) {
|
||||
_infoView->SetText("MISSING API KEY");
|
||||
ShowMissingKeyAlertAndQuit();
|
||||
return;
|
||||
} else {
|
||||
_infoView->SetText("API Key loaded.");
|
||||
|
||||
waitMode = true;
|
||||
progressColor = 0;
|
||||
progressAnim = 1;
|
||||
|
||||
_conversation->loadModels();
|
||||
_infoView->SetText("Requesting model lists...");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::ShowMissingKeyAlertAndQuit()
|
||||
{
|
||||
void MainWindow::ShowMissingKeyAlertAndQuit() {
|
||||
|
||||
BAlert* alert = new BAlert("Missing key file!", "Create a file named 'openai_key' containing a valid OpenAI Token on one line in \n\n/boot/home/config/settings/openai_key .\n\nThen relaunch the app.\n\nBe aware that this is not a safe storage so don't use valuable keys.", "Oh, no", "Sigh", "Just give up", B_WIDTH_AS_USUAL,B_WARNING_ALERT);
|
||||
|
||||
alert->SetType(B_INFO_ALERT);
|
||||
|
||||
uint32 result = alert->Go();
|
||||
PostMessage(B_QUIT_REQUESTED);
|
||||
BAlert *alert = new BAlert(
|
||||
"Missing key file!",
|
||||
"Create a file named 'openai_key' containing a valid OpenAI Token on one "
|
||||
"line in \n\n/boot/home/config/settings/openai_key .\n\nThen relaunch "
|
||||
"the app.\n\nBe aware that this is not a safe storage so don't use "
|
||||
"valuable keys.",
|
||||
"Oh, no", "Sigh", "Just give up", B_WIDTH_AS_USUAL, B_WARNING_ALERT);
|
||||
|
||||
alert->SetType(B_INFO_ALERT);
|
||||
|
||||
uint32 result = alert->Go();
|
||||
PostMessage(B_QUIT_REQUESTED);
|
||||
}
|
||||
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void MainWindow::SelectModelByName(const char *targetLabel) {
|
||||
BMenu *menu = _modelField->Menu();
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
for (int32 i = 0; i < menu->CountItems(); ++i) {
|
||||
BMenuItem *item = menu->ItemAt(i);
|
||||
|
||||
// printf("comparing %s\n", item->Label());
|
||||
if (item && strcmp(item->Label(), targetLabel) == 0) {
|
||||
printf("FOUND %s\n", item->Label());
|
||||
|
||||
item->SetMarked(true);
|
||||
PostMessage(item->Message());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::updateHistoryInfo() {
|
||||
|
||||
_infoConversation->SetText(_conversation->buildHistoryInfoLine().c_str());
|
||||
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::MessageReceived(BMessage *message) {
|
||||
|
||||
switch (message->what) {
|
||||
switch (message->what) {
|
||||
|
||||
case kCheckKey: {
|
||||
checkValidKey();
|
||||
}
|
||||
break;
|
||||
case kCheckKey: {
|
||||
checkValidKey();
|
||||
} break;
|
||||
|
||||
case kPulse: {
|
||||
|
||||
if (progressAnim >=1 && progressAnim <= 85) {
|
||||
_progress->SetTo(progressAnim);
|
||||
progressAnim++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// case kMsgNewFile: {
|
||||
|
||||
|
||||
case kClearHistory: {
|
||||
|
||||
printf("will clear history");
|
||||
_infoView->SetText("Cleared conversation history. Starting new context");
|
||||
_inputField->SetText("");
|
||||
_answerView->SetText("");
|
||||
_conversation->ClearHistory();
|
||||
updateHistoryInfo();
|
||||
|
||||
} break;
|
||||
|
||||
|
||||
case kModelSelected: {
|
||||
|
||||
printf("model selected");
|
||||
const char *model;
|
||||
|
||||
if (message->FindString("model", &model) == B_OK) {
|
||||
_infoView->SetText(BString("Model selected: ") << model);
|
||||
printf("model selected: %s\n", model);
|
||||
_conversation->setModel(model);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case kModelsReceived: {
|
||||
waitMode = false;
|
||||
progressAnim = 100;
|
||||
|
||||
_modelMenu->RemoveItems(0, _modelMenu->CountItems(), true);
|
||||
_infoView->SetText("Models list received.");
|
||||
|
||||
_modelMenu->SetTargetForItems(this);
|
||||
const char *model;
|
||||
for (int32 i = 0; message->FindString("model", i, &model) == B_OK; ++i) {
|
||||
BMessage *modelMsg = new BMessage(kModelSelected);
|
||||
modelMsg->AddString("model", model);
|
||||
BMenuItem *item = new BMenuItem(model, modelMsg);
|
||||
item->SetTarget(this);
|
||||
_modelMenu->AddItem(item);
|
||||
}
|
||||
_modelField->SetEnabled(true);
|
||||
_sendButton->SetEnabled(true);
|
||||
|
||||
SelectModelByName("gpt-4o-mini");
|
||||
|
||||
} break;
|
||||
|
||||
case kPulse: {
|
||||
uint8 r = (uint8)((20 * progressColor) / 255);
|
||||
uint8 g = (uint8)((128 * progressColor) / 255);
|
||||
uint8 b = (uint8)((255 * progressColor) / 255);
|
||||
|
||||
rgb_color color = {r, g, b, 255};
|
||||
_progress->SetBarColor(color);
|
||||
|
||||
if (waitMode) {
|
||||
|
||||
int step = 8;
|
||||
|
||||
if (progressColorUp)
|
||||
progressColor += step;
|
||||
else
|
||||
progressColor -= step;
|
||||
|
||||
if (progressColor >= 255) {
|
||||
progressColorUp = false;
|
||||
progressColor = 255;
|
||||
} else if (progressColor <= 0) {
|
||||
progressColorUp = true;
|
||||
progressColor = 0;
|
||||
}
|
||||
|
||||
if (progressAnim >= 1 && progressAnim <= 99) {
|
||||
_progress->SetTo(progressAnim);
|
||||
progressAnim++;
|
||||
}
|
||||
} else
|
||||
_progress->SetTo(progressAnim);
|
||||
} break;
|
||||
|
||||
// case kMsgNewFile: {
|
||||
// fSaveMenuItem->SetEnabled(false);
|
||||
// printf("New\n");
|
||||
// } break;
|
||||
|
@ -194,39 +358,46 @@ void MainWindow::MessageReceived(BMessage *message) {
|
|||
|
||||
_progress->SetMaxValue(100);
|
||||
_progress->SetTo(0);
|
||||
_answerView->SetText("...");
|
||||
progressAnim = 1;//will trigger animation
|
||||
|
||||
|
||||
_answerView->SetText("...");
|
||||
progressAnim = 1; // will trigger animation
|
||||
|
||||
_sendButton->SetEnabled(false);
|
||||
waitMode = true;
|
||||
progressColor = 255;
|
||||
|
||||
printf("Button Pressed\n");
|
||||
_infoView->SetText("Asking...");
|
||||
_infoView->SetText("Asking...");
|
||||
_conversation->ask(std::string(_inputField->Text()));
|
||||
|
||||
} break;
|
||||
|
||||
case kSendReply: {
|
||||
|
||||
_sendButton->SetEnabled(true);
|
||||
|
||||
waitMode = false;
|
||||
progressColor = 255;
|
||||
|
||||
printf("Conversation returned!\n");
|
||||
_infoView->SetText("Answer Received");
|
||||
_infoView->SetText("Answer Received");
|
||||
|
||||
progressAnim = 100;
|
||||
progressAnim = 100;
|
||||
|
||||
|
||||
const char* text;
|
||||
if (message->FindString("text", &text) == B_OK) {
|
||||
// printf("Received text: %s\n", text);
|
||||
// Do something with text (e.g., set it to a BTextView)
|
||||
_answerView->SetText(text);
|
||||
} else {
|
||||
printf("No text found in message.\n");
|
||||
_answerView->SetText("NO TEXT IN REPLY");
|
||||
}
|
||||
const char *text;
|
||||
if (message->FindString("text", &text) == B_OK) {
|
||||
// printf("Received text: %s\n", text);
|
||||
// Do something with text (e.g., set it to a BTextView)
|
||||
_answerView->SetText(text);
|
||||
} else {
|
||||
printf("No text found in message.\n");
|
||||
_answerView->SetText("NO TEXT IN REPLY");
|
||||
}
|
||||
_progress->SetMaxValue(100);
|
||||
_progress->SetTo(100);
|
||||
|
||||
} break;
|
||||
|
||||
updateHistoryInfo();
|
||||
|
||||
} break;
|
||||
|
||||
default: {
|
||||
// message->PrintToStream();
|
||||
|
@ -240,7 +411,6 @@ void MainWindow::MessageReceived(BMessage *message) {
|
|||
|
||||
} // end function
|
||||
|
||||
|
||||
BMenuBar *MainWindow::_BuildMenu() {
|
||||
|
||||
BMenuBar *menuBar = new BMenuBar("menubar");
|
||||
|
@ -272,10 +442,23 @@ BMenuBar *MainWindow::_BuildMenu() {
|
|||
item =
|
||||
new BMenuItem(B_TRANSLATE("Quit"), new BMessage(B_QUIT_REQUESTED), 'Q');
|
||||
menu->AddItem(item);
|
||||
|
||||
|
||||
menuBar->AddItem(menu);
|
||||
|
||||
//-------------------------
|
||||
|
||||
menu = new BMenu(B_TRANSLATE("History"));
|
||||
|
||||
item = new BMenuItem(B_TRANSLATE("Clear History" B_UTF8_ELLIPSIS),
|
||||
new BMessage(kClearHistory));
|
||||
item->SetTarget(this);
|
||||
menu->AddItem(item);
|
||||
|
||||
|
||||
menuBar->AddItem(menu);
|
||||
|
||||
|
||||
|
||||
return menuBar;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue