mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-25 15:53:11 +03:00
Generate summary and save conversation WIP.
This commit is contained in:
@@ -38,7 +38,8 @@
|
||||
"display_name": "Claude 3.5 Haiku",
|
||||
"max_output_tokens": 8192,
|
||||
"max_tokens": 200000,
|
||||
"name": "claude-3-5-haiku-latest"
|
||||
"name": "claude-3-5-haiku-latest",
|
||||
"cheapest": true
|
||||
},
|
||||
{
|
||||
"cache_configuration": null,
|
||||
@@ -79,7 +80,8 @@
|
||||
"display_name": "DeepSeek Chat",
|
||||
"max_output_tokens": 8192,
|
||||
"max_tokens": 64000,
|
||||
"name": "deepseek-chat"
|
||||
"name": "deepseek-chat",
|
||||
"cheapest": true
|
||||
},
|
||||
{
|
||||
"display_name": "DeepSeek Reasoner",
|
||||
@@ -121,7 +123,8 @@
|
||||
{
|
||||
"display_name": "Gemini 2.0 Flash Lite",
|
||||
"max_tokens": 1000000,
|
||||
"name": "gemini-2.0-flash-lite-preview"
|
||||
"name": "gemini-2.0-flash-lite-preview",
|
||||
"cheapest": true
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -148,7 +151,8 @@
|
||||
{
|
||||
"display_name": "mistral-small-latest",
|
||||
"max_tokens": 32000,
|
||||
"name": "mistral-small-latest"
|
||||
"name": "mistral-small-latest",
|
||||
"cheapest": true
|
||||
},
|
||||
{
|
||||
"display_name": "open-mistral-nemo",
|
||||
@@ -190,7 +194,8 @@
|
||||
},
|
||||
{
|
||||
"max_tokens": 128000,
|
||||
"name": "gpt-4o-mini"
|
||||
"name": "gpt-4o-mini",
|
||||
"cheapest": true
|
||||
},
|
||||
{
|
||||
"max_tokens": 200000,
|
||||
@@ -216,7 +221,8 @@
|
||||
"display_name": "xAI",
|
||||
"models": [
|
||||
{
|
||||
"name": "grok-2-latest"
|
||||
"name": "grok-2-latest",
|
||||
"cheapest": true
|
||||
},
|
||||
{
|
||||
"name": "grok-3-latest"
|
||||
|
||||
@@ -1109,9 +1109,12 @@ Http::Response Http::downloadRequest( const Http::Request& request, IOStream& wr
|
||||
// Close the connection
|
||||
if ( !mConnection->isKeepAlive() ) {
|
||||
mConnection->disconnect();
|
||||
HttpConnection* connection = mConnection;
|
||||
eeSAFE_DELETE( connection );
|
||||
mConnection = NULL;
|
||||
|
||||
if ( mConnection ) {
|
||||
HttpConnection* connection = mConnection;
|
||||
eeSAFE_DELETE( connection );
|
||||
mConnection = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1177,9 +1180,11 @@ void Http::AsyncRequest::run() {
|
||||
}
|
||||
|
||||
// The Async Request destroys the socket used to create the request
|
||||
HttpConnection* connection = mHttp->mConnection;
|
||||
eeSAFE_DELETE( connection );
|
||||
mHttp->mConnection = NULL;
|
||||
if ( mHttp->mConnection ) {
|
||||
HttpConnection* connection = mHttp->mConnection;
|
||||
eeSAFE_DELETE( connection );
|
||||
mHttp->mConnection = NULL;
|
||||
}
|
||||
|
||||
mRunning = false;
|
||||
}
|
||||
|
||||
@@ -57,15 +57,23 @@ static std::map<std::string, LLMProvider> parseLLMProviders( const nlohmann::jso
|
||||
if ( modelJson.contains( "display_name" ) ) {
|
||||
model.displayName = modelJson["display_name"].get<std::string>();
|
||||
}
|
||||
|
||||
if ( modelJson.contains( "max_tokens" ) ) {
|
||||
model.maxTokens = modelJson["max_tokens"].get<std::size_t>();
|
||||
}
|
||||
|
||||
if ( modelJson.contains( "max_output_tokens" ) ) {
|
||||
model.maxOutputTokens = modelJson["max_output_tokens"].get<std::size_t>();
|
||||
}
|
||||
|
||||
if ( modelJson.contains( "default_temperature" ) ) {
|
||||
model.defaultTemperature = modelJson["default_temperature"].get<double>();
|
||||
}
|
||||
|
||||
if ( modelJson.contains( "cheapest" ) ) {
|
||||
model.cheapest = modelJson.value( "cheapest", false );
|
||||
}
|
||||
|
||||
if ( modelJson.contains( "cache_configuration" ) &&
|
||||
!modelJson["cache_configuration"].is_null() ) {
|
||||
const auto& cacheJson = modelJson["cache_configuration"];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "aiassistantplugin.hpp"
|
||||
#include "chatui.hpp"
|
||||
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/ui/doc/syntaxdefinitionmanager.hpp>
|
||||
#include <eepp/ui/uicodeeditor.hpp>
|
||||
#include <eepp/ui/uidropdownlist.hpp>
|
||||
@@ -14,6 +15,7 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using namespace EE::System;
|
||||
using namespace EE::Window;
|
||||
|
||||
namespace ecode {
|
||||
@@ -398,22 +400,36 @@ Uint32 LLMChatUI::onMessage( const NodeMessage* msg ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
nlohmann::json LLMChatUI::serializeChat() {
|
||||
nlohmann::json LLMChatUI::serializeChat( const LLMModel& model ) {
|
||||
nlohmann::json j = {
|
||||
{ "model", mCurModel.name }, { "stream", true }, { "messages", chatToJson() } };
|
||||
if ( mCurModel.maxOutputTokens )
|
||||
j["max_tokens"] = *mCurModel.maxOutputTokens;
|
||||
{ "model", model.name }, { "stream", true }, { "messages", chatToJson() } };
|
||||
if ( model.maxOutputTokens )
|
||||
j["max_tokens"] = *model.maxOutputTokens;
|
||||
return j;
|
||||
}
|
||||
|
||||
nlohmann::json LLMChatUI::serialize() {
|
||||
nlohmann::json j;
|
||||
j["uuid"] = mUUID.toString();
|
||||
j["chat"] = serializeChat();
|
||||
j["chat"] = serializeChat( mCurModel );
|
||||
return j;
|
||||
}
|
||||
|
||||
void unserialize( const nlohmann::json& /*payload*/ ) {}
|
||||
void LLMChatUI::unserialize( const nlohmann::json& /*payload*/ ) {}
|
||||
|
||||
void LLMChatUI::saveChat() {
|
||||
auto plugin = getPlugin();
|
||||
if ( plugin == nullptr )
|
||||
return;
|
||||
|
||||
std::string pluginsStatePath( plugin->getManager()->getPluginsPath() + "plugins_state" +
|
||||
FileSystem::getOSSlash() + "aiassistant" +
|
||||
FileSystem::getOSSlash() );
|
||||
if ( !FileSystem::fileExists( pluginsStatePath ) )
|
||||
FileSystem::makeDir( pluginsStatePath, true );
|
||||
std::string path( pluginsStatePath + mSummary + ".json" );
|
||||
FileSystem::fileWrite( path, serialize().dump( 2 ) );
|
||||
}
|
||||
|
||||
std::string LLMChatUI::prepareApiUrl( const std::string& apiKey ) {
|
||||
const auto& provider = mProviders[mCurModel.provider];
|
||||
@@ -441,9 +457,11 @@ void LLMChatUI::doRequest() {
|
||||
UIWidget* chat = addChatUI( LLMChat::Role::Assistant );
|
||||
toggleEnableChats( false );
|
||||
|
||||
auto model = mCurModel;
|
||||
auto* editor = chat->findByClass<UICodeEditor>( "data_ui" );
|
||||
std::string apiUrl( prepareApiUrl( apiKeyStr ) );
|
||||
mRequest = std::make_unique<LLMChatCompletionRequest>(
|
||||
prepareApiUrl( apiKeyStr ), apiKeyStr, serializeChat().dump(), mCurModel.provider );
|
||||
apiUrl, apiKeyStr, serializeChat( model ).dump(), model.provider );
|
||||
mRequest->streamedResponseCb = [this, editor]( const std::string& chunk ) {
|
||||
auto conversation = chunk;
|
||||
editor->runOnMainThread( [this, conversation = std::move( conversation ), editor] {
|
||||
@@ -452,11 +470,14 @@ void LLMChatUI::doRequest() {
|
||||
resizeToFit( editor );
|
||||
} );
|
||||
};
|
||||
mRequest->doneCb = [this, editor]( const LLMChatCompletionRequest&, Http::Response& response ) {
|
||||
mRequest->doneCb = [this, editor, apiUrl = std::move( apiUrl ),
|
||||
apiKeyStr = std::move( apiKeyStr ), model = std::move( model )](
|
||||
const LLMChatCompletionRequest&, Http::Response& response ) {
|
||||
auto status = response.getStatus();
|
||||
auto statusDesc = response.getStatusDescription();
|
||||
|
||||
runOnMainThread( [this, editor, status, statusDesc] {
|
||||
runOnMainThread( [this, editor, status, statusDesc, apiUrl = std::move( apiUrl ),
|
||||
apiKeyStr = std::move( apiKeyStr ), model = std::move( model )] {
|
||||
if ( status != Http::Response::Ok ) {
|
||||
auto resp = nlohmann::json::parse( mRequest->getStream(), nullptr, false );
|
||||
if ( resp.contains( "error" ) && resp["error"].contains( "message" ) ) {
|
||||
@@ -477,6 +498,38 @@ void LLMChatUI::doRequest() {
|
||||
|
||||
if ( editor->hasFocus() )
|
||||
mChatInput->setFocus();
|
||||
|
||||
if ( !mSummaryRequest && mSummary.empty() && status == Http::Response::Ok ) {
|
||||
static const std::string SummaryPrompt =
|
||||
"Generate a concise 3-7 word title for this conversation, omitting "
|
||||
"punctuation. Go "
|
||||
"straight to the title, without any preamble and prefix like `Here's a concise "
|
||||
"suggestion:...` or `Title:`. Ignore this message for the summary generation.";
|
||||
|
||||
auto jchat = serializeChat( getCheapestModelFromCurrentProvider() );
|
||||
|
||||
jchat["messages"].push_back(
|
||||
{ { "role", LLMChat::roleToString( LLMChat::Role::User ) },
|
||||
{ "content", SummaryPrompt } } );
|
||||
|
||||
auto chatstr = jchat.dump();
|
||||
|
||||
mSummaryRequest = std::make_unique<LLMChatCompletionRequest>(
|
||||
apiUrl, apiKeyStr, chatstr, model.provider );
|
||||
|
||||
mSummaryRequest->doneCb = [this]( const LLMChatCompletionRequest& req,
|
||||
Http::Response& response ) {
|
||||
auto status = response.getStatus();
|
||||
if ( status == Http::Response::Ok ) {
|
||||
mSummary = req.getResponse();
|
||||
saveChat();
|
||||
}
|
||||
runOnMainThread( [this] { mSummaryRequest.reset(); } );
|
||||
};
|
||||
mSummaryRequest->requestAsync();
|
||||
} else {
|
||||
saveChat();
|
||||
}
|
||||
} );
|
||||
};
|
||||
mRequest->requestAsync();
|
||||
@@ -612,4 +665,14 @@ AIAssistantPlugin* LLMChatUI::getPlugin() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const LLMModel& LLMChatUI::getCheapestModelFromCurrentProvider() const {
|
||||
auto providerIt = mProviders.find( mCurModel.provider );
|
||||
if ( providerIt != mProviders.end() ) {
|
||||
for ( const auto& model : providerIt->second.models )
|
||||
if ( model.cheapest )
|
||||
return model;
|
||||
}
|
||||
return mCurModel;
|
||||
}
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -53,6 +53,7 @@ class LLMChatUI : public UILinearLayout {
|
||||
|
||||
protected:
|
||||
UUID mUUID;
|
||||
std::string mSummary;
|
||||
PluginManager* mManager{ nullptr };
|
||||
UIWidget* mChatsList{ nullptr };
|
||||
UICodeEditor* mChatInput{ nullptr };
|
||||
@@ -62,6 +63,7 @@ class LLMChatUI : public UILinearLayout {
|
||||
UIScrollView* mChatScrollView{ nullptr };
|
||||
UIDropDownList* mModelDDL{ nullptr };
|
||||
std::unique_ptr<LLMChatCompletionRequest> mRequest;
|
||||
std::unique_ptr<LLMChatCompletionRequest> mSummaryRequest;
|
||||
LLMProviders mProviders;
|
||||
LLMModel mCurModel;
|
||||
std::unordered_map<String::HashType, LLMModel> mModelsMap;
|
||||
@@ -72,7 +74,7 @@ class LLMChatUI : public UILinearLayout {
|
||||
|
||||
void showMsg( String msg );
|
||||
|
||||
nlohmann::json serializeChat();
|
||||
nlohmann::json serializeChat( const LLMModel& model );
|
||||
|
||||
nlohmann::json chatToJson();
|
||||
|
||||
@@ -101,6 +103,10 @@ class LLMChatUI : public UILinearLayout {
|
||||
void setProviders( LLMProviders&& providers );
|
||||
|
||||
virtual Uint32 onMessage( const NodeMessage* );
|
||||
|
||||
const LLMModel& getCheapestModelFromCurrentProvider() const;
|
||||
|
||||
void saveChat();
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -103,7 +103,7 @@ void LLMChatCompletionRequest::cancel() {
|
||||
mCancel = true;
|
||||
}
|
||||
|
||||
const std::string& LLMChatCompletionRequest::getStream() {
|
||||
const std::string& LLMChatCompletionRequest::getStream() const {
|
||||
return mStream.getStream();
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,9 @@ class LLMChatCompletionRequest {
|
||||
|
||||
void cancel();
|
||||
|
||||
const std::string& getStream();
|
||||
const std::string& getStream() const;
|
||||
|
||||
const std::string& getResponse() const { return mResponse; }
|
||||
|
||||
protected:
|
||||
URI mUrl;
|
||||
|
||||
@@ -22,6 +22,7 @@ struct LLMModel {
|
||||
std::optional<double> defaultTemperature;
|
||||
std::optional<LLMCacheConfiguration> cacheConfiguration;
|
||||
bool isEphemeral{ false };
|
||||
bool cheapest{ false };
|
||||
};
|
||||
|
||||
struct LLMProvider {
|
||||
|
||||
Reference in New Issue
Block a user