Skip to content

Commit

Permalink
OpenAI Wingman works! (1st usecase ~ summarization) + adding JSon par…
Browse files Browse the repository at this point in the history
…sing library #1514
  • Loading branch information
dvorka committed Jan 14, 2024
1 parent 153496e commit 9ceb557
Show file tree
Hide file tree
Showing 16 changed files with 24,958 additions and 69 deletions.
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Big thanks to 3rd party FOSS content authors:
* GitHub ([CMark GFM](https://github.com/github/cmark-gfm) - Markdown rendering - lib)
* Kevin Hendricks, Bjoern Jacke, Lázsló Németh ([Hunspell](https://github.com/hunspell/hunspell) - spellcheck - lib)
* Daniel Stenberg ([cURL](https://curl.se) - libcurl with GnuTLS flavor)
* Niels Lohmann ([json](https://github.com/nlohmann/json) - JSon for modern C++ library)
* NetBSD Foundation (strptime - Windows port - lib)
* Toni Ronkko (dirent - Windows port - lib)
* Microsoft (getopt - Windows port - lib)
Expand Down
24 changes: 16 additions & 8 deletions Changelog
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
2024-02-?? Martin Dvorak <[email protected]>

* Released v2.0.0 - major release which removes features which are not used
in practices and brings several new features.
* Released v2.0.0 - a major release that removes unused features
and brings several new features like Wingman
* Feature: Wingman brings OpenAI chat GPT integration allowing to
compose, rewrite, summarize, do NER, fix, or chat with remarks.
* Feature: Notebook Tree view brings ability to organize Notebooks to
and outline.
* Feature: Libraries bring ability to index external PDF files and generate
Notebooks which represent them in MindForger. Synchronization and removal
of the library supported as well.
* Feature: New left side toolbar which runs various tools
* Feature: Emojis dialog allowing to use Unicode-based emojis
in Notebook names, Note names or text.
* Hidden feature: New left side toolbar which runs various tools
(like Wikipedia, arXiv, StackOverflow, ...) on phrase which is the current
context (Notebook or Note name, selected text or text under the cursor, ...)
in order to get more information about the phrase.
Expand All @@ -20,17 +24,21 @@
O's Ns while presenting a N.
* Enhancement: MindForger icon changed to GenAI style.
* Enhancement: CLI rewrite towards Wingman with help, search, knowledge recherche and commands.
* Enhancement: menu refactoring impacting Scope, and Navigate and various
menu items.
* Fix: Missing OOTB Eisenhower Matrix is automatically added back to
the list of Organizers.
* Fix: Conflicting menu keyboard shortcuts resolved.
* Fix: Conflicting menu keyboard shortcuts resolution (e.g. Organizers view).
* Deprecation: dashboard view removed.
* Deprecation: experimental Nitie code removed.

2023-01-15 Martin Dvorak <[email protected]>

* Released v1.55.0 - delete of a Note in the outline view keeps selected
an adjacent Note, improved page up/page down navigation in table widgets,
Tools menu, charset added to HTML head, new Note templates, from Registry
to Workspace in UI (source code kept intact).
* Released v1.55.0 - a minor release which fixes delete of a Note in
the Notebook view that now keeps selected an adjacent Note, improves
page up/page down navigation in table widgets, adds charset to
the exported HTML head, adds new Note templates, and renames Repository
to Workspace in the UI (source code kept intact).

2022-03-07 Martin Dvorak <[email protected]>

Expand Down
2 changes: 1 addition & 1 deletion app/app.pro
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ win32 {
else:CONFIG(debug, debug|release): LIBS += -L$$PWD/../lib/debug -lmindforger
} else {
# Linux and macOS
LIBS += -L$$OUT_PWD/../lib -lmindforger
LIBS += -L$$OUT_PWD/../lib -lmindforger -lcurl
}

# Markdown to HTML: cmark-gfm (or nothing)
Expand Down
9 changes: 4 additions & 5 deletions app/src/qt/dialogs/chat_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,16 @@ void ChatDialog::show()

string ChatDialog::getTerminalPrompt(bool error)
{
// TODO
string thing{"notebook"};
string thingName{"My notebook"};
string wingmanModel{"OpenAI gpt-3"};
string thing{"notebook"}; // TODO notebook / note
string thingName{"My notebook"}; // TODO name based on ctx
string wingmanModel{"OpenAI gpt-3"}; // TODO get provider from mind (virtual method @ base class)

string prompt{
"<hr/>"
"<font color='" + COLOR_PROMPT_BLUE + "'>@" + thing + "</font> " +
"<font color='" + COLOR_PROMPT_GREEN + "'><b>" + thingName + "</b></font>"
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
"<font color='" + COLOR_PROMPT_BLUE + "'>" + wingmanModel + "</font>"
"<font color='" + COLOR_PROMPT_BLUE + "'>[" + wingmanModel + "]</font>"
"<br/>"
};

Expand Down
4 changes: 2 additions & 2 deletions app/src/qt/dialogs/wingman_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ WingmanDialog::WingmanDialog(
const vector<string>& predefinedTPrompts,
QWidget* parent
):
context{},
QDialog(parent)
QDialog(parent),
context{}
{
for(string prompt:predefinedOPrompts) {
outlinePrompts.push_back(QString::fromStdString(prompt));
Expand Down
20 changes: 7 additions & 13 deletions app/src/qt/main_menu_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,7 @@ void MainMenuView::showAllMenuItems()
actionOrganizerMovePrevious->setEnabled(true);
actionOrganizerMoveNext->setEnabled(true);

menuNavigator->show();
menuNavigator->setEnabled(true);
actionViewOrganizers->setEnabled(true);
actionOutlineEdit->setEnabled(true);
Expand Down Expand Up @@ -1180,7 +1181,6 @@ void MainMenuView::showModeAwareFacet(bool repositoryMode, bool mfMode)
}
}


void MainMenuView::showFacetOrganizerList(bool repositoryMode, bool mfMode)
{
showAllMenuItems();
Expand All @@ -1193,7 +1193,7 @@ void MainMenuView::showFacetOrganizerList(bool repositoryMode, bool mfMode)
actionOrganizerMovePrevious->setEnabled(false);
actionOrganizerMoveNext->setEnabled(false);

menuNavigator->setEnabled(false);
menuNavigator->setEnabled(false); menuNavigator->setVisible(false);
menuLibrary->setEnabled(false);
menuOutline->setEnabled(false);
menuNote->setEnabled(false);
Expand All @@ -1208,10 +1208,8 @@ void MainMenuView::showFacetOrganizerView(bool repositoryMode, bool mfMode)
{
showAllMenuItems();

menuNavigator->setEnabled(false);
#ifdef MF_WIP
menuNavigator->setEnabled(false); menuNavigator->hide();
menuLibrary->setEnabled(false);
#endif
menuOutline->setEnabled(false);
menuNote->setEnabled(false);
menuEdit->setEnabled(false);
Expand All @@ -1225,7 +1223,7 @@ void MainMenuView::showFacetOutlineList(bool repositoryMode, bool mfMode)
{
showAllMenuItems();

menuNavigator->setEnabled(false);
menuNavigator->setEnabled(false); menuNavigator->hide();
menuOrganizer->setEnabled(false);
menuEdit->setEnabled(false);
menuFormat->setEnabled(false);
Expand All @@ -1250,7 +1248,7 @@ void MainMenuView::showFacetOutlinesMap(bool repositoryMode, bool mfMode)
{
showAllMenuItems();

menuNavigator->setEnabled(false);
menuNavigator->setEnabled(false); menuNavigator->hide();
menuOrganizer->setEnabled(false);
menuEdit->setEnabled(false);
menuFormat->setEnabled(false);
Expand All @@ -1264,10 +1262,8 @@ void MainMenuView::showFacetOutlineView(bool repositoryMode, bool mfMode)
{
showAllMenuItems();

menuNavigator->setEnabled(false);
#ifdef MF_WIP
menuNavigator->setEnabled(false); menuNavigator->hide();
menuLibrary->setEnabled(false);
#endif
menuOrganizer->setEnabled(false);
menuEdit->setEnabled(false);
menuFormat->setEnabled(false);
Expand All @@ -1289,9 +1285,7 @@ void MainMenuView::showFacetNoteEdit(bool repositoryMode, bool mfMode)
menuMind->setEnabled(false);
actionExit->setEnabled(false);

#ifdef MF_WIP
menuLibrary->setEnabled(false);
#endif
menuOrganizer->setEnabled(false);
actionOrganizerNew->setEnabled(false);
actionOrganizerEdit->setEnabled(false);
Expand All @@ -1317,7 +1311,7 @@ void MainMenuView::showFacetNoteEdit(bool repositoryMode, bool mfMode)
actionViewLimbo->setEnabled(false);
actionViewRecentNotes->setEnabled(false);

menuNavigator->setEnabled(false);
menuNavigator->setEnabled(false); menuNavigator->hide();
actionViewOrganizers->setEnabled(false);
actionOutlineEdit->setEnabled(false);
actionOutlineClone->setEnabled(false);
Expand Down
9 changes: 5 additions & 4 deletions lib/src/mind/ai/llm/mock_wingman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ MockWingman::~MockWingman()
{
}

void MockWingman::summarize(const string& text, string& summary)

void MockWingman::chat(const std::string& prompt, std::string& answer)
{
MF_DEBUG("MockWingman::summarize() text:" << text << endl);
MF_DEBUG("MockWingman::summarize() text:" << prompt << endl);

summary = "SUMMARY(MOCK, '"+text+"')";
answer.assign("chat(MOCK, '"+prompt+"')");

MF_DEBUG("MockWingman::summarize() summary:" << summary << endl);
MF_DEBUG("MockWingman::summarize() summary:" << answer << endl);
}

} // m8r namespace
2 changes: 1 addition & 1 deletion lib/src/mind/ai/llm/mock_wingman.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class MockWingman: Wingman
MockWingman& operator =(const MockWingman&&) = delete;
~MockWingman();

virtual void summarize(const std::string& text, std::string& summary) override;
virtual void chat(const std::string& prompt, std::string& answer) override;
};

}
Expand Down
141 changes: 114 additions & 27 deletions lib/src/mind/ai/llm/openai_wingman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
*/
#include "openai_wingman.h"

#include "../../../representations/json/nlohmann/json.hpp"

#include "../../../gear/string_utils.h"

namespace m8r {

using namespace std;
Expand All @@ -26,54 +30,137 @@ using namespace std;
* cURL callback for writing data to string.
*/

static size_t WriteCallback(
void* contents, size_t size, size_t nmemb, void* userp
) {
((std::string*)userp)->append((char*)contents, size * nmemb);

return size * nmemb;
size_t openaiCurlWriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
size_t totalSize = size * nmemb;
output->append((char*)contents, totalSize);
return totalSize;
}

/*
* OpenAi Wingman class implementation.
*/

OpenAiWingman::OpenAiWingman()
: Wingman(WingmanLlmProviders::WINGMAN_PROVIDER_OPENAI)
: Wingman(WingmanLlmProviders::WINGMAN_PROVIDER_OPENAI),
apiKey{}
{
const char* apiKeyEnv = std::getenv("OPENAI_API_KEY");
if (!apiKeyEnv) {
std::cerr << "OpenAI API key not found in the environment variable OPENAI_API_KEY." << std::endl;
// TODO open FE dialog and ask for entering the key
throw std::runtime_error(
"OpenAI API key not found in the environment variable OPENAI_API_KEY.");
}
this->apiKey = string(apiKeyEnv);
}

OpenAiWingman::~OpenAiWingman()
{
}

void OpenAiWingman::curlGet(string& url, string& readBuffer)
{
CURL* curl;
CURLcode res;

curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);

// https://curl.se/libcurl/c/curl_easy_perform.html
res = curl_easy_perform(curl);

/**
* OpenAI cURL GET request.
*
* @see https://platform.openai.com/docs/guides/text-generation/chat-completions-api?lang=curl
*/
void OpenAiWingman::curlGet(
const string& prompt,
string& response
) {
CURL* curl = curl_easy_init();
if (curl) {
// TODO get GPT model from the configuration
string gptModel{"gpt-3.5-turbo"};

string escapedPrompt{prompt};
replaceAll("\n", " ", escapedPrompt);
replaceAll("\"", "\\\"", escapedPrompt);

string promptJSon{
"{"
" \"model\": \"" + gptModel + "\","
" \"messages\": ["
" {"
" \"role\": \"system\","
" \"content\": \"You are a helpful assistant.\""
" },"
// TODO conversation history as additional context
//" {"
//" \"role\": \"user\","
//" \"content\": \"Who won the world series in 2020?\""
//" },"
//" {"
//" \"role\": \"assistant\","
//" \"content\": \"The Los Angeles Dodgers won the World Series in 2020.\""
//" },"
" {"
" \"role\": \"user\","
" \"content\": \"" + escapedPrompt + "\""
" }"
" ]"
"}"
};
MF_DEBUG(
"OpenAiWingman::curlGet() promptJSon:" << endl
<< ">>>"
<< promptJSon
<< "<<<"
<< endl);
// TODO remove
// TODO response = promptJSon;

// set up cURL options
curl_easy_setopt(
curl, CURLOPT_URL,
"https://api.openai.com/v1/chat/completions");
curl_easy_setopt(
curl, CURLOPT_POSTFIELDS,
promptJSon.c_str());
curl_easy_setopt(
curl, CURLOPT_WRITEFUNCTION,
openaiCurlWriteCallback);
curl_easy_setopt(
curl, CURLOPT_WRITEDATA,
&response);

struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, ("Authorization: Bearer " + apiKey).c_str());
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

// perform the request
CURLcode res = curl_easy_perform(curl);

// clean up
curl_easy_cleanup(curl);
MF_DEBUG("Wingman::curlGet() result:" << res << endl);
MF_DEBUG("Wingman::curlGet() response:" << readBuffer << endl);
curl_slist_free_all(headers);

if (res != CURLE_OK) {
std::cerr << "cURL request failed: " << curl_easy_strerror(res) << std::endl;
response.clear();
}
// TODO report error code to show RED in chat

// parse JSon
// TODO import to json namespace
// TODO auto responseJSon = nlohmann::json::parse(R"({"happy": true, "pi": 3.141})");
auto responseJSon = nlohmann::json::parse(response);
MF_DEBUG(
"OpenAiWingman::curlGet() responseJSon:" << endl
<< ">>>"
<< responseJSon.dump(4)
<< "<<<"
<< endl);
}
}

void OpenAiWingman::summarize(const string& text, string& summary)
void OpenAiWingman::chat(const std::string& prompt, std::string& answer)
{
MF_DEBUG("OpenAiWingman::summarize() text:" << text << endl);
MF_DEBUG("OpenAiWingman::summarize() prompt:" << endl << prompt << endl);

summary = "SUMMARY(OpenAI, '"+text+"')";
curlGet(prompt, answer);

MF_DEBUG("OpenAiWingman::summarize() summary:" << summary << endl);
MF_DEBUG("OpenAiWingman::summarize() summary:" << endl << answer << endl);
}

} // m8r namespace
Loading

0 comments on commit 9ceb557

Please sign in to comment.