separated request class
This commit is contained in:
parent
2dd76e787e
commit
c8523bc115
8 changed files with 336 additions and 209 deletions
8
App.cpp
8
App.cpp
|
@ -15,10 +15,16 @@
|
||||||
const char *kApplicationSignature = "application/x-vnd.SLema-DumBer";
|
const char *kApplicationSignature = "application/x-vnd.SLema-DumBer";
|
||||||
|
|
||||||
App::App() : BApplication(kApplicationSignature) {
|
App::App() : BApplication(kApplicationSignature) {
|
||||||
MainWindow *mainWindow = new MainWindow();
|
MainWindow *m = new MainWindow();
|
||||||
|
mainWindow = m;
|
||||||
mainWindow->Show();
|
mainWindow->Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
App::~App() {}
|
App::~App() {}
|
||||||
|
|
||||||
void App::AboutRequested() {
|
void App::AboutRequested() {
|
||||||
|
|
6
App.h
6
App.h
|
@ -5,6 +5,7 @@
|
||||||
#ifndef APP_H
|
#ifndef APP_H
|
||||||
#define APP_H
|
#define APP_H
|
||||||
|
|
||||||
|
#include "MainWindow.h"
|
||||||
|
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
|
|
||||||
|
@ -17,8 +18,13 @@ public:
|
||||||
|
|
||||||
virtual void AboutRequested();
|
virtual void AboutRequested();
|
||||||
|
|
||||||
|
MainWindow* mainWindow = nullptr;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // APP_H
|
#endif // APP_H
|
||||||
|
|
||||||
|
|
228
Conversation.cpp
Normal file
228
Conversation.cpp
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
// Conversation.cpp
|
||||||
|
#include "Conversation.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <File.h>
|
||||||
|
#include <FindDirectory.h>
|
||||||
|
#include <Path.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
#include <Url.h>
|
||||||
|
#include <MimeType.h>
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
|
|
||||||
|
Conversation::Conversation(BHandler* replyTo) {
|
||||||
|
|
||||||
|
replyTarget = replyTo;
|
||||||
|
_apiKey = ReadOpenAIKey();
|
||||||
|
printf("key is: %s", _apiKey.String());
|
||||||
|
|
||||||
|
}
|
||||||
|
Conversation::~Conversation() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Conversation::MessageReceived(BMessage* message) {
|
||||||
|
switch (message->what) {
|
||||||
|
//.. case B_HTTP_DATA_RECEIVED: {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
case UrlEvent::HostNameResolved: {
|
||||||
|
printf("Host name resolved\n");
|
||||||
|
auto name = message->GetString(UrlEventData::HostName);
|
||||||
|
message->PrintToStream();
|
||||||
|
|
||||||
|
//_infoView->SetText("Hostname resolve...");
|
||||||
|
//_infoView->SetText(name);
|
||||||
|
//_progress->SetTo(5);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case UrlEvent::ConnectionOpened: {
|
||||||
|
printf("ConnectionOpened\n");
|
||||||
|
//_progress->SetTo(10);
|
||||||
|
//_infoView->SetText("connection opened...");
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case UrlEvent::ResponseStarted: {
|
||||||
|
printf("ResponseStarted\n");
|
||||||
|
//_progress->SetTo(14);
|
||||||
|
//_infoView->SetText("ResponseStarted...");
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case UrlEvent::HttpRedirect: {
|
||||||
|
printf("HttpRedirect\n");
|
||||||
|
//_progress->SetTo(16);
|
||||||
|
//_infoView->SetText("HttpRedirect...");
|
||||||
|
} 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())
|
||||||
|
{
|
||||||
|
|
||||||
|
json parsed = json::parse(body.text.value().String());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::string content = parsed["choices"][0]["message"]["content"];
|
||||||
|
|
||||||
|
// printf("we got content:%s",content.c_str());
|
||||||
|
|
||||||
|
|
||||||
|
BMessage message(kSendReply);
|
||||||
|
message.AddString("text", BString(content.c_str()));
|
||||||
|
|
||||||
|
|
||||||
|
BLooper* looper = replyTarget->Looper(); // get the looper it's attached to
|
||||||
|
|
||||||
|
if (looper != nullptr) {
|
||||||
|
BMessenger messenger(replyTarget, looper);
|
||||||
|
messenger.SendMessage(&message);
|
||||||
|
} else {
|
||||||
|
printf("Handler not attached to a looper.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// status_t err = appMessenger.SendMessage(&message);
|
||||||
|
//if (err != B_OK)
|
||||||
|
// printf("SendMessage failed: %s\n", strerror(err));
|
||||||
|
//else
|
||||||
|
//printf("SendMessage OK");
|
||||||
|
|
||||||
|
// _answerView->SetText(content.c_str());
|
||||||
|
|
||||||
|
// _answerView->SetText(body.text.value());
|
||||||
|
|
||||||
|
}
|
||||||
|
// else
|
||||||
|
//_answerView->SetText("nuthin'");
|
||||||
|
}
|
||||||
|
|
||||||
|
//_infoView->SetText("Completed");
|
||||||
|
//_progress->SetMaxValue(100);
|
||||||
|
//_progress->SetTo(100);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case UrlEvent::HttpStatus: {
|
||||||
|
|
||||||
|
printf("HttpStatus\n");
|
||||||
|
//_infoView->SetText("HttpStatus received");
|
||||||
|
//_progress->SetTo(20);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
} 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..");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BHandler::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Conversation::ask(const std::string& prompt) {
|
||||||
|
|
||||||
|
printf("Asking prompt: %s",prompt.c_str());
|
||||||
|
|
||||||
|
if (_lastResult)
|
||||||
|
|
||||||
|
_sharedSession.Cancel(_lastResult->Identity());
|
||||||
|
|
||||||
|
|
||||||
|
auto url = BUrl("https://api.openai.com/v1/chat/completions");
|
||||||
|
BHttpRequest request = BHttpRequest(url);
|
||||||
|
request.SetMethod(BHttpMethod::Post);
|
||||||
|
|
||||||
|
// if the API key file contains a new line bhttpfields will crash with invalid
|
||||||
|
// content .end() requires include algorithm
|
||||||
|
std::string key = _apiKey.String();
|
||||||
|
key.erase(std::remove(key.begin(), key.end(), '\n'), key.end());
|
||||||
|
key.erase(std::remove(key.begin(), key.end(), '\r'), key.end());
|
||||||
|
|
||||||
|
std::string bearer = std::string("Bearer ") + std::string(key);
|
||||||
|
|
||||||
|
BHttpFields fields = BHttpFields();
|
||||||
|
fields.AddField("Authorization", bearer);
|
||||||
|
// fields.AddField("Content-Type", "application/json"); //NO, this will
|
||||||
|
// crash, we set it in request
|
||||||
|
request.SetFields(fields);
|
||||||
|
|
||||||
|
json bodyJson = {
|
||||||
|
{"model", "gpt-4o"},
|
||||||
|
{"messages", {{{"role", "user"}, {"content", prompt}}}}};
|
||||||
|
|
||||||
|
std::string body = bodyJson.dump();
|
||||||
|
|
||||||
|
BString mime = BString("application/json");
|
||||||
|
|
||||||
|
auto memoryIO = std::make_unique<BMemoryIO>(body.c_str(), body.size());
|
||||||
|
request.SetRequestBody(std::move(memoryIO), "application/json", body.size());
|
||||||
|
|
||||||
|
printf("Sending Prompt to server: %s\n", url.UrlString().String());
|
||||||
|
_lastResult = _sharedSession.Execute(std::move(request), nullptr, this);
|
||||||
|
|
||||||
|
if (_lastResult) {
|
||||||
|
printf("Result has identity: %d\n", _lastResult->Identity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BString Conversation::ReadOpenAIKey() {
|
||||||
|
|
||||||
|
// /boot/home/config/openai_key
|
||||||
|
// or ~/.config/openai_key on linux
|
||||||
|
|
||||||
|
BPath configPath;
|
||||||
|
if (find_directory(B_USER_SETTINGS_DIRECTORY, &configPath) != B_OK)
|
||||||
|
return "error: couldn't find config directory";
|
||||||
|
|
||||||
|
configPath.Append("openai_key");
|
||||||
|
|
||||||
|
BFile file(configPath.Path(), B_READ_ONLY);
|
||||||
|
|
||||||
|
printf("full path:%s\n", configPath.Path());
|
||||||
|
if (file.InitCheck() != B_OK)
|
||||||
|
return "error: couldn't open key file ";
|
||||||
|
|
||||||
|
off_t size;
|
||||||
|
file.GetSize(&size);
|
||||||
|
|
||||||
|
char *buffer = new char[size + 1];
|
||||||
|
file.Read(buffer, size);
|
||||||
|
buffer[size] = '\0'; // null-terminate
|
||||||
|
|
||||||
|
BString result(buffer);
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
61
Conversation.h
Normal file
61
Conversation.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// Conversation.h
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Handler.h>
|
||||||
|
#include <String.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//NEED THIS IN MAKE FILE TO USE PRIVATE HEADERS
|
||||||
|
//CXXFLAGS = -std=c++17 -Wall -I/boot/system/develop/headers/private
|
||||||
|
|
||||||
|
|
||||||
|
//Build works but Genio doesn't see class definitions unless I use full path ?
|
||||||
|
#include "/boot/system/develop/headers/private/netservices2/NetServicesDefs.h"
|
||||||
|
#include "/boot/system/develop/headers/private/netservices2/HttpSession.h"
|
||||||
|
#include "/boot/system/develop/headers/private/netservices2/HttpRequest.h"
|
||||||
|
#include "/boot/system/develop/headers/private/netservices2/HttpResult.h"
|
||||||
|
#include "/boot/system/develop/headers/private/netservices2/HttpFields.h"
|
||||||
|
#include "/boot/system/develop/headers/private/netservices2/ErrorsExt.h"
|
||||||
|
|
||||||
|
//From private headers !
|
||||||
|
//#include <NetServicesDefs.h>
|
||||||
|
//#include <HttpSession.h>
|
||||||
|
//#include <HttpSession.h>
|
||||||
|
//#include <HttpRequest.h>
|
||||||
|
//#include <HttpResult.h>
|
||||||
|
//#include <ErrorsExt.h>
|
||||||
|
|
||||||
|
|
||||||
|
static const uint32 kSendReply = 'krpl';
|
||||||
|
|
||||||
|
#include "include/json.hpp"
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
using namespace BPrivate::Network;
|
||||||
|
|
||||||
|
|
||||||
|
using namespace BPrivate::Network;
|
||||||
|
|
||||||
|
class Conversation : public BHandler {
|
||||||
|
public:
|
||||||
|
|
||||||
|
Conversation(BHandler* replyTo);
|
||||||
|
virtual ~Conversation() ;
|
||||||
|
virtual void ask(const std::string& prompt);
|
||||||
|
virtual void MessageReceived(BMessage *msg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BHandler* replyTarget;
|
||||||
|
BString ReadOpenAIKey();
|
||||||
|
BString _apiKey;
|
||||||
|
BHttpSession _sharedSession = BHttpSession ();
|
||||||
|
std::optional<BHttpResult> _lastResult;
|
||||||
|
};
|
BIN
DumBer
BIN
DumBer
Binary file not shown.
205
MainWindow.cpp
205
MainWindow.cpp
|
@ -5,9 +5,7 @@
|
||||||
|
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include <Url.h>
|
|
||||||
|
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
#include <Button.h>
|
#include <Button.h>
|
||||||
|
@ -18,23 +16,10 @@
|
||||||
#include <MimeType.h>
|
#include <MimeType.h>
|
||||||
#include <ScrollView.h>
|
#include <ScrollView.h>
|
||||||
#include <StringView.h>
|
#include <StringView.h>
|
||||||
#include <memory.h>
|
|
||||||
|
|
||||||
#include <View.h>
|
#include <View.h>
|
||||||
|
|
||||||
#include <File.h>
|
#include "Conversation.h"
|
||||||
#include <FindDirectory.h>
|
|
||||||
#include <Path.h>
|
|
||||||
#include <String.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
#include "include/json.hpp"
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
using namespace BPrivate::Network;
|
|
||||||
|
|
||||||
#undef B_TRANSLATION_CONTEXT
|
#undef B_TRANSLATION_CONTEXT
|
||||||
#define B_TRANSLATION_CONTEXT "Window"
|
#define B_TRANSLATION_CONTEXT "Window"
|
||||||
|
@ -50,6 +35,13 @@ MainWindow::MainWindow()
|
||||||
: BWindow(BRect(100, 100, 600, 400), B_TRANSLATE("BeDumb"), B_TITLED_WINDOW,
|
: BWindow(BRect(100, 100, 600, 400), B_TRANSLATE("BeDumb"), B_TITLED_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
|
||||||
|
LockLooper();
|
||||||
|
AddHandler(_conversation);
|
||||||
|
UnlockLooper();
|
||||||
|
|
||||||
|
|
||||||
BMenuBar *menuBar = _BuildMenu();
|
BMenuBar *menuBar = _BuildMenu();
|
||||||
|
|
||||||
BLayoutBuilder::Group<>(this, B_VERTICAL, 0).Add(menuBar).AddGlue().End();
|
BLayoutBuilder::Group<>(this, B_VERTICAL, 0).Add(menuBar).AddGlue().End();
|
||||||
|
@ -87,8 +79,6 @@ MainWindow::MainWindow()
|
||||||
float askH = lineHeight * 5;
|
float askH = lineHeight * 5;
|
||||||
_inputField->SetExplicitMinSize(BSize(B_SIZE_UNSET, askH));
|
_inputField->SetExplicitMinSize(BSize(B_SIZE_UNSET, askH));
|
||||||
|
|
||||||
_apiKey = ReadOpenAIKey();
|
|
||||||
printf("key is: %s", _apiKey.String());
|
|
||||||
|
|
||||||
BButton *sendButton =
|
BButton *sendButton =
|
||||||
new BButton("send", B_TRANSLATE("Send"), new BMessage(kSendPrompt),
|
new BButton("send", B_TRANSLATE("Send"), new BMessage(kSendPrompt),
|
||||||
|
@ -130,7 +120,7 @@ MainWindow::~MainWindow() {}
|
||||||
|
|
||||||
void MainWindow::MessageReceived(BMessage *message) {
|
void MainWindow::MessageReceived(BMessage *message) {
|
||||||
|
|
||||||
switch (message->what) {
|
switch (message->what) {
|
||||||
|
|
||||||
// case kMsgNewFile: {
|
// case kMsgNewFile: {
|
||||||
// fSaveMenuItem->SetEnabled(false);
|
// fSaveMenuItem->SetEnabled(false);
|
||||||
|
@ -148,101 +138,38 @@ void MainWindow::MessageReceived(BMessage *message) {
|
||||||
|
|
||||||
case kSendPrompt: {
|
case kSendPrompt: {
|
||||||
|
|
||||||
printf("Button Pressed\n");
|
_progress->SetMaxValue(100);
|
||||||
sendQuery();
|
|
||||||
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case UrlEvent::HostNameResolved: {
|
|
||||||
printf("Host name resolved\n");
|
|
||||||
auto name = message->GetString(UrlEventData::HostName);
|
|
||||||
message->PrintToStream();
|
|
||||||
|
|
||||||
_infoView->SetText("Hostname resolve...");
|
|
||||||
_infoView->SetText(name);
|
|
||||||
_progress->SetTo(5);
|
_progress->SetTo(5);
|
||||||
|
|
||||||
|
printf("Button Pressed\n");
|
||||||
|
_infoView->SetText("Asking...");
|
||||||
|
_conversation->ask(std::string(_inputField->Text()));
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case UrlEvent::ConnectionOpened: {
|
case kSendReply: {
|
||||||
printf("ConnectionOpened\n");
|
printf("Conversation returned!\n");
|
||||||
_progress->SetTo(10);
|
_infoView->SetText("Answer Received");
|
||||||
_infoView->SetText("connection opened...");
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case UrlEvent::ResponseStarted: {
|
|
||||||
printf("ResponseStarted\n");
|
|
||||||
_progress->SetTo(14);
|
|
||||||
_infoView->SetText("ResponseStarted...");
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case UrlEvent::HttpRedirect: {
|
const char* text;
|
||||||
printf("HttpRedirect\n");
|
if (message->FindString("text", &text) == B_OK) {
|
||||||
_progress->SetTo(16);
|
printf("Received text: %s\n", text);
|
||||||
_infoView->SetText("HttpRedirect...");
|
// Do something with text (e.g., set it to a BTextView)
|
||||||
} break;
|
_answerView->SetText(text);
|
||||||
|
} else {
|
||||||
case UrlEvent::RequestCompleted: {
|
printf("No text found in message.\n");
|
||||||
printf("RequestCompleted\n");
|
_answerView->SetText("NO TEXT IN REPLY");
|
||||||
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())
|
|
||||||
{
|
|
||||||
|
|
||||||
json parsed = json::parse(body.text.value().String());
|
|
||||||
|
|
||||||
std::string content = parsed["choices"][0]["message"]["content"];
|
|
||||||
_answerView->SetText(content.c_str());
|
|
||||||
|
|
||||||
// _answerView->SetText(body.text.value());
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_answerView->SetText("nuthin'");
|
|
||||||
}
|
|
||||||
|
|
||||||
_infoView->SetText("Completed");
|
|
||||||
_progress->SetMaxValue(100);
|
_progress->SetMaxValue(100);
|
||||||
_progress->SetTo(100);
|
_progress->SetTo(100);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case UrlEvent::HttpStatus: {
|
|
||||||
|
|
||||||
printf("HttpStatus\n");
|
|
||||||
_infoView->SetText("HttpStatus received");
|
|
||||||
_progress->SetTo(20);
|
|
||||||
|
|
||||||
} break;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
} 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..");
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
// message->PrintToStream();
|
// message->PrintToStream();
|
||||||
BWindow::MessageReceived(
|
BHandler::MessageReceived(
|
||||||
message); // call the parent handler for other messages
|
message); // call the parent handler for other messages
|
||||||
// _infoView->SetText(message->FindMessage());
|
// _infoView->SetText(message->FindMessage());
|
||||||
break;
|
break;
|
||||||
|
@ -252,51 +179,6 @@ void MainWindow::MessageReceived(BMessage *message) {
|
||||||
|
|
||||||
} // end function
|
} // end function
|
||||||
|
|
||||||
void MainWindow::sendQuery() {
|
|
||||||
|
|
||||||
if (_lastResult)
|
|
||||||
_sharedSession.Cancel(_lastResult->Identity());
|
|
||||||
|
|
||||||
_progress->SetMaxValue(100);
|
|
||||||
_progress->SetTo(0);
|
|
||||||
|
|
||||||
auto url = BUrl("https://api.openai.com/v1/chat/completions");
|
|
||||||
BHttpRequest request = BHttpRequest(url);
|
|
||||||
request.SetMethod(BHttpMethod::Post);
|
|
||||||
|
|
||||||
// if the API key file contains a new line bhttpfields will crash with invalid
|
|
||||||
// content .end() requires include algorithm
|
|
||||||
std::string key = _apiKey.String();
|
|
||||||
key.erase(std::remove(key.begin(), key.end(), '\n'), key.end());
|
|
||||||
key.erase(std::remove(key.begin(), key.end(), '\r'), key.end());
|
|
||||||
|
|
||||||
std::string bearer = std::string("Bearer ") + std::string(key);
|
|
||||||
|
|
||||||
BHttpFields fields = BHttpFields();
|
|
||||||
fields.AddField("Authorization", bearer);
|
|
||||||
// fields.AddField("Content-Type", "application/json"); //NO, this will
|
|
||||||
// crash, we set it in request
|
|
||||||
request.SetFields(fields);
|
|
||||||
|
|
||||||
json bodyJson = {
|
|
||||||
{"model", "gpt-3.5-turbo"},
|
|
||||||
{"messages", {{{"role", "user"}, {"content", _inputField->Text()}}}}};
|
|
||||||
|
|
||||||
std::string body = bodyJson.dump();
|
|
||||||
|
|
||||||
BString mime = BString("application/json");
|
|
||||||
// request.SetRequestBody(body.c_str(),mime);
|
|
||||||
|
|
||||||
auto memoryIO = std::make_unique<BMemoryIO>(body.c_str(), body.size());
|
|
||||||
request.SetRequestBody(std::move(memoryIO), "application/json", body.size());
|
|
||||||
|
|
||||||
printf("Sending Prompt to server: %s\n", url.UrlString().String());
|
|
||||||
_lastResult = _sharedSession.Execute(std::move(request), nullptr, this);
|
|
||||||
|
|
||||||
if (_lastResult) {
|
|
||||||
printf("Result has identity: %d\n", _lastResult->Identity());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BMenuBar *MainWindow::_BuildMenu() {
|
BMenuBar *MainWindow::_BuildMenu() {
|
||||||
|
|
||||||
|
@ -336,32 +218,3 @@ BMenuBar *MainWindow::_BuildMenu() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BString MainWindow::ReadOpenAIKey() {
|
|
||||||
|
|
||||||
// /boot/home/config/openai_key
|
|
||||||
// or ~/.config/openai_key on linux
|
|
||||||
|
|
||||||
BPath configPath;
|
|
||||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &configPath) != B_OK)
|
|
||||||
return "error: couldn't find config directory";
|
|
||||||
|
|
||||||
configPath.Append("openai_key");
|
|
||||||
|
|
||||||
BFile file(configPath.Path(), B_READ_ONLY);
|
|
||||||
|
|
||||||
printf("full path:%s\n", configPath.Path());
|
|
||||||
if (file.InitCheck() != B_OK)
|
|
||||||
return "error: couldn't open key file ";
|
|
||||||
|
|
||||||
off_t size;
|
|
||||||
file.GetSize(&size);
|
|
||||||
|
|
||||||
char *buffer = new char[size + 1];
|
|
||||||
file.Read(buffer, size);
|
|
||||||
buffer[size] = '\0'; // null-terminate
|
|
||||||
|
|
||||||
BString result(buffer);
|
|
||||||
delete[] buffer;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
34
MainWindow.h
34
MainWindow.h
|
@ -12,30 +12,9 @@
|
||||||
#include <Window.h>
|
#include <Window.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
|
||||||
|
#include "Conversation.h"
|
||||||
|
|
||||||
|
|
||||||
//NEED THIS IN MAKE FILE TO USE PRIVATE HEADERS
|
|
||||||
//CXXFLAGS = -std=c++17 -Wall -I/boot/system/develop/headers/private
|
|
||||||
|
|
||||||
|
|
||||||
//Build works but Genio doesn't see class definitions unless I use full path ?
|
|
||||||
#include "/boot/system/develop/headers/private/netservices2/NetServicesDefs.h"
|
|
||||||
#include "/boot/system/develop/headers/private/netservices2/HttpSession.h"
|
|
||||||
#include "/boot/system/develop/headers/private/netservices2/HttpRequest.h"
|
|
||||||
#include "/boot/system/develop/headers/private/netservices2/HttpResult.h"
|
|
||||||
#include "/boot/system/develop/headers/private/netservices2/HttpFields.h"
|
|
||||||
#include "/boot/system/develop/headers/private/netservices2/ErrorsExt.h"
|
|
||||||
|
|
||||||
//From private headers !
|
|
||||||
//#include <NetServicesDefs.h>
|
|
||||||
//#include <HttpSession.h>
|
|
||||||
//#include <HttpSession.h>
|
|
||||||
//#include <HttpRequest.h>
|
|
||||||
//#include <HttpResult.h>
|
|
||||||
//#include <ErrorsExt.h>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace BPrivate::Network;
|
|
||||||
|
|
||||||
class MainWindow : public BWindow {
|
class MainWindow : public BWindow {
|
||||||
public:
|
public:
|
||||||
|
@ -44,25 +23,18 @@ public:
|
||||||
|
|
||||||
virtual void MessageReceived(BMessage *msg);
|
virtual void MessageReceived(BMessage *msg);
|
||||||
|
|
||||||
void sendQuery();
|
Conversation* _conversation = new Conversation(this);
|
||||||
BString ReadOpenAIKey();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
BString _apiKey;
|
|
||||||
BHttpSession _sharedSession = BHttpSession ();
|
|
||||||
|
|
||||||
std::optional<BHttpResult> _lastResult;
|
|
||||||
|
|
||||||
BMenuBar *_BuildMenu();
|
BMenuBar *_BuildMenu();
|
||||||
BTextView * _answerView;
|
BTextView * _answerView;
|
||||||
BTextView * _infoView;
|
BTextView * _infoView;
|
||||||
BTextView* _inputField;
|
BTextView* _inputField;
|
||||||
//BTextControl* _inputField;
|
|
||||||
BStatusBar* _progress;
|
BStatusBar* _progress;
|
||||||
|
|
||||||
BMenuItem *fSaveMenuItem;
|
// BMenuItem *fSaveMenuItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
3
Makefile
3
Makefile
|
@ -31,7 +31,8 @@ APP_MIME_SIG = application/x-vnd.SLema-DumBer
|
||||||
# same name (source.c or source.cpp) are included from different directories.
|
# 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.
|
# Also note that spaces in folder names do not work well with this Makefile.
|
||||||
SRCS = App.cpp \
|
SRCS = App.cpp \
|
||||||
MainWindow.cpp
|
MainWindow.cpp \
|
||||||
|
Conversation.cpp
|
||||||
|
|
||||||
# Specify the resource definition files to use. Full or relative paths can be
|
# Specify the resource definition files to use. Full or relative paths can be
|
||||||
# used.
|
# used.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue