mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-01 10:40:20 +03:00
A few optimizations to not affect first-frame time by the models catalog load, now everything runs async.
This commit is contained in:
@@ -210,6 +210,9 @@ AIAssistantPlugin::AIAssistantPlugin( PluginManager* pluginManager, bool sync )
|
||||
AIAssistantPlugin::~AIAssistantPlugin() {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( mModelCatalogMutex );
|
||||
mModelCatalogCancelled->store( true );
|
||||
if ( mModelCatalog )
|
||||
mModelCatalog->cancel();
|
||||
mModelCatalog.reset();
|
||||
}
|
||||
if ( SceneManager::existsSingleton() && !SceneManager::instance()->isShuttingDown() ) {
|
||||
@@ -287,9 +290,6 @@ void AIAssistantPlugin::load( PluginManager* pluginManager ) {
|
||||
userConfig["model_catalog_refresh_hours"].get<std::uint32_t>();
|
||||
}
|
||||
}
|
||||
LLMModelCatalog catalog( catalogSettings );
|
||||
catalog.loadCached( mProviders );
|
||||
|
||||
if ( !mConfigPath.empty() ) {
|
||||
try {
|
||||
loadAIAssistantConfig( mConfigPath, true );
|
||||
@@ -375,7 +375,8 @@ void AIAssistantPlugin::load( PluginManager* pluginManager ) {
|
||||
void AIAssistantPlugin::refreshModelCatalogAsync() {
|
||||
LLMModelCatalog::Settings settings;
|
||||
Node* mainThreadNode;
|
||||
LLMModelCatalog* catalog;
|
||||
std::shared_ptr<LLMModelCatalog> catalog;
|
||||
std::shared_ptr<std::atomic_bool> cancelled;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( mModelCatalogMutex );
|
||||
if ( mModelCatalogRefreshStarted || !mModelCatalogSettings ||
|
||||
@@ -386,23 +387,39 @@ void AIAssistantPlugin::refreshModelCatalogAsync() {
|
||||
if ( !mainThreadNode || !mainThreadNode->getSceneNode() )
|
||||
return;
|
||||
settings = *mModelCatalogSettings;
|
||||
mModelCatalog = std::make_unique<LLMModelCatalog>( settings );
|
||||
catalog = mModelCatalog.get();
|
||||
mModelCatalog = std::make_shared<LLMModelCatalog>( settings );
|
||||
catalog = mModelCatalog;
|
||||
cancelled = mModelCatalogCancelled;
|
||||
mModelCatalogRefreshStarted = true;
|
||||
}
|
||||
auto* manager = mManager;
|
||||
catalog->refreshAsync( mProviders, [manager, mainThreadNode]( LLMProviders providers ) mutable {
|
||||
mainThreadNode->runOnMainThread( [providers = std::move( providers ), manager]() mutable {
|
||||
if ( manager->isClosing() )
|
||||
return;
|
||||
auto* plugin = manager->get( AIAssistantPlugin::Definition().id );
|
||||
if ( plugin )
|
||||
static_cast<AIAssistantPlugin*>( plugin )->applyModelCatalog(
|
||||
std::move( providers ) );
|
||||
else
|
||||
Log::warning(
|
||||
"Could not apply refreshed LLM model catalog: plugin is unavailable" );
|
||||
} );
|
||||
auto applyProviders = [manager, mainThreadNode, cancelled]( LLMProviders providers ) mutable {
|
||||
if ( cancelled->load() )
|
||||
return;
|
||||
mainThreadNode->runOnMainThread(
|
||||
[providers = std::move( providers ), manager, cancelled]() mutable {
|
||||
if ( cancelled->load() || manager->isClosing() )
|
||||
return;
|
||||
auto* plugin = manager->get( AIAssistantPlugin::Definition().id );
|
||||
if ( plugin ) {
|
||||
static_cast<AIAssistantPlugin*>( plugin )->applyModelCatalog(
|
||||
std::move( providers ) );
|
||||
} else {
|
||||
Log::warning(
|
||||
"Could not apply refreshed LLM model catalog: plugin is unavailable" );
|
||||
}
|
||||
} );
|
||||
};
|
||||
LLMProviders providers = mProviders;
|
||||
mThreadPool->run( [catalog = std::move( catalog ), providers = std::move( providers ),
|
||||
applyProviders = std::move( applyProviders ), cancelled]() mutable {
|
||||
if ( cancelled->load() )
|
||||
return;
|
||||
if ( catalog->loadCached( providers ) && !cancelled->load() )
|
||||
applyProviders( LLMProviders( providers ) );
|
||||
if ( cancelled->load() )
|
||||
return;
|
||||
catalog->refreshAsync( std::move( providers ), std::move( applyProviders ) );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,9 @@ class AIAssistantPlugin : public PluginBase {
|
||||
std::string mConfigFileError;
|
||||
std::mutex mModelCatalogMutex;
|
||||
std::optional<LLMModelCatalog::Settings> mModelCatalogSettings;
|
||||
std::unique_ptr<LLMModelCatalog> mModelCatalog;
|
||||
std::shared_ptr<LLMModelCatalog> mModelCatalog;
|
||||
std::shared_ptr<std::atomic_bool> mModelCatalogCancelled{
|
||||
std::make_shared<std::atomic_bool>( false ) };
|
||||
bool mModelCatalogRefreshStarted{ false };
|
||||
|
||||
AIAssistantPlugin( PluginManager* pluginManager, bool sync );
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <eepp/network/http.hpp>
|
||||
#include <eepp/system/clock.hpp>
|
||||
#include <eepp/system/fileinfo.hpp>
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/system/log.hpp>
|
||||
#include <eepp/system/sys.hpp>
|
||||
@@ -32,9 +33,7 @@ static bool supportsTextChat( const json& model ) {
|
||||
}
|
||||
|
||||
static json normalizeCatalog( const json& source ) {
|
||||
json result = { { "version", CATALOG_VERSION },
|
||||
{ "fetched_at", Sys::getUnixTimestamp() },
|
||||
{ "providers", json::object() } };
|
||||
json result = { { "version", CATALOG_VERSION }, { "providers", json::object() } };
|
||||
for ( const auto& [providerId, provider] : source.items() ) {
|
||||
if ( !provider.is_object() || !provider.contains( "models" ) ||
|
||||
!provider["models"].is_object() )
|
||||
@@ -124,6 +123,10 @@ static bool writeAtomically( const std::string& path, const std::string& data )
|
||||
LLMModelCatalog::LLMModelCatalog( Settings settings ) : mSettings( std::move( settings ) ) {}
|
||||
|
||||
LLMModelCatalog::~LLMModelCatalog() {
|
||||
cancel();
|
||||
}
|
||||
|
||||
void LLMModelCatalog::cancel() {
|
||||
mCancelled->store( true );
|
||||
if ( mRequestId && Http::Pool::getGlobal().exists( mRequestURI, mProxyURI ) )
|
||||
Http::Pool::getGlobal().get( mRequestURI, mProxyURI )->setCancelRequest( mRequestId );
|
||||
@@ -161,7 +164,8 @@ LLMModelCatalog::parseReasoningConfiguration( const json& options ) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
bool LLMModelCatalog::applyCatalog( const std::string& data, LLMProviders& providers ) const {
|
||||
bool LLMModelCatalog::applyCatalog( const std::string& data, LLMProviders& providers,
|
||||
std::string* etag ) const {
|
||||
const auto catalog = json::parse( data, nullptr, false, true );
|
||||
if ( !catalog.is_object() || !catalog.contains( "version" ) ||
|
||||
!catalog["version"].is_number_integer() ||
|
||||
@@ -243,15 +247,24 @@ bool LLMModelCatalog::applyCatalog( const std::string& data, LLMProviders& provi
|
||||
catalogProviders.insert_or_assign( providerId, std::move( provider ) );
|
||||
if ( catalogProviders.empty() )
|
||||
return false;
|
||||
if ( etag )
|
||||
*etag = catalog.contains( "etag" ) && catalog["etag"].is_string()
|
||||
? catalog["etag"].get<std::string>()
|
||||
: "";
|
||||
providers = std::move( catalogProviders );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLMModelCatalog::loadCached( LLMProviders& providers ) const {
|
||||
bool LLMModelCatalog::loadCached( LLMProviders& providers ) {
|
||||
if ( !mSettings.enabled )
|
||||
return false;
|
||||
std::string data;
|
||||
return FileSystem::fileGet( mSettings.cachePath, data ) && applyCatalog( data, providers );
|
||||
if ( !FileSystem::fileGet( mSettings.cachePath, data ) ||
|
||||
!applyCatalog( data, providers, &mCachedETag ) )
|
||||
return false;
|
||||
mCachedData = std::move( data );
|
||||
mCachedCatalogValid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
@@ -260,36 +273,23 @@ LLMModelCatalog::refreshAsync( LLMProviders providers,
|
||||
if ( !mSettings.enabled || mSettings.url.empty() )
|
||||
return 0;
|
||||
Clock clock;
|
||||
std::string cached;
|
||||
json cache;
|
||||
if ( FileSystem::fileGet( mSettings.cachePath, cached ) )
|
||||
cache = json::parse( cached, nullptr, false, true );
|
||||
const bool validCache = cache.is_object() && cache.contains( "version" ) &&
|
||||
cache["version"].is_number_integer() &&
|
||||
cache["version"].get<int>() == CATALOG_VERSION;
|
||||
const std::int64_t fetchedAt =
|
||||
validCache && cache.contains( "fetched_at" ) && cache["fetched_at"].is_number_integer()
|
||||
? cache["fetched_at"].get<std::int64_t>()
|
||||
: 0;
|
||||
const std::int64_t maxAge =
|
||||
static_cast<std::int64_t>( mSettings.refreshIntervalHours ) * 60 * 60;
|
||||
if ( fetchedAt > 0 && Sys::getUnixTimestamp() - fetchedAt < maxAge )
|
||||
const FileInfo cacheInfo( mSettings.cachePath );
|
||||
if ( mCachedCatalogValid && cacheInfo.exists() && cacheInfo.getModificationTime() > 0 &&
|
||||
Sys::getUnixTimestamp() - cacheInfo.getModificationTime() < maxAge )
|
||||
return 0;
|
||||
|
||||
Http::Request::FieldTable headers;
|
||||
if ( validCache ) {
|
||||
const std::string etag = cache.contains( "etag" ) && cache["etag"].is_string()
|
||||
? cache["etag"].get<std::string>()
|
||||
: "";
|
||||
if ( !etag.empty() )
|
||||
headers["If-None-Match"] = etag;
|
||||
}
|
||||
if ( !mCachedETag.empty() )
|
||||
headers["If-None-Match"] = mCachedETag;
|
||||
const Settings settings = mSettings;
|
||||
std::string cachedData = std::move( mCachedData );
|
||||
mCancelled->store( false );
|
||||
mRequestURI = URI( mSettings.url );
|
||||
mProxyURI = Http::getEnvProxyURI();
|
||||
mRequestId = Http::getAsync(
|
||||
[settings, cache = std::move( cache ), providers = std::move( providers ),
|
||||
[settings, cachedData = std::move( cachedData ), providers = std::move( providers ),
|
||||
refreshedCallback = std::move( refreshedCallback ), clock,
|
||||
cancelled = mCancelled]( const Http&, Http::Request&, Http::Response& response ) mutable {
|
||||
if ( cancelled->load() )
|
||||
@@ -297,8 +297,8 @@ LLMModelCatalog::refreshAsync( LLMProviders providers,
|
||||
if ( response.getStatus() == Http::Response::Status::NotModified ) {
|
||||
if ( cancelled->load() )
|
||||
return;
|
||||
cache["fetched_at"] = Sys::getUnixTimestamp();
|
||||
writeAtomically( settings.cachePath, cache.dump() );
|
||||
if ( !cachedData.empty() )
|
||||
writeAtomically( settings.cachePath, cachedData );
|
||||
return;
|
||||
}
|
||||
if ( response.getStatus() != Http::Response::Status::Ok ) {
|
||||
|
||||
@@ -23,8 +23,9 @@ class LLMModelCatalog {
|
||||
|
||||
explicit LLMModelCatalog( Settings settings );
|
||||
~LLMModelCatalog();
|
||||
void cancel();
|
||||
|
||||
bool loadCached( LLMProviders& providers ) const;
|
||||
bool loadCached( LLMProviders& providers );
|
||||
|
||||
std::uint64_t refreshAsync( LLMProviders providers,
|
||||
std::function<void( LLMProviders )> refreshedCallback );
|
||||
@@ -38,8 +39,12 @@ class LLMModelCatalog {
|
||||
EE::Network::URI mProxyURI;
|
||||
std::uint64_t mRequestId{ 0 };
|
||||
std::shared_ptr<std::atomic_bool> mCancelled{ std::make_shared<std::atomic_bool>( false ) };
|
||||
std::string mCachedData;
|
||||
std::string mCachedETag;
|
||||
bool mCachedCatalogValid{ false };
|
||||
|
||||
bool applyCatalog( const std::string& data, LLMProviders& providers ) const;
|
||||
bool applyCatalog( const std::string& data, LLMProviders& providers,
|
||||
std::string* etag = nullptr ) const;
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
Reference in New Issue
Block a user