saves models to settings to avoid reload, with option to force from menu
This commit is contained in:
parent
dd033a7896
commit
177cdb925f
10 changed files with 269 additions and 42 deletions
BIN
.genio
BIN
.genio
Binary file not shown.
67
App.cpp
67
App.cpp
|
@ -9,12 +9,25 @@
|
|||
#include <AboutWindow.h>
|
||||
#include <Catalog.h>
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "Application"
|
||||
|
||||
const char *kApplicationSignature = "application/x-vnd.SLema-DumBer";
|
||||
|
||||
App::App() : BApplication(kApplicationSignature) {
|
||||
|
||||
BMessage s = LoadMessageFromFile(kSettingsFileName);
|
||||
|
||||
if (s.what=='STNG')
|
||||
settingsMessage = s;
|
||||
else
|
||||
{
|
||||
settingsMessage.what = 'STNG';
|
||||
settingsMessage.AddInt32("settings_format_version", 1); // Initial data
|
||||
}
|
||||
|
||||
MainWindow *m = new MainWindow();
|
||||
m->SetLook(B_DOCUMENT_WINDOW_LOOK);
|
||||
m->SetFeel(B_NORMAL_WINDOW_FEEL);
|
||||
|
@ -44,8 +57,62 @@ void App::AboutRequested() {
|
|||
|
||||
|
||||
|
||||
void App::MessageReceived(BMessage *message) {
|
||||
|
||||
switch (message->what) {
|
||||
|
||||
case kSettingsUpdate: {
|
||||
|
||||
// NO DO NOT CLEAR message, we can just overwrite one field and save the whole thing each time
|
||||
//settingsMessage.MakeEmpty();
|
||||
|
||||
std::cout << "Received settings update: " ;
|
||||
|
||||
|
||||
int32 count = message->CountNames(B_ANY_TYPE);
|
||||
for (int32 index = 0; index < count; ++index) {
|
||||
char* name;
|
||||
uint32 type;
|
||||
int32 itemCount;
|
||||
|
||||
std::cout << "Received settings update - key: " << name;
|
||||
|
||||
// Retrieve information about the item at the index
|
||||
if (message->GetInfo(B_ANY_TYPE, index, &name, &type, &itemCount) == B_NO_ERROR) {
|
||||
|
||||
if (type == B_STRING_TYPE) {
|
||||
BString value;
|
||||
if (message->FindString(name, &value) == B_NO_ERROR) {
|
||||
settingsMessage.AddString(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SaveMessageToFile(settingsMessage,kSettingsFileName);
|
||||
} break;
|
||||
|
||||
|
||||
default: {
|
||||
// message->PrintToStream();
|
||||
BHandler::MessageReceived(
|
||||
message); // call the parent handler for other messages
|
||||
// _infoView->SetText(message->FindMessage());
|
||||
break;
|
||||
}
|
||||
|
||||
} // end switch
|
||||
|
||||
} // end function
|
||||
|
||||
|
||||
|
||||
int main() {
|
||||
App *app = new App();
|
||||
|
||||
|
||||
app->Run();
|
||||
delete app;
|
||||
return 0;
|
||||
|
|
6
App.h
6
App.h
|
@ -5,7 +5,7 @@
|
|||
#ifndef APP_H
|
||||
#define APP_H
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
|
@ -16,10 +16,14 @@ public:
|
|||
App();
|
||||
virtual ~App();
|
||||
|
||||
|
||||
virtual void AboutRequested();
|
||||
|
||||
MainWindow* mainWindow = nullptr;
|
||||
|
||||
BMessage settingsMessage;
|
||||
BMessage* getSettingsMessage() { return &settingsMessage; }
|
||||
virtual void MessageReceived(BMessage *msg);
|
||||
|
||||
void ReadyToRun()
|
||||
{
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
|
||||
#include <Application.h>
|
||||
|
||||
#include "Utils.h"
|
||||
#include "App.h"
|
||||
|
||||
|
||||
Conversation::Conversation(BHandler *replyTo) {
|
||||
|
||||
replyTarget = replyTo;
|
||||
|
@ -49,8 +53,7 @@ void Conversation::ClearHistory() {
|
|||
_messageHistory.clear();
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
Conversation::FilterTextModels(const json &modelsJson) {
|
||||
status_t Conversation::FilterTextModels(const json &modelsJson) {
|
||||
std::vector<std::string> result;
|
||||
std::regex pattern("gpt|text|curie|babbage|ada");
|
||||
|
||||
|
@ -69,10 +72,27 @@ Conversation::FilterTextModels(const json &modelsJson) {
|
|||
result.push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.empty())
|
||||
return B_ERROR;
|
||||
|
||||
|
||||
std::sort(result.begin(), result.end(),
|
||||
std::greater<>()); // inverse alphabetical to get gpt-4 on top
|
||||
return result;
|
||||
|
||||
PrintAsJsonArray(result);
|
||||
|
||||
BMessage msg(kModelsReceived);
|
||||
for (const auto &model : result) {
|
||||
msg.AddString("model", model.c_str());
|
||||
}
|
||||
sendReply(msg);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void Conversation::MessageReceived(BMessage *message) {
|
||||
|
@ -148,18 +168,13 @@ void Conversation::MessageReceived(BMessage *message) {
|
|||
|
||||
if (objType == "list") {
|
||||
// printf("full Reply as text:%s",body.text.value().String());
|
||||
|
||||
std::vector validModels = FilterTextModels(parsed);
|
||||
PrintAsJsonArray(validModels);
|
||||
BMessage msg(kModelsReceived);
|
||||
|
||||
for (const auto &model : validModels) {
|
||||
msg.AddString("model", model.c_str());
|
||||
}
|
||||
sendReply(msg);
|
||||
|
||||
// std::string content =
|
||||
// parsed["choices"][0]["message"]["content"];
|
||||
if (FilterTextModels(parsed)==B_OK)
|
||||
{
|
||||
//Save models in settings so we don't have to do one request at start each time
|
||||
BMessage message(kSettingsUpdate);
|
||||
message.AddString("models_json", BString(fullBody));
|
||||
be_app->PostMessage(&message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -236,20 +251,20 @@ void Conversation::MessageReceived(BMessage *message) {
|
|||
sendReply(msgr);
|
||||
|
||||
|
||||
BMessage msg(kShowError);
|
||||
BMessage msg(kShowStatus);
|
||||
msg.AddString("text", e.DebugMessage());
|
||||
sendReply(msg);
|
||||
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
std::cout << "Caught a standard exception: " << e.what() << std::endl;
|
||||
BMessage msg(kShowError);
|
||||
BMessage msg(kShowStatus);
|
||||
msg.AddString("text", e.what());
|
||||
sendReply(msg);
|
||||
|
||||
} catch (...) {
|
||||
std::cout << "Caught an unknown exception!" << std::endl;
|
||||
BMessage msg(kShowError);
|
||||
BMessage msg(kShowStatus);
|
||||
msg.AddString("text", "unknown exception");
|
||||
sendReply(msg);
|
||||
}
|
||||
|
@ -268,7 +283,40 @@ std::string Conversation::buildBearerKey() {
|
|||
return bearer;
|
||||
}
|
||||
|
||||
void Conversation::loadModels() {
|
||||
void Conversation::loadModelsForced(bool force) {
|
||||
|
||||
// TRY first to get models from settings files
|
||||
if (force==false) {
|
||||
App* app = dynamic_cast<App*>(be_app);
|
||||
if (app) {
|
||||
BMessage* settings = app->getSettingsMessage();
|
||||
const char* jsonString;
|
||||
|
||||
if (settings->FindString("models_json", &jsonString)==B_NO_ERROR)
|
||||
{
|
||||
json parsed = json::parse(jsonString);
|
||||
std::string objType = parsed["object"];
|
||||
if (objType == "list") {
|
||||
//printf("loadModelFromSettings :%s",jsonString);
|
||||
|
||||
if(FilterTextModels(parsed)==B_OK)
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
std::cout << "no models in settings object...\n";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//MODELS not in settings, ask them.
|
||||
|
||||
|
||||
BMessage msg(kShowStatus);
|
||||
msg.AddString("text", "Asking server for list of models...");
|
||||
sendReply(msg);
|
||||
|
||||
|
||||
auto url = BUrl("https://api.openai.com/v1/models", true);
|
||||
BHttpRequest request = BHttpRequest(url);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
static const uint32 kShowError = 'serr';
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -63,11 +63,11 @@ public:
|
|||
virtual void MessageReceived(BMessage *msg);
|
||||
|
||||
|
||||
std::vector<std::string> FilterTextModels(const json& modelsJson);
|
||||
status_t FilterTextModels(const json& modelsJson);
|
||||
|
||||
void ask(const std::string& prompt);
|
||||
void setModel(const std::string& prompt);
|
||||
void loadModels();
|
||||
void loadModelsForced(bool force);
|
||||
void PrintAsJsonArray(const std::vector<std::string>& models) ;
|
||||
void ClearHistory();
|
||||
std::string buildHistoryInfoLine();
|
||||
|
|
|
@ -28,9 +28,10 @@ static bool progressColorUp = false;
|
|||
#include <View.h>
|
||||
|
||||
#include <Path.h>
|
||||
#include <FindDirectory.h>
|
||||
|
||||
#include "Conversation.h"
|
||||
#include <FindDirectory.h>
|
||||
#include "Utils.h"
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "Window"
|
||||
|
@ -236,11 +237,12 @@ void MainWindow::checkValidKey() {
|
|||
progressColor = 0;
|
||||
progressAnim = 1;
|
||||
|
||||
_conversation->loadModels();
|
||||
_infoView->SetText("Requesting model lists...");
|
||||
|
||||
_conversation->loadModelsForced(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::ShowMissingKeyAlertAndQuit() {
|
||||
|
||||
BAlert *alert = new BAlert(
|
||||
|
@ -302,15 +304,27 @@ void MainWindow::MessageReceived(BMessage *message) {
|
|||
updateHistoryInfo();
|
||||
|
||||
} break;
|
||||
|
||||
case kRequestModels: {
|
||||
|
||||
case kShowError: {
|
||||
printf("will Request models");
|
||||
//_infoView->SetText("Cleared conversation history. Starting new context");
|
||||
//_inputField->SetText("");
|
||||
//_answerView->SetText("");
|
||||
//_conversation->ClearHistory();
|
||||
_conversation->loadModelsForced(true);
|
||||
//updateHistoryInfo();
|
||||
|
||||
printf("error received:");
|
||||
} break;
|
||||
|
||||
case kShowStatus: {
|
||||
|
||||
printf("status or error received:");
|
||||
const char *text;
|
||||
|
||||
if (message->FindString("text", &text) == B_OK) {
|
||||
_infoView->SetText(BString("ERROR: ") << text);
|
||||
printf("ERROR: %s\n", text);
|
||||
_infoView->SetText(BString("Status: ") << text);
|
||||
printf("Status: %s\n", text);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
@ -517,6 +531,8 @@ BMenuBar *MainWindow::_BuildMenu() {
|
|||
|
||||
menu->AddSeparatorItem();
|
||||
|
||||
|
||||
//--------------------------------
|
||||
item = new BMenuItem(B_TRANSLATE("Clear History" B_UTF8_ELLIPSIS),
|
||||
new BMessage(kClearHistory));
|
||||
item->SetTarget(this);
|
||||
|
@ -525,12 +541,22 @@ BMenuBar *MainWindow::_BuildMenu() {
|
|||
|
||||
menuBar->AddItem(menu);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
//--------------------------------
|
||||
item = new BMenuItem(B_TRANSLATE("Update models..." B_UTF8_ELLIPSIS),
|
||||
new BMessage(kRequestModels));
|
||||
item->SetTarget(this);
|
||||
//item->SetShortcut('J', B_COMMAND_KEY | B_SHIFT_KEY);
|
||||
menu->AddItem(item);
|
||||
|
||||
return menuBar;
|
||||
}
|
||||
|
|
13
MainWindow.h
13
MainWindow.h
|
@ -17,18 +17,6 @@
|
|||
|
||||
#include "Conversation.h"
|
||||
|
||||
static const uint32 kCheckKey = 'chkk';
|
||||
static const uint32 kMsgNewFile = 'fnew';
|
||||
static const uint32 kMsgOpenFile = 'fopn';
|
||||
static const uint32 kMsgSaveFile = 'fsav';
|
||||
static const uint32 kModelSelected = 'msel';
|
||||
static const uint32 kViewJSON = 'vjso';
|
||||
|
||||
static const uint32 kPulse = 'plse';
|
||||
|
||||
static const uint32 kSendPrompt = 'kspt';
|
||||
static const uint32 kQuestionChanged = 'kqch';
|
||||
|
||||
class MainWindow : public BWindow {
|
||||
public:
|
||||
MainWindow();
|
||||
|
@ -71,6 +59,7 @@ private:
|
|||
BMenuField *_modelField;
|
||||
BPopUpMenu *_modelMenu;
|
||||
BButton *_sendButton;
|
||||
BMessage *settings;
|
||||
|
||||
// BMenuItem *fSaveMenuItem;
|
||||
};
|
||||
|
|
1
Makefile
1
Makefile
|
@ -33,6 +33,7 @@ APP_MIME_SIG = application/x-vnd.SLema-DumBer
|
|||
# same name (source.c or source.cpp) are included from different directories.
|
||||
# Also note that spaces in folder names do not work well with this Makefile.
|
||||
SRCS = App.cpp \
|
||||
Utils.cpp \
|
||||
MainWindow.cpp \
|
||||
Conversation.cpp
|
||||
|
||||
|
|
52
Utils.cpp
Normal file
52
Utils.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2024, My Name <my@email.address>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
#include <File.h>
|
||||
#include <Path.h>
|
||||
#include <Directory.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Message.h>
|
||||
#include <String.h>
|
||||
|
||||
|
||||
status_t SaveMessageToFile(const BMessage& message, const char* fileName) {
|
||||
BPath path;
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) {
|
||||
return B_ERROR;
|
||||
}
|
||||
path.Append(fileName);
|
||||
|
||||
BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE);
|
||||
if (file.InitCheck() != B_OK) {
|
||||
return file.InitCheck();
|
||||
}
|
||||
return message.Flatten(&file);
|
||||
}
|
||||
|
||||
BMessage LoadMessageFromFile(const char* fileName) {
|
||||
BPath path;
|
||||
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) {
|
||||
return BMessage(B_ERROR); // Return a message indicating an error
|
||||
}
|
||||
|
||||
path.Append(fileName);
|
||||
|
||||
BFile file(path.Path(), B_READ_ONLY);
|
||||
if (file.InitCheck() != B_OK) {
|
||||
return BMessage(file.InitCheck()); // Return a message with the error status
|
||||
}
|
||||
|
||||
BMessage message;
|
||||
status_t status = message.Unflatten(&file);
|
||||
if (status != B_OK) {
|
||||
return BMessage(status); // Return a message indicating unflattening error
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
40
Utils.h
Normal file
40
Utils.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2024, My Name <my@email.address>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include <Message.h>
|
||||
#include <String.h>
|
||||
#include <Path.h>
|
||||
#include <Directory.h>
|
||||
#include <File.h>
|
||||
|
||||
static const uint32 kShowStatus = 'stat';
|
||||
static const uint32 kCheckKey = 'chkK';
|
||||
static const uint32 kMsgNewFile = 'fNEW';
|
||||
static const uint32 kMsgOpenFile = 'fOPN';
|
||||
static const uint32 kMsgSaveFile = 'fSAV';
|
||||
static const uint32 kModelSelected = 'mSEL';
|
||||
static const uint32 kRequestModels = 'mREQ';
|
||||
|
||||
static const uint32 kViewJSON = 'vJSN';
|
||||
static const uint32 kSettingsUpdate = 'sUPD';
|
||||
static const char* kSettingsFileName = "bedumber_settings.bmessage";
|
||||
|
||||
|
||||
static const uint32 kPulse = 'plse';
|
||||
|
||||
static const uint32 kSendPrompt = 'kspt';
|
||||
static const uint32 kQuestionChanged = 'kqch';
|
||||
|
||||
|
||||
|
||||
status_t SaveMessageToFile(const BMessage& message, const char* fileName);
|
||||
BMessage LoadMessageFromFile(const char* fileName);
|
||||
|
||||
#endif // UTILS_H
|
Loading…
Add table
Add a link
Reference in a new issue