2023-06-22 19:44:49 +00:00
# include "modellist.h"
2023-06-28 20:05:35 +00:00
# include "mysettings.h"
2023-07-01 15:34:21 +00:00
# include "network.h"
2024-01-31 19:17:44 +00:00
# include "../gpt4all-backend/llmodel.h"
2023-06-22 19:44:49 +00:00
2023-07-10 20:14:57 +00:00
# include <QFile>
# include <QStandardPaths>
2023-06-22 19:44:49 +00:00
# include <algorithm>
2024-03-06 19:12:21 +00:00
# include <compare>
2023-06-22 19:44:49 +00:00
2023-06-28 15:13:33 +00:00
//#define USE_LOCAL_MODELSJSON
2023-11-15 17:23:45 +00:00
# define DEFAULT_EMBEDDING_MODEL "all-MiniLM-L6-v2-f16.gguf"
2024-01-22 17:36:01 +00:00
# define NOMIC_EMBEDDING_MODEL "nomic-embed-text-v1.txt"
2023-11-15 17:23:45 +00:00
2023-07-01 15:34:21 +00:00
QString ModelInfo : : id ( ) const
{
return m_id ;
}
void ModelInfo : : setId ( const QString & id )
{
m_id = id ;
}
QString ModelInfo : : name ( ) const
{
return MySettings : : globalInstance ( ) - > modelName ( * this ) ;
}
void ModelInfo : : setName ( const QString & name )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelName ( * this , name , true /*force*/ ) ;
2023-07-01 15:34:21 +00:00
m_name = name ;
}
QString ModelInfo : : filename ( ) const
{
return MySettings : : globalInstance ( ) - > modelFilename ( * this ) ;
}
void ModelInfo : : setFilename ( const QString & filename )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelFilename ( * this , filename , true /*force*/ ) ;
2023-07-01 15:34:21 +00:00
m_filename = filename ;
}
2024-03-05 16:31:31 +00:00
QString ModelInfo : : description ( ) const
{
return MySettings : : globalInstance ( ) - > modelDescription ( * this ) ;
}
void ModelInfo : : setDescription ( const QString & d )
{
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelDescription ( * this , d , true /*force*/ ) ;
m_description = d ;
}
QString ModelInfo : : url ( ) const
{
return MySettings : : globalInstance ( ) - > modelUrl ( * this ) ;
}
void ModelInfo : : setUrl ( const QString & u )
{
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelUrl ( * this , u , true /*force*/ ) ;
m_url = u ;
}
QString ModelInfo : : quant ( ) const
{
return MySettings : : globalInstance ( ) - > modelQuant ( * this ) ;
}
void ModelInfo : : setQuant ( const QString & q )
{
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelQuant ( * this , q , true /*force*/ ) ;
m_quant = q ;
}
QString ModelInfo : : type ( ) const
{
return MySettings : : globalInstance ( ) - > modelType ( * this ) ;
}
void ModelInfo : : setType ( const QString & t )
{
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelType ( * this , t , true /*force*/ ) ;
m_type = t ;
}
bool ModelInfo : : isClone ( ) const
{
return MySettings : : globalInstance ( ) - > modelIsClone ( * this ) ;
}
void ModelInfo : : setIsClone ( bool b )
{
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelIsClone ( * this , b , true /*force*/ ) ;
m_isClone = b ;
}
bool ModelInfo : : isDiscovered ( ) const
{
return MySettings : : globalInstance ( ) - > modelIsDiscovered ( * this ) ;
}
void ModelInfo : : setIsDiscovered ( bool b )
{
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelIsDiscovered ( * this , b , true /*force*/ ) ;
m_isDiscovered = b ;
}
int ModelInfo : : likes ( ) const
{
return MySettings : : globalInstance ( ) - > modelLikes ( * this ) ;
}
void ModelInfo : : setLikes ( int l )
{
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelLikes ( * this , l , true /*force*/ ) ;
m_likes = l ;
}
int ModelInfo : : downloads ( ) const
{
return MySettings : : globalInstance ( ) - > modelDownloads ( * this ) ;
}
void ModelInfo : : setDownloads ( int d )
{
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelDownloads ( * this , d , true /*force*/ ) ;
m_downloads = d ;
}
QDateTime ModelInfo : : recency ( ) const
{
return MySettings : : globalInstance ( ) - > modelRecency ( * this ) ;
}
void ModelInfo : : setRecency ( const QDateTime & r )
{
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelRecency ( * this , r , true /*force*/ ) ;
m_recency = r ;
}
2023-07-01 15:34:21 +00:00
double ModelInfo : : temperature ( ) const
{
return MySettings : : globalInstance ( ) - > modelTemperature ( * this ) ;
}
void ModelInfo : : setTemperature ( double t )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelTemperature ( * this , t , true /*force*/ ) ;
2023-07-01 15:34:21 +00:00
m_temperature = t ;
}
double ModelInfo : : topP ( ) const
{
return MySettings : : globalInstance ( ) - > modelTopP ( * this ) ;
}
2024-02-24 22:51:34 +00:00
double ModelInfo : : minP ( ) const
{
return MySettings : : globalInstance ( ) - > modelMinP ( * this ) ;
}
2023-07-01 15:34:21 +00:00
void ModelInfo : : setTopP ( double p )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelTopP ( * this , p , true /*force*/ ) ;
2023-07-01 15:34:21 +00:00
m_topP = p ;
}
2024-02-24 22:51:34 +00:00
void ModelInfo : : setMinP ( double p )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelMinP ( * this , p , true /*force*/ ) ;
2024-02-24 22:51:34 +00:00
m_minP = p ;
}
2023-07-01 15:34:21 +00:00
int ModelInfo : : topK ( ) const
{
return MySettings : : globalInstance ( ) - > modelTopK ( * this ) ;
}
void ModelInfo : : setTopK ( int k )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelTopK ( * this , k , true /*force*/ ) ;
2023-07-01 15:34:21 +00:00
m_topK = k ;
}
int ModelInfo : : maxLength ( ) const
{
return MySettings : : globalInstance ( ) - > modelMaxLength ( * this ) ;
}
void ModelInfo : : setMaxLength ( int l )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelMaxLength ( * this , l , true /*force*/ ) ;
2023-07-01 15:34:21 +00:00
m_maxLength = l ;
}
int ModelInfo : : promptBatchSize ( ) const
{
return MySettings : : globalInstance ( ) - > modelPromptBatchSize ( * this ) ;
}
void ModelInfo : : setPromptBatchSize ( int s )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelPromptBatchSize ( * this , s , true /*force*/ ) ;
2023-07-01 15:34:21 +00:00
m_promptBatchSize = s ;
}
2023-12-16 22:58:15 +00:00
int ModelInfo : : contextLength ( ) const
{
return MySettings : : globalInstance ( ) - > modelContextLength ( * this ) ;
}
void ModelInfo : : setContextLength ( int l )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelContextLength ( * this , l , true /*force*/ ) ;
2023-12-16 22:58:15 +00:00
m_contextLength = l ;
}
2024-01-31 19:17:44 +00:00
int ModelInfo : : maxContextLength ( ) const
{
if ( m_maxContextLength ! = - 1 ) return m_maxContextLength ;
auto path = ( dirpath + filename ( ) ) . toStdString ( ) ;
int layers = LLModel : : Implementation : : maxContextLength ( path ) ;
if ( layers < 0 ) {
layers = 4096 ; // fallback value
}
m_maxContextLength = layers ;
return m_maxContextLength ;
}
int ModelInfo : : gpuLayers ( ) const
{
return MySettings : : globalInstance ( ) - > modelGpuLayers ( * this ) ;
}
void ModelInfo : : setGpuLayers ( int l )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelGpuLayers ( * this , l , true /*force*/ ) ;
2024-01-31 19:17:44 +00:00
m_gpuLayers = l ;
}
int ModelInfo : : maxGpuLayers ( ) const
{
2024-02-26 16:11:38 +00:00
if ( ! installed | | isOnline ) return - 1 ;
2024-01-31 19:17:44 +00:00
if ( m_maxGpuLayers ! = - 1 ) return m_maxGpuLayers ;
auto path = ( dirpath + filename ( ) ) . toStdString ( ) ;
int layers = LLModel : : Implementation : : layerCount ( path ) ;
if ( layers < 0 ) {
layers = 100 ; // fallback value
}
m_maxGpuLayers = layers ;
return m_maxGpuLayers ;
}
2023-07-01 15:34:21 +00:00
double ModelInfo : : repeatPenalty ( ) const
{
return MySettings : : globalInstance ( ) - > modelRepeatPenalty ( * this ) ;
}
void ModelInfo : : setRepeatPenalty ( double p )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelRepeatPenalty ( * this , p , true /*force*/ ) ;
2023-07-01 15:34:21 +00:00
m_repeatPenalty = p ;
}
int ModelInfo : : repeatPenaltyTokens ( ) const
{
return MySettings : : globalInstance ( ) - > modelRepeatPenaltyTokens ( * this ) ;
}
void ModelInfo : : setRepeatPenaltyTokens ( int t )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelRepeatPenaltyTokens ( * this , t , true /*force*/ ) ;
2023-07-01 15:34:21 +00:00
m_repeatPenaltyTokens = t ;
}
QString ModelInfo : : promptTemplate ( ) const
{
return MySettings : : globalInstance ( ) - > modelPromptTemplate ( * this ) ;
}
void ModelInfo : : setPromptTemplate ( const QString & t )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelPromptTemplate ( * this , t , true /*force*/ ) ;
2023-07-01 15:34:21 +00:00
m_promptTemplate = t ;
}
QString ModelInfo : : systemPrompt ( ) const
{
return MySettings : : globalInstance ( ) - > modelSystemPrompt ( * this ) ;
}
void ModelInfo : : setSystemPrompt ( const QString & p )
{
2024-03-05 16:31:31 +00:00
if ( shouldSaveMetadata ( ) ) MySettings : : globalInstance ( ) - > setModelSystemPrompt ( * this , p , true /*force*/ ) ;
2023-07-01 15:34:21 +00:00
m_systemPrompt = p ;
}
2024-03-05 16:31:31 +00:00
bool ModelInfo : : shouldSaveMetadata ( ) const
{
return installed & & ( isClone ( ) | | isDiscovered ( ) | | description ( ) = = " " /*indicates sideloaded*/ ) ;
}
2023-10-24 16:13:32 +00:00
EmbeddingModels : : EmbeddingModels ( QObject * parent )
: QSortFilterProxyModel ( parent )
{
connect ( this , & EmbeddingModels : : rowsInserted , this , & EmbeddingModels : : countChanged ) ;
connect ( this , & EmbeddingModels : : rowsRemoved , this , & EmbeddingModels : : countChanged ) ;
connect ( this , & EmbeddingModels : : modelReset , this , & EmbeddingModels : : countChanged ) ;
connect ( this , & EmbeddingModels : : layoutChanged , this , & EmbeddingModels : : countChanged ) ;
}
bool EmbeddingModels : : filterAcceptsRow ( int sourceRow ,
const QModelIndex & sourceParent ) const
{
QModelIndex index = sourceModel ( ) - > index ( sourceRow , 0 , sourceParent ) ;
bool isInstalled = sourceModel ( ) - > data ( index , ModelList : : InstalledRole ) . toBool ( ) ;
2024-01-22 17:36:01 +00:00
bool isEmbedding = sourceModel ( ) - > data ( index , ModelList : : FilenameRole ) . toString ( ) = = DEFAULT_EMBEDDING_MODEL | |
sourceModel ( ) - > data ( index , ModelList : : FilenameRole ) . toString ( ) = = NOMIC_EMBEDDING_MODEL ;
2023-10-24 16:13:32 +00:00
return isInstalled & & isEmbedding ;
}
int EmbeddingModels : : count ( ) const
{
return rowCount ( ) ;
}
ModelInfo EmbeddingModels : : defaultModelInfo ( ) const
{
if ( ! sourceModel ( ) )
return ModelInfo ( ) ;
const ModelList * sourceListModel = qobject_cast < const ModelList * > ( sourceModel ( ) ) ;
if ( ! sourceListModel )
return ModelInfo ( ) ;
const int rows = sourceListModel - > rowCount ( ) ;
for ( int i = 0 ; i < rows ; + + i ) {
QModelIndex sourceIndex = sourceListModel - > index ( i , 0 ) ;
if ( filterAcceptsRow ( i , sourceIndex . parent ( ) ) ) {
const QString id = sourceListModel - > data ( sourceIndex , ModelList : : IdRole ) . toString ( ) ;
return sourceListModel - > modelInfo ( id ) ;
}
}
return ModelInfo ( ) ;
}
2023-06-26 13:35:29 +00:00
InstalledModels : : InstalledModels ( QObject * parent )
: QSortFilterProxyModel ( parent )
{
connect ( this , & InstalledModels : : rowsInserted , this , & InstalledModels : : countChanged ) ;
connect ( this , & InstalledModels : : rowsRemoved , this , & InstalledModels : : countChanged ) ;
connect ( this , & InstalledModels : : modelReset , this , & InstalledModels : : countChanged ) ;
connect ( this , & InstalledModels : : layoutChanged , this , & InstalledModels : : countChanged ) ;
}
2023-06-22 19:44:49 +00:00
bool InstalledModels : : filterAcceptsRow ( int sourceRow ,
const QModelIndex & sourceParent ) const
{
QModelIndex index = sourceModel ( ) - > index ( sourceRow , 0 , sourceParent ) ;
bool isInstalled = sourceModel ( ) - > data ( index , ModelList : : InstalledRole ) . toBool ( ) ;
2023-10-24 16:13:32 +00:00
bool showInGUI = ! sourceModel ( ) - > data ( index , ModelList : : DisableGUIRole ) . toBool ( ) ;
return isInstalled & & showInGUI ;
2023-06-22 19:44:49 +00:00
}
2023-06-26 13:35:29 +00:00
int InstalledModels : : count ( ) const
{
return rowCount ( ) ;
}
2023-06-22 19:44:49 +00:00
DownloadableModels : : DownloadableModels ( QObject * parent )
: QSortFilterProxyModel ( parent )
, m_expanded ( false )
, m_limit ( 5 )
{
connect ( this , & DownloadableModels : : rowsInserted , this , & DownloadableModels : : countChanged ) ;
connect ( this , & DownloadableModels : : rowsRemoved , this , & DownloadableModels : : countChanged ) ;
connect ( this , & DownloadableModels : : modelReset , this , & DownloadableModels : : countChanged ) ;
connect ( this , & DownloadableModels : : layoutChanged , this , & DownloadableModels : : countChanged ) ;
}
bool DownloadableModels : : filterAcceptsRow ( int sourceRow ,
const QModelIndex & sourceParent ) const
{
bool withinLimit = sourceRow < ( m_expanded ? sourceModel ( ) - > rowCount ( ) : m_limit ) ;
QModelIndex index = sourceModel ( ) - > index ( sourceRow , 0 , sourceParent ) ;
bool isDownloadable = ! sourceModel ( ) - > data ( index , ModelList : : DescriptionRole ) . toString ( ) . isEmpty ( ) ;
2024-03-05 16:31:31 +00:00
bool isInstalled = ! sourceModel ( ) - > data ( index , ModelList : : InstalledRole ) . toString ( ) . isEmpty ( ) ;
bool isIncomplete = ! sourceModel ( ) - > data ( index , ModelList : : IncompleteRole ) . toString ( ) . isEmpty ( ) ;
return withinLimit & & ( isDownloadable | | isInstalled | | isIncomplete ) ;
2023-06-22 19:44:49 +00:00
}
int DownloadableModels : : count ( ) const
{
return rowCount ( ) ;
}
bool DownloadableModels : : isExpanded ( ) const
{
return m_expanded ;
}
void DownloadableModels : : setExpanded ( bool expanded )
{
if ( m_expanded ! = expanded ) {
m_expanded = expanded ;
invalidateFilter ( ) ;
emit expandedChanged ( m_expanded ) ;
}
}
2024-03-05 16:31:31 +00:00
void DownloadableModels : : discoverAndFilter ( const QString & discover )
{
m_discoverFilter = discover ;
ModelList * ml = qobject_cast < ModelList * > ( parent ( ) ) ;
ml - > discoverSearch ( discover ) ;
}
2023-06-22 19:44:49 +00:00
class MyModelList : public ModelList { } ;
Q_GLOBAL_STATIC ( MyModelList , modelListInstance )
ModelList * ModelList : : globalInstance ( )
{
return modelListInstance ( ) ;
}
ModelList : : ModelList ( )
: QAbstractListModel ( nullptr )
2023-10-24 16:13:32 +00:00
, m_embeddingModels ( new EmbeddingModels ( this ) )
2023-06-22 19:44:49 +00:00
, m_installedModels ( new InstalledModels ( this ) )
, m_downloadableModels ( new DownloadableModels ( this ) )
2023-07-12 15:46:40 +00:00
, m_asyncModelRequestOngoing ( false )
2024-03-05 16:31:31 +00:00
, m_discoverLimit ( 20 )
, m_discoverSortDirection ( - 1 )
, m_discoverSort ( Likes )
, m_discoverNumberOfResults ( 0 )
, m_discoverResultsCompleted ( 0 )
, m_discoverInProgress ( false )
2023-06-22 19:44:49 +00:00
{
2023-10-24 16:13:32 +00:00
m_embeddingModels - > setSourceModel ( this ) ;
2023-06-22 19:44:49 +00:00
m_installedModels - > setSourceModel ( this ) ;
m_downloadableModels - > setSourceModel ( this ) ;
2023-11-17 18:27:17 +00:00
2023-07-01 15:34:21 +00:00
connect ( MySettings : : globalInstance ( ) , & MySettings : : modelPathChanged , this , & ModelList : : updateModelsFromDirectory ) ;
connect ( MySettings : : globalInstance ( ) , & MySettings : : modelPathChanged , this , & ModelList : : updateModelsFromJson ) ;
connect ( MySettings : : globalInstance ( ) , & MySettings : : modelPathChanged , this , & ModelList : : updateModelsFromSettings ) ;
connect ( MySettings : : globalInstance ( ) , & MySettings : : nameChanged , this , & ModelList : : updateDataForSettings ) ;
connect ( MySettings : : globalInstance ( ) , & MySettings : : temperatureChanged , this , & ModelList : : updateDataForSettings ) ;
connect ( MySettings : : globalInstance ( ) , & MySettings : : topPChanged , this , & ModelList : : updateDataForSettings ) ;
2024-02-24 22:51:34 +00:00
connect ( MySettings : : globalInstance ( ) , & MySettings : : minPChanged , this , & ModelList : : updateDataForSettings ) ;
2023-07-01 15:34:21 +00:00
connect ( MySettings : : globalInstance ( ) , & MySettings : : topKChanged , this , & ModelList : : updateDataForSettings ) ;
connect ( MySettings : : globalInstance ( ) , & MySettings : : maxLengthChanged , this , & ModelList : : updateDataForSettings ) ;
connect ( MySettings : : globalInstance ( ) , & MySettings : : promptBatchSizeChanged , this , & ModelList : : updateDataForSettings ) ;
2023-12-16 22:58:15 +00:00
connect ( MySettings : : globalInstance ( ) , & MySettings : : contextLengthChanged , this , & ModelList : : updateDataForSettings ) ;
2024-01-31 19:17:44 +00:00
connect ( MySettings : : globalInstance ( ) , & MySettings : : gpuLayersChanged , this , & ModelList : : updateDataForSettings ) ;
2023-07-01 15:34:21 +00:00
connect ( MySettings : : globalInstance ( ) , & MySettings : : repeatPenaltyChanged , this , & ModelList : : updateDataForSettings ) ;
connect ( MySettings : : globalInstance ( ) , & MySettings : : repeatPenaltyTokensChanged , this , & ModelList : : updateDataForSettings ) ; ;
connect ( MySettings : : globalInstance ( ) , & MySettings : : promptTemplateChanged , this , & ModelList : : updateDataForSettings ) ;
connect ( MySettings : : globalInstance ( ) , & MySettings : : systemPromptChanged , this , & ModelList : : updateDataForSettings ) ;
2023-07-10 20:14:57 +00:00
connect ( & m_networkManager , & QNetworkAccessManager : : sslErrors , this , & ModelList : : handleSslErrors ) ;
2023-07-01 15:34:21 +00:00
updateModelsFromJson ( ) ;
updateModelsFromSettings ( ) ;
2023-06-22 19:44:49 +00:00
updateModelsFromDirectory ( ) ;
}
QString ModelList : : incompleteDownloadPath ( const QString & modelFile )
{
2023-06-28 20:05:35 +00:00
return MySettings : : globalInstance ( ) - > modelPath ( ) + " incomplete- " + modelFile ;
2023-06-22 19:44:49 +00:00
}
const QList < ModelInfo > ModelList : : exportModelList ( ) const
{
QMutexLocker locker ( & m_mutex ) ;
QList < ModelInfo > infos ;
for ( ModelInfo * info : m_models )
if ( info - > installed )
infos . append ( * info ) ;
return infos ;
}
const QList < QString > ModelList : : userDefaultModelList ( ) const
{
QMutexLocker locker ( & m_mutex ) ;
2023-06-29 00:42:40 +00:00
const QString userDefaultModelName = MySettings : : globalInstance ( ) - > userDefaultModel ( ) ;
2023-06-22 19:44:49 +00:00
QList < QString > models ;
bool foundUserDefault = false ;
for ( ModelInfo * info : m_models ) {
2023-07-01 15:34:21 +00:00
if ( info - > installed & & info - > id ( ) = = userDefaultModelName ) {
2023-06-22 19:44:49 +00:00
foundUserDefault = true ;
2023-07-01 15:34:21 +00:00
models . prepend ( info - > name ( ) ) ;
2023-06-22 19:44:49 +00:00
} else if ( info - > installed ) {
2023-07-01 15:34:21 +00:00
models . append ( info - > name ( ) ) ;
2023-06-22 19:44:49 +00:00
}
}
2023-07-01 15:34:21 +00:00
const QString defaultId = " Application default " ;
2023-06-22 19:44:49 +00:00
if ( foundUserDefault )
2023-07-01 15:34:21 +00:00
models . append ( defaultId ) ;
2023-06-22 19:44:49 +00:00
else
2023-07-01 15:34:21 +00:00
models . prepend ( defaultId ) ;
2023-06-22 19:44:49 +00:00
return models ;
}
2023-10-24 16:13:32 +00:00
int ModelList : : defaultEmbeddingModelIndex ( ) const
{
QMutexLocker locker ( & m_mutex ) ;
for ( int i = 0 ; i < m_models . size ( ) ; + + i ) {
const ModelInfo * info = m_models . at ( i ) ;
2023-11-15 17:23:45 +00:00
const bool isEmbedding = info - > filename ( ) = = DEFAULT_EMBEDDING_MODEL ;
2023-10-24 16:13:32 +00:00
if ( isEmbedding ) return i ;
}
return - 1 ;
}
2023-06-22 19:44:49 +00:00
ModelInfo ModelList : : defaultModelInfo ( ) const
{
QMutexLocker locker ( & m_mutex ) ;
QSettings settings ;
settings . sync ( ) ;
// The user default model can be set by the user in the settings dialog. The "default" user
2023-07-12 16:45:08 +00:00
// default model is "Application default" which signals we should use the logic here.
2023-06-29 00:42:40 +00:00
const QString userDefaultModelName = MySettings : : globalInstance ( ) - > userDefaultModel ( ) ;
2023-06-26 21:50:11 +00:00
const bool hasUserDefaultName = ! userDefaultModelName . isEmpty ( ) & & userDefaultModelName ! = " Application default " ;
2023-06-22 19:44:49 +00:00
ModelInfo * defaultModel = nullptr ;
for ( ModelInfo * info : m_models ) {
if ( ! info - > installed )
continue ;
defaultModel = info ;
2023-06-26 21:50:11 +00:00
2023-07-12 16:45:08 +00:00
const size_t ramrequired = defaultModel - > ramrequired ;
2023-06-26 21:50:11 +00:00
2023-07-12 16:45:08 +00:00
// If we don't have either setting, then just use the first model that requires less than 16GB that is installed
2024-01-22 17:36:01 +00:00
if ( ! hasUserDefaultName & & ! info - > isOnline & & ramrequired > 0 & & ramrequired < 16 )
2023-06-26 21:50:11 +00:00
break ;
// If we have a user specified default and match, then use it
2023-07-01 15:34:21 +00:00
if ( hasUserDefaultName & & ( defaultModel - > id ( ) = = userDefaultModelName ) )
2023-06-26 21:50:11 +00:00
break ;
2023-06-22 19:44:49 +00:00
}
if ( defaultModel )
return * defaultModel ;
return ModelInfo ( ) ;
}
2023-07-01 15:34:21 +00:00
bool ModelList : : contains ( const QString & id ) const
{
QMutexLocker locker ( & m_mutex ) ;
return m_modelMap . contains ( id ) ;
}
bool ModelList : : containsByFilename ( const QString & filename ) const
2023-06-22 19:44:49 +00:00
{
QMutexLocker locker ( & m_mutex ) ;
2023-07-01 15:34:21 +00:00
for ( ModelInfo * info : m_models )
if ( info - > filename ( ) = = filename )
return true ;
return false ;
2023-06-22 19:44:49 +00:00
}
2024-03-05 16:31:31 +00:00
bool ModelList : : lessThan ( const ModelInfo * a , const ModelInfo * b , DiscoverSort s , int d )
2023-06-22 19:44:49 +00:00
{
2024-03-05 16:31:31 +00:00
// Rule -1a: Discover sort
if ( a - > isDiscovered ( ) & & b - > isDiscovered ( ) ) {
switch ( s ) {
case Default : break ;
case Likes : return ( d > 0 ? a - > likes ( ) < b - > likes ( ) : a - > likes ( ) > b - > likes ( ) ) ;
case Downloads : return ( d > 0 ? a - > downloads ( ) < b - > downloads ( ) : a - > downloads ( ) > b - > downloads ( ) ) ;
case Recent : return ( d > 0 ? a - > recency ( ) < b - > recency ( ) : a - > recency ( ) > b - > recency ( ) ) ;
}
}
// Rule -1: Discovered before non-discovered
if ( a - > isDiscovered ( ) ! = b - > isDiscovered ( ) ) {
return a - > isDiscovered ( ) ;
}
2023-07-01 15:34:21 +00:00
// Rule 0: Non-clone before clone
2024-03-05 16:31:31 +00:00
if ( a - > isClone ( ) ! = b - > isClone ( ) ) {
return ! a - > isClone ( ) ;
2023-07-01 15:34:21 +00:00
}
2023-06-22 19:44:49 +00:00
// Rule 1: Non-empty 'order' before empty
if ( a - > order . isEmpty ( ) ! = b - > order . isEmpty ( ) ) {
return ! a - > order . isEmpty ( ) ;
}
// Rule 2: Both 'order' are non-empty, sort alphanumerically
if ( ! a - > order . isEmpty ( ) & & ! b - > order . isEmpty ( ) ) {
return a - > order < b - > order ;
}
2023-07-01 15:34:21 +00:00
// Rule 3: Both 'order' are empty, sort by id
return a - > id ( ) < b - > id ( ) ;
2023-06-22 19:44:49 +00:00
}
2023-07-01 15:34:21 +00:00
void ModelList : : addModel ( const QString & id )
2023-06-22 19:44:49 +00:00
{
2023-07-01 15:34:21 +00:00
const bool hasModel = contains ( id ) ;
2023-06-26 00:22:38 +00:00
Q_ASSERT ( ! hasModel ) ;
if ( hasModel ) {
2023-07-01 15:34:21 +00:00
qWarning ( ) < < " ERROR: model list already contains " < < id ;
2023-06-22 19:44:49 +00:00
return ;
}
2024-03-05 16:31:31 +00:00
ModelInfo * info = new ModelInfo ;
info - > setId ( id ) ;
m_mutex . lock ( ) ;
auto s = m_discoverSort ;
auto d = m_discoverSortDirection ;
const auto insertPosition = std : : lower_bound ( m_models . begin ( ) , m_models . end ( ) , info ,
[ s , d ] ( const ModelInfo * lhs , const ModelInfo * rhs ) {
return ModelList : : lessThan ( lhs , rhs , s , d ) ;
} ) ;
const int index = std : : distance ( m_models . begin ( ) , insertPosition ) ;
m_mutex . unlock ( ) ;
// NOTE: The begin/end rows cannot have a lock placed around them. We calculate the index ahead
// of time and this works because this class is designed carefully so that only one thread is
// responsible for insertion, deletion, and update
beginInsertRows ( QModelIndex ( ) , index , index ) ;
m_mutex . lock ( ) ;
m_models . insert ( insertPosition , info ) ;
m_modelMap . insert ( id , info ) ;
m_mutex . unlock ( ) ;
2023-06-22 19:44:49 +00:00
endInsertRows ( ) ;
2024-03-05 16:31:31 +00:00
2023-06-22 19:44:49 +00:00
emit userDefaultModelListChanged ( ) ;
}
2023-07-10 20:14:57 +00:00
void ModelList : : changeId ( const QString & oldId , const QString & newId )
{
const bool hasModel = contains ( oldId ) ;
Q_ASSERT ( hasModel ) ;
if ( ! hasModel ) {
qWarning ( ) < < " ERROR: model list does not contain " < < oldId ;
return ;
}
QMutexLocker locker ( & m_mutex ) ;
ModelInfo * info = m_modelMap . take ( oldId ) ;
info - > setId ( newId ) ;
m_modelMap . insert ( newId , info ) ;
}
2023-06-22 19:44:49 +00:00
int ModelList : : rowCount ( const QModelIndex & parent ) const
{
Q_UNUSED ( parent )
QMutexLocker locker ( & m_mutex ) ;
return m_models . size ( ) ;
}
QVariant ModelList : : dataInternal ( const ModelInfo * info , int role ) const
{
switch ( role ) {
2023-07-01 15:34:21 +00:00
case IdRole :
return info - > id ( ) ;
2023-06-22 19:44:49 +00:00
case NameRole :
2023-07-01 15:34:21 +00:00
return info - > name ( ) ;
2023-06-22 19:44:49 +00:00
case FilenameRole :
2023-07-01 15:34:21 +00:00
return info - > filename ( ) ;
2023-06-22 19:44:49 +00:00
case DirpathRole :
return info - > dirpath ;
case FilesizeRole :
return info - > filesize ;
2024-03-05 16:31:31 +00:00
case HashRole :
return info - > hash ;
case HashAlgorithmRole :
return info - > hashAlgorithm ;
2023-06-22 19:44:49 +00:00
case CalcHashRole :
return info - > calcHash ;
case InstalledRole :
return info - > installed ;
case DefaultRole :
return info - > isDefault ;
2024-01-22 17:36:01 +00:00
case OnlineRole :
return info - > isOnline ;
2023-06-22 19:44:49 +00:00
case DisableGUIRole :
return info - > disableGUI ;
case DescriptionRole :
2024-03-05 16:31:31 +00:00
return info - > description ( ) ;
2023-06-22 19:44:49 +00:00
case RequiresVersionRole :
return info - > requiresVersion ;
2024-03-06 19:12:21 +00:00
case VersionRemovedRole :
return info - > versionRemoved ;
2023-06-22 19:44:49 +00:00
case UrlRole :
2024-03-05 16:31:31 +00:00
return info - > url ( ) ;
2023-06-22 19:44:49 +00:00
case BytesReceivedRole :
return info - > bytesReceived ;
case BytesTotalRole :
return info - > bytesTotal ;
case TimestampRole :
return info - > timestamp ;
case SpeedRole :
return info - > speed ;
case DownloadingRole :
return info - > isDownloading ;
case IncompleteRole :
return info - > isIncomplete ;
case DownloadErrorRole :
return info - > downloadError ;
case OrderRole :
return info - > order ;
case RamrequiredRole :
return info - > ramrequired ;
case ParametersRole :
return info - > parameters ;
case QuantRole :
2024-03-05 16:31:31 +00:00
return info - > quant ( ) ;
2023-06-22 19:44:49 +00:00
case TypeRole :
2024-03-05 16:31:31 +00:00
return info - > type ( ) ;
2023-07-01 15:34:21 +00:00
case IsCloneRole :
2024-03-05 16:31:31 +00:00
return info - > isClone ( ) ;
case IsDiscoveredRole :
return info - > isDiscovered ( ) ;
2023-07-01 15:34:21 +00:00
case TemperatureRole :
return info - > temperature ( ) ;
case TopPRole :
return info - > topP ( ) ;
2024-02-24 22:51:34 +00:00
case MinPRole :
return info - > minP ( ) ;
2023-07-01 15:34:21 +00:00
case TopKRole :
return info - > topK ( ) ;
case MaxLengthRole :
return info - > maxLength ( ) ;
case PromptBatchSizeRole :
return info - > promptBatchSize ( ) ;
2023-12-16 22:58:15 +00:00
case ContextLengthRole :
return info - > contextLength ( ) ;
2024-01-31 19:17:44 +00:00
case GpuLayersRole :
return info - > gpuLayers ( ) ;
2023-07-01 15:34:21 +00:00
case RepeatPenaltyRole :
return info - > repeatPenalty ( ) ;
case RepeatPenaltyTokensRole :
return info - > repeatPenaltyTokens ( ) ;
case PromptTemplateRole :
return info - > promptTemplate ( ) ;
case SystemPromptRole :
return info - > systemPrompt ( ) ;
2024-03-05 16:31:31 +00:00
case LikesRole :
return info - > likes ( ) ;
case DownloadsRole :
return info - > downloads ( ) ;
case RecencyRole :
return info - > recency ( ) ;
2023-06-22 19:44:49 +00:00
}
return QVariant ( ) ;
}
2023-07-01 15:34:21 +00:00
QVariant ModelList : : data ( const QString & id , int role ) const
2023-06-22 19:44:49 +00:00
{
QMutexLocker locker ( & m_mutex ) ;
2023-07-01 15:34:21 +00:00
ModelInfo * info = m_modelMap . value ( id ) ;
2023-06-22 19:44:49 +00:00
return dataInternal ( info , role ) ;
}
2023-07-06 00:12:37 +00:00
QVariant ModelList : : dataByFilename ( const QString & filename , int role ) const
{
QMutexLocker locker ( & m_mutex ) ;
for ( ModelInfo * info : m_models )
if ( info - > filename ( ) = = filename )
return dataInternal ( info , role ) ;
return QVariant ( ) ;
}
2023-06-22 19:44:49 +00:00
QVariant ModelList : : data ( const QModelIndex & index , int role ) const
{
QMutexLocker locker ( & m_mutex ) ;
if ( ! index . isValid ( ) | | index . row ( ) < 0 | | index . row ( ) > = m_models . size ( ) )
return QVariant ( ) ;
const ModelInfo * info = m_models . at ( index . row ( ) ) ;
return dataInternal ( info , role ) ;
}
2023-07-01 15:34:21 +00:00
void ModelList : : updateData ( const QString & id , int role , const QVariant & value )
2023-06-22 19:44:49 +00:00
{
2024-03-05 16:31:31 +00:00
QVector < QPair < int , QVariant > > data ;
data . append ( qMakePair ( role , value ) ) ;
updateData ( id , data ) ;
}
void ModelList : : updateData ( const QString & id , const QVector < QPair < int , QVariant > > & data )
{
2023-06-26 00:22:38 +00:00
int index ;
{
QMutexLocker locker ( & m_mutex ) ;
2023-07-01 15:34:21 +00:00
if ( ! m_modelMap . contains ( id ) ) {
qWarning ( ) < < " ERROR: cannot update as model map does not contain " < < id ;
2023-06-26 00:22:38 +00:00
return ;
}
2023-06-22 19:44:49 +00:00
2023-07-01 15:34:21 +00:00
ModelInfo * info = m_modelMap . value ( id ) ;
2023-06-26 00:22:38 +00:00
index = m_models . indexOf ( info ) ;
if ( index = = - 1 ) {
2023-07-01 15:34:21 +00:00
qWarning ( ) < < " ERROR: cannot update as model list does not contain " < < id ;
2023-06-26 00:22:38 +00:00
return ;
}
2023-06-22 19:44:49 +00:00
2024-03-05 16:31:31 +00:00
for ( const auto & d : data ) {
const int role = d . first ;
const QVariant value = d . second ;
switch ( role ) {
case IdRole :
info - > setId ( value . toString ( ) ) ; break ;
case NameRole :
info - > setName ( value . toString ( ) ) ; break ;
case FilenameRole :
info - > setFilename ( value . toString ( ) ) ; break ;
case DirpathRole :
info - > dirpath = value . toString ( ) ; break ;
case FilesizeRole :
info - > filesize = value . toString ( ) ; break ;
case HashRole :
info - > hash = value . toByteArray ( ) ; break ;
case HashAlgorithmRole :
info - > hashAlgorithm = static_cast < ModelInfo : : HashAlgorithm > ( value . toInt ( ) ) ; break ;
case CalcHashRole :
info - > calcHash = value . toBool ( ) ; break ;
case InstalledRole :
info - > installed = value . toBool ( ) ; break ;
case DefaultRole :
info - > isDefault = value . toBool ( ) ; break ;
case OnlineRole :
info - > isOnline = value . toBool ( ) ; break ;
case DisableGUIRole :
info - > disableGUI = value . toBool ( ) ; break ;
case DescriptionRole :
info - > setDescription ( value . toString ( ) ) ; break ;
case RequiresVersionRole :
info - > requiresVersion = value . toString ( ) ; break ;
2024-03-06 19:12:21 +00:00
case VersionRemovedRole :
info - > versionRemoved = value . toString ( ) ; break ;
2024-03-05 16:31:31 +00:00
case UrlRole :
info - > setUrl ( value . toString ( ) ) ; break ;
case BytesReceivedRole :
info - > bytesReceived = value . toLongLong ( ) ; break ;
case BytesTotalRole :
info - > bytesTotal = value . toLongLong ( ) ; break ;
case TimestampRole :
info - > timestamp = value . toLongLong ( ) ; break ;
case SpeedRole :
info - > speed = value . toString ( ) ; break ;
case DownloadingRole :
info - > isDownloading = value . toBool ( ) ; break ;
case IncompleteRole :
info - > isIncomplete = value . toBool ( ) ; break ;
case DownloadErrorRole :
info - > downloadError = value . toString ( ) ; break ;
case OrderRole :
info - > order = value . toString ( ) ; break ;
case RamrequiredRole :
info - > ramrequired = value . toInt ( ) ; break ;
case ParametersRole :
info - > parameters = value . toString ( ) ; break ;
case QuantRole :
info - > setQuant ( value . toString ( ) ) ; break ;
case TypeRole :
info - > setType ( value . toString ( ) ) ; break ;
case IsCloneRole :
info - > setIsClone ( value . toBool ( ) ) ; break ;
case IsDiscoveredRole :
info - > setIsDiscovered ( value . toBool ( ) ) ; break ;
case TemperatureRole :
info - > setTemperature ( value . toDouble ( ) ) ; break ;
case TopPRole :
info - > setTopP ( value . toDouble ( ) ) ; break ;
case MinPRole :
info - > setMinP ( value . toDouble ( ) ) ; break ;
case TopKRole :
info - > setTopK ( value . toInt ( ) ) ; break ;
case MaxLengthRole :
info - > setMaxLength ( value . toInt ( ) ) ; break ;
case PromptBatchSizeRole :
info - > setPromptBatchSize ( value . toInt ( ) ) ; break ;
case ContextLengthRole :
info - > setContextLength ( value . toInt ( ) ) ; break ;
case GpuLayersRole :
info - > setGpuLayers ( value . toInt ( ) ) ; break ;
case RepeatPenaltyRole :
info - > setRepeatPenalty ( value . toDouble ( ) ) ; break ;
case RepeatPenaltyTokensRole :
info - > setRepeatPenaltyTokens ( value . toInt ( ) ) ; break ;
case PromptTemplateRole :
info - > setPromptTemplate ( value . toString ( ) ) ; break ;
case SystemPromptRole :
info - > setSystemPrompt ( value . toString ( ) ) ; break ;
case LikesRole :
info - > setLikes ( value . toInt ( ) ) ; break ;
case DownloadsRole :
info - > setDownloads ( value . toInt ( ) ) ; break ;
case RecencyRole :
info - > setRecency ( value . toDateTime ( ) ) ; break ;
}
2023-06-26 00:22:38 +00:00
}
2023-06-22 19:44:49 +00:00
2023-06-26 00:22:38 +00:00
// Extra guarantee that these always remains in sync with filesystem
2024-03-05 16:31:31 +00:00
const QFileInfo fileInfo ( info - > dirpath + info - > filename ( ) ) ;
info - > installed = fileInfo . exists ( ) ;
const QFileInfo incompleteInfo ( incompleteDownloadPath ( info - > filename ( ) ) ) ;
info - > isIncomplete = incompleteInfo . exists ( ) ;
auto s = m_discoverSort ;
auto d = m_discoverSortDirection ;
std : : stable_sort ( m_models . begin ( ) , m_models . end ( ) , [ s , d ] ( const ModelInfo * lhs , const ModelInfo * rhs ) {
return ModelList : : lessThan ( lhs , rhs , s , d ) ;
} ) ;
2023-06-26 00:22:38 +00:00
}
2024-03-05 16:31:31 +00:00
emit dataChanged ( createIndex ( index , 0 ) , createIndex ( index , 0 ) ) ;
2023-06-22 19:44:49 +00:00
emit userDefaultModelListChanged ( ) ;
}
2024-03-05 16:31:31 +00:00
void ModelList : : resortModel ( )
{
emit layoutAboutToBeChanged ( ) ;
{
QMutexLocker locker ( & m_mutex ) ;
auto s = m_discoverSort ;
auto d = m_discoverSortDirection ;
std : : stable_sort ( m_models . begin ( ) , m_models . end ( ) , [ s , d ] ( const ModelInfo * lhs , const ModelInfo * rhs ) {
return ModelList : : lessThan ( lhs , rhs , s , d ) ;
} ) ;
}
emit layoutChanged ( ) ;
}
2023-07-06 00:12:37 +00:00
void ModelList : : updateDataByFilename ( const QString & filename , int role , const QVariant & value )
{
QVector < QString > modelsById ;
{
QMutexLocker locker ( & m_mutex ) ;
for ( ModelInfo * info : m_models )
if ( info - > filename ( ) = = filename )
modelsById . append ( info - > id ( ) ) ;
}
if ( modelsById . isEmpty ( ) ) {
qWarning ( ) < < " ERROR: cannot update model as list does not contain file " < < filename ;
return ;
}
for ( const QString & id : modelsById )
updateData ( id , role , value ) ; ;
}
2023-07-01 15:34:21 +00:00
ModelInfo ModelList : : modelInfo ( const QString & id ) const
2023-06-22 19:44:49 +00:00
{
QMutexLocker locker ( & m_mutex ) ;
2023-07-01 15:34:21 +00:00
if ( ! m_modelMap . contains ( id ) )
2023-06-22 19:44:49 +00:00
return ModelInfo ( ) ;
2023-07-01 15:34:21 +00:00
return * m_modelMap . value ( id ) ;
}
ModelInfo ModelList : : modelInfoByFilename ( const QString & filename ) const
{
QMutexLocker locker ( & m_mutex ) ;
for ( ModelInfo * info : m_models )
if ( info - > filename ( ) = = filename )
return * info ;
return ModelInfo ( ) ;
}
bool ModelList : : isUniqueName ( const QString & name ) const
{
QMutexLocker locker ( & m_mutex ) ;
for ( const ModelInfo * info : m_models ) {
if ( info - > name ( ) = = name )
return false ;
}
return true ;
}
QString ModelList : : clone ( const ModelInfo & model )
{
const QString id = Network : : globalInstance ( ) - > generateUniqueId ( ) ;
addModel ( id ) ;
updateData ( id , ModelList : : IsCloneRole , true ) ;
updateData ( id , ModelList : : NameRole , uniqueModelName ( model ) ) ;
updateData ( id , ModelList : : FilenameRole , model . filename ( ) ) ;
updateData ( id , ModelList : : DirpathRole , model . dirpath ) ;
updateData ( id , ModelList : : InstalledRole , model . installed ) ;
2024-01-22 17:36:01 +00:00
updateData ( id , ModelList : : OnlineRole , model . isOnline ) ;
2023-07-01 15:34:21 +00:00
updateData ( id , ModelList : : TemperatureRole , model . temperature ( ) ) ;
updateData ( id , ModelList : : TopPRole , model . topP ( ) ) ;
2024-02-24 22:51:34 +00:00
updateData ( id , ModelList : : MinPRole , model . minP ( ) ) ;
2023-07-01 15:34:21 +00:00
updateData ( id , ModelList : : TopKRole , model . topK ( ) ) ;
updateData ( id , ModelList : : MaxLengthRole , model . maxLength ( ) ) ;
updateData ( id , ModelList : : PromptBatchSizeRole , model . promptBatchSize ( ) ) ;
2023-12-16 22:58:15 +00:00
updateData ( id , ModelList : : ContextLengthRole , model . contextLength ( ) ) ;
2024-02-26 18:09:29 +00:00
updateData ( id , ModelList : : GpuLayersRole , model . gpuLayers ( ) ) ;
2023-07-01 15:34:21 +00:00
updateData ( id , ModelList : : RepeatPenaltyRole , model . repeatPenalty ( ) ) ;
updateData ( id , ModelList : : RepeatPenaltyTokensRole , model . repeatPenaltyTokens ( ) ) ;
updateData ( id , ModelList : : PromptTemplateRole , model . promptTemplate ( ) ) ;
updateData ( id , ModelList : : SystemPromptRole , model . systemPrompt ( ) ) ;
return id ;
}
2024-03-05 16:31:31 +00:00
void ModelList : : removeClone ( const ModelInfo & model )
2023-07-01 15:34:21 +00:00
{
2024-03-05 16:31:31 +00:00
Q_ASSERT ( model . isClone ( ) ) ;
if ( ! model . isClone ( ) )
2023-07-01 15:34:21 +00:00
return ;
2024-03-05 16:31:31 +00:00
removeInternal ( model ) ;
emit layoutChanged ( ) ;
}
void ModelList : : removeInstalled ( const ModelInfo & model )
{
// We only remove a model if it is installed and is discovered or sideloaded
if ( ! model . installed | | ! ( model . isDiscovered ( ) | | model . description ( ) = = " " /*indicates sideloaded*/ ) )
return ;
// We shouldn't remove it if a discovered search is in progress or completed because the
// clearing of that search will erase it...
// FIXME: This won't be true in a bit when save the installed portion to settings, then we'll need to
// use this... or at least unflag the installed bit...
if ( m_discoverNumberOfResults )
return ;
removeInternal ( model ) ;
emit layoutChanged ( ) ;
}
void ModelList : : removeInternal ( const ModelInfo & model )
{
2023-07-01 15:34:21 +00:00
const bool hasModel = contains ( model . id ( ) ) ;
Q_ASSERT ( hasModel ) ;
if ( ! hasModel ) {
qWarning ( ) < < " ERROR: model list does not contain " < < model . id ( ) ;
return ;
}
int indexOfModel = 0 ;
{
QMutexLocker locker ( & m_mutex ) ;
ModelInfo * info = m_modelMap . value ( model . id ( ) ) ;
indexOfModel = m_models . indexOf ( info ) ;
}
beginRemoveRows ( QModelIndex ( ) , indexOfModel , indexOfModel ) ;
{
QMutexLocker locker ( & m_mutex ) ;
ModelInfo * info = m_models . takeAt ( indexOfModel ) ;
m_modelMap . remove ( info - > id ( ) ) ;
delete info ;
}
endRemoveRows ( ) ;
emit userDefaultModelListChanged ( ) ;
MySettings : : globalInstance ( ) - > eraseModel ( model ) ;
}
QString ModelList : : uniqueModelName ( const ModelInfo & model ) const
{
QMutexLocker locker ( & m_mutex ) ;
QRegularExpression re ( " ^(.*) ~ ( \ \ d + ) $ " ) ;
QRegularExpressionMatch match = re . match ( model . name ( ) ) ;
QString baseName ;
if ( match . hasMatch ( ) )
baseName = match . captured ( 1 ) ;
else
baseName = model . name ( ) ;
int maxSuffixNumber = 0 ;
bool baseNameExists = false ;
for ( const ModelInfo * info : m_models ) {
if ( info - > name ( ) = = baseName )
baseNameExists = true ;
QRegularExpressionMatch match = re . match ( info - > name ( ) ) ;
if ( match . hasMatch ( ) ) {
QString currentBaseName = match . captured ( 1 ) ;
int currentSuffixNumber = match . captured ( 2 ) . toInt ( ) ;
if ( currentBaseName = = baseName & & currentSuffixNumber > maxSuffixNumber )
maxSuffixNumber = currentSuffixNumber ;
}
}
if ( baseNameExists )
return baseName + " ~ " + QString : : number ( maxSuffixNumber + 1 ) ;
return baseName ;
2023-06-22 19:44:49 +00:00
}
2024-01-22 17:36:01 +00:00
QString ModelList : : modelDirPath ( const QString & modelName , bool isOnline )
2023-06-22 19:44:49 +00:00
{
QVector < QString > possibleFilePaths ;
2024-01-22 17:36:01 +00:00
if ( isOnline )
2023-06-22 19:44:49 +00:00
possibleFilePaths < < " / " + modelName + " .txt " ;
else {
possibleFilePaths < < " /ggml- " + modelName + " .bin " ;
possibleFilePaths < < " / " + modelName + " .bin " ;
}
for ( const QString & modelFilename : possibleFilePaths ) {
QString appPath = QCoreApplication : : applicationDirPath ( ) + modelFilename ;
QFileInfo infoAppPath ( appPath ) ;
if ( infoAppPath . exists ( ) )
return QCoreApplication : : applicationDirPath ( ) ;
2023-06-28 20:05:35 +00:00
QString downloadPath = MySettings : : globalInstance ( ) - > modelPath ( ) + modelFilename ;
2023-06-22 19:44:49 +00:00
QFileInfo infoLocalPath ( downloadPath ) ;
if ( infoLocalPath . exists ( ) )
2023-06-28 20:05:35 +00:00
return MySettings : : globalInstance ( ) - > modelPath ( ) ;
2023-06-22 19:44:49 +00:00
}
return QString ( ) ;
}
void ModelList : : updateModelsFromDirectory ( )
{
const QString exePath = QCoreApplication : : applicationDirPath ( ) + QDir : : separator ( ) ;
2023-06-28 20:05:35 +00:00
const QString localPath = MySettings : : globalInstance ( ) - > modelPath ( ) ;
2023-06-22 19:44:49 +00:00
2023-06-26 14:11:33 +00:00
auto processDirectory = [ & ] ( const QString & path ) {
QDirIterator it ( path , QDirIterator : : Subdirectories ) ;
while ( it . hasNext ( ) ) {
it . next ( ) ;
if ( ! it . fileInfo ( ) . isDir ( ) ) {
QString filename = it . fileName ( ) ;
2023-06-22 19:44:49 +00:00
2023-06-26 14:11:33 +00:00
// All files that end with .bin and have 'ggml' somewhere in the name
2023-09-21 16:41:48 +00:00
if ( ( ( filename . endsWith ( " .bin " ) | | filename . endsWith ( " .gguf " ) ) & & ( /*filename.contains("ggml") ||*/ filename . contains ( " gguf " ) ) & & ! filename . startsWith ( " incomplete " ) )
2024-01-22 17:36:01 +00:00
| | ( filename . endsWith ( " .txt " ) & & ( filename . startsWith ( " chatgpt- " ) | | filename . startsWith ( " nomic- " ) ) ) ) {
2023-06-26 14:11:33 +00:00
QString filePath = it . filePath ( ) ;
QFileInfo info ( filePath ) ;
if ( ! info . exists ( ) )
continue ;
2023-07-01 15:34:21 +00:00
QVector < QString > modelsById ;
{
QMutexLocker locker ( & m_mutex ) ;
for ( ModelInfo * info : m_models )
if ( info - > filename ( ) = = filename )
modelsById . append ( info - > id ( ) ) ;
}
2023-06-26 14:11:33 +00:00
2023-07-01 15:34:21 +00:00
if ( modelsById . isEmpty ( ) ) {
2024-03-05 16:31:31 +00:00
if ( ! contains ( filename ) )
addModel ( filename ) ;
2023-07-01 15:34:21 +00:00
modelsById . append ( filename ) ;
}
for ( const QString & id : modelsById ) {
2024-03-05 16:31:31 +00:00
updateData ( id , InstalledRole , true ) ;
2023-07-01 15:34:21 +00:00
updateData ( id , FilenameRole , filename ) ;
2024-01-22 17:36:01 +00:00
// FIXME: WE should change this to use a consistent filename for online models
updateData ( id , OnlineRole , filename . startsWith ( " chatgpt- " ) | | filename . startsWith ( " nomic- " ) ) ;
2023-07-12 18:12:41 +00:00
updateData ( id , DirpathRole , info . dir ( ) . absolutePath ( ) + " / " ) ;
2023-07-01 15:34:21 +00:00
updateData ( id , FilesizeRole , toFileSize ( info . size ( ) ) ) ;
}
2023-06-26 14:11:33 +00:00
}
2023-06-22 19:44:49 +00:00
}
}
2023-06-26 14:11:33 +00:00
} ;
2023-06-22 19:44:49 +00:00
2023-06-26 14:11:33 +00:00
processDirectory ( exePath ) ;
if ( localPath ! = exePath )
processDirectory ( localPath ) ;
2023-06-22 19:44:49 +00:00
}
2023-06-28 15:13:33 +00:00
2024-02-21 20:45:32 +00:00
# define MODELS_VERSION 3
2023-10-05 13:56:40 +00:00
2023-07-01 15:34:21 +00:00
void ModelList : : updateModelsFromJson ( )
2023-06-28 15:13:33 +00:00
{
# if defined(USE_LOCAL_MODELSJSON)
2023-10-05 13:56:40 +00:00
QUrl jsonUrl ( " file:// " + QDir : : homePath ( ) + QString ( " /dev/large_language_models/gpt4all/gpt4all-chat/metadata/models%1.json " ) . arg ( MODELS_VERSION ) ) ;
2023-06-28 15:13:33 +00:00
# else
2023-10-05 13:56:40 +00:00
QUrl jsonUrl ( QString ( " http://gpt4all.io/models/models%1.json " ) . arg ( MODELS_VERSION ) ) ;
2023-06-28 15:13:33 +00:00
# endif
QNetworkRequest request ( jsonUrl ) ;
QSslConfiguration conf = request . sslConfiguration ( ) ;
conf . setPeerVerifyMode ( QSslSocket : : VerifyNone ) ;
request . setSslConfiguration ( conf ) ;
QNetworkReply * jsonReply = m_networkManager . get ( request ) ;
2023-07-11 16:37:21 +00:00
connect ( qApp , & QCoreApplication : : aboutToQuit , jsonReply , & QNetworkReply : : abort ) ;
2023-06-28 15:13:33 +00:00
QEventLoop loop ;
connect ( jsonReply , & QNetworkReply : : finished , & loop , & QEventLoop : : quit ) ;
QTimer : : singleShot ( 1500 , & loop , & QEventLoop : : quit ) ;
loop . exec ( ) ;
if ( jsonReply - > error ( ) = = QNetworkReply : : NoError & & jsonReply - > isFinished ( ) ) {
QByteArray jsonData = jsonReply - > readAll ( ) ;
jsonReply - > deleteLater ( ) ;
2023-07-10 20:14:57 +00:00
parseModelsJsonFile ( jsonData , true ) ;
2023-06-28 15:13:33 +00:00
} else {
2023-07-10 20:14:57 +00:00
qWarning ( ) < < " WARNING: Could not download models.json synchronously " ;
updateModelsFromJsonAsync ( ) ;
QSettings settings ;
QFileInfo info ( settings . fileName ( ) ) ;
QString dirPath = info . canonicalPath ( ) ;
const QString modelsConfig = dirPath + " /models.json " ;
QFile file ( modelsConfig ) ;
if ( ! file . open ( QIODeviceBase : : ReadOnly ) ) {
qWarning ( ) < < " ERROR: Couldn't read models config file: " < < modelsConfig ;
} else {
QByteArray jsonData = file . readAll ( ) ;
file . close ( ) ;
parseModelsJsonFile ( jsonData , false ) ;
}
2023-06-28 15:13:33 +00:00
}
delete jsonReply ;
}
2023-07-10 20:14:57 +00:00
void ModelList : : updateModelsFromJsonAsync ( )
{
2023-07-12 15:46:40 +00:00
m_asyncModelRequestOngoing = true ;
emit asyncModelRequestOngoingChanged ( ) ;
2023-07-10 20:14:57 +00:00
# if defined(USE_LOCAL_MODELSJSON)
2023-10-05 13:56:40 +00:00
QUrl jsonUrl ( " file:// " + QDir : : homePath ( ) + QString ( " /dev/large_language_models/gpt4all/gpt4all-chat/metadata/models%1.json " ) . arg ( MODELS_VERSION ) ) ;
2023-07-10 20:14:57 +00:00
# else
2023-10-05 13:56:40 +00:00
QUrl jsonUrl ( QString ( " http://gpt4all.io/models/models%1.json " ) . arg ( MODELS_VERSION ) ) ;
2023-07-10 20:14:57 +00:00
# endif
QNetworkRequest request ( jsonUrl ) ;
QSslConfiguration conf = request . sslConfiguration ( ) ;
conf . setPeerVerifyMode ( QSslSocket : : VerifyNone ) ;
request . setSslConfiguration ( conf ) ;
QNetworkReply * jsonReply = m_networkManager . get ( request ) ;
2023-07-11 16:37:21 +00:00
connect ( qApp , & QCoreApplication : : aboutToQuit , jsonReply , & QNetworkReply : : abort ) ;
2023-07-10 20:14:57 +00:00
connect ( jsonReply , & QNetworkReply : : finished , this , & ModelList : : handleModelsJsonDownloadFinished ) ;
2023-07-12 15:46:40 +00:00
connect ( jsonReply , & QNetworkReply : : errorOccurred , this , & ModelList : : handleModelsJsonDownloadErrorOccurred ) ;
2023-07-10 20:14:57 +00:00
}
void ModelList : : handleModelsJsonDownloadFinished ( )
{
QNetworkReply * jsonReply = qobject_cast < QNetworkReply * > ( sender ( ) ) ;
2023-07-12 15:46:40 +00:00
if ( ! jsonReply ) {
m_asyncModelRequestOngoing = false ;
emit asyncModelRequestOngoingChanged ( ) ;
2023-07-10 20:14:57 +00:00
return ;
2023-07-12 15:46:40 +00:00
}
2023-07-10 20:14:57 +00:00
QByteArray jsonData = jsonReply - > readAll ( ) ;
jsonReply - > deleteLater ( ) ;
parseModelsJsonFile ( jsonData , true ) ;
2023-07-12 15:46:40 +00:00
m_asyncModelRequestOngoing = false ;
emit asyncModelRequestOngoingChanged ( ) ;
}
void ModelList : : handleModelsJsonDownloadErrorOccurred ( QNetworkReply : : NetworkError code )
{
2023-07-12 16:47:09 +00:00
// TODO: Show what error occurred in the GUI
2023-07-12 15:46:40 +00:00
m_asyncModelRequestOngoing = false ;
emit asyncModelRequestOngoingChanged ( ) ;
QNetworkReply * reply = qobject_cast < QNetworkReply * > ( sender ( ) ) ;
if ( ! reply )
return ;
qWarning ( ) < < QString ( " ERROR: Modellist download failed with error code \" %1-%2 \" " )
. arg ( code ) . arg ( reply - > errorString ( ) ) . toStdString ( ) ;
2023-07-10 20:14:57 +00:00
}
void ModelList : : handleSslErrors ( QNetworkReply * reply , const QList < QSslError > & errors )
{
QUrl url = reply - > request ( ) . url ( ) ;
for ( const auto & e : errors )
qWarning ( ) < < " ERROR: Received ssl error: " < < e . errorString ( ) < < " for " < < url ;
}
2023-07-01 15:34:21 +00:00
void ModelList : : updateDataForSettings ( )
{
emit dataChanged ( index ( 0 , 0 ) , index ( m_models . size ( ) - 1 , 0 ) ) ;
2023-06-28 15:13:33 +00:00
}
2024-03-06 19:12:21 +00:00
static std : : strong_ordering compareVersions ( const QString & a , const QString & b ) {
2023-06-28 15:13:33 +00:00
QStringList aParts = a . split ( ' . ' ) ;
QStringList bParts = b . split ( ' . ' ) ;
for ( int i = 0 ; i < std : : min ( aParts . size ( ) , bParts . size ( ) ) ; + + i ) {
int aInt = aParts [ i ] . toInt ( ) ;
int bInt = bParts [ i ] . toInt ( ) ;
2024-03-06 19:12:21 +00:00
if ( auto diff = aInt < = > bInt ; diff ! = 0 ) {
return diff ;
2023-06-28 15:13:33 +00:00
}
}
2024-03-06 19:12:21 +00:00
return aParts . size ( ) < = > bParts . size ( ) ;
2023-06-28 15:13:33 +00:00
}
2023-07-10 20:14:57 +00:00
void ModelList : : parseModelsJsonFile ( const QByteArray & jsonData , bool save )
2023-06-28 15:13:33 +00:00
{
QJsonParseError err ;
QJsonDocument document = QJsonDocument : : fromJson ( jsonData , & err ) ;
if ( err . error ! = QJsonParseError : : NoError ) {
qWarning ( ) < < " ERROR: Couldn't parse: " < < jsonData < < err . errorString ( ) ;
return ;
}
2023-07-10 20:14:57 +00:00
if ( save ) {
QSettings settings ;
QFileInfo info ( settings . fileName ( ) ) ;
QString dirPath = info . canonicalPath ( ) ;
const QString modelsConfig = dirPath + " /models.json " ;
QFile file ( modelsConfig ) ;
if ( ! file . open ( QIODeviceBase : : WriteOnly ) ) {
qWarning ( ) < < " ERROR: Couldn't write models config file: " < < modelsConfig ;
} else {
file . write ( jsonData . constData ( ) ) ;
file . close ( ) ;
}
}
2023-06-28 15:13:33 +00:00
QJsonArray jsonArray = document . array ( ) ;
const QString currentVersion = QCoreApplication : : applicationVersion ( ) ;
for ( const QJsonValue & value : jsonArray ) {
QJsonObject obj = value . toObject ( ) ;
QString modelName = obj [ " name " ] . toString ( ) ;
QString modelFilename = obj [ " filename " ] . toString ( ) ;
QString modelFilesize = obj [ " filesize " ] . toString ( ) ;
QString requiresVersion = obj [ " requires " ] . toString ( ) ;
2024-03-06 19:12:21 +00:00
QString versionRemoved = obj [ " removedIn " ] . toString ( ) ;
2023-06-28 15:13:33 +00:00
QString url = obj [ " url " ] . toString ( ) ;
2024-03-05 16:31:31 +00:00
QByteArray modelHash = obj [ " md5sum " ] . toString ( ) . toLatin1 ( ) . constData ( ) ;
2023-06-28 15:13:33 +00:00
bool isDefault = obj . contains ( " isDefault " ) & & obj [ " isDefault " ] = = QString ( " true " ) ;
bool disableGUI = obj . contains ( " disableGUI " ) & & obj [ " disableGUI " ] = = QString ( " true " ) ;
QString description = obj [ " description " ] . toString ( ) ;
QString order = obj [ " order " ] . toString ( ) ;
int ramrequired = obj [ " ramrequired " ] . toString ( ) . toInt ( ) ;
QString parameters = obj [ " parameters " ] . toString ( ) ;
QString quant = obj [ " quant " ] . toString ( ) ;
QString type = obj [ " type " ] . toString ( ) ;
2024-03-06 19:12:21 +00:00
// If the current version is strictly less than required version, then skip
if ( ! requiresVersion . isEmpty ( ) & & compareVersions ( currentVersion , requiresVersion ) < 0 ) {
2023-06-28 15:13:33 +00:00
continue ;
}
2024-03-06 19:12:21 +00:00
// If the version removed is less than or equal to the current version, then skip
if ( ! versionRemoved . isEmpty ( ) & & compareVersions ( versionRemoved , currentVersion ) < = 0 ) {
2023-06-28 15:13:33 +00:00
continue ;
}
modelFilesize = ModelList : : toFileSize ( modelFilesize . toULongLong ( ) ) ;
2023-07-01 15:34:21 +00:00
const QString id = modelName ;
Q_ASSERT ( ! id . isEmpty ( ) ) ;
2023-07-10 20:14:57 +00:00
if ( contains ( modelFilename ) )
changeId ( modelFilename , id ) ;
2023-07-01 15:34:21 +00:00
if ( ! contains ( id ) )
addModel ( id ) ;
updateData ( id , ModelList : : NameRole , modelName ) ;
updateData ( id , ModelList : : FilenameRole , modelFilename ) ;
updateData ( id , ModelList : : FilesizeRole , modelFilesize ) ;
2024-03-05 16:31:31 +00:00
updateData ( id , ModelList : : HashRole , modelHash ) ;
updateData ( id , ModelList : : HashAlgorithmRole , ModelInfo : : Md5 ) ;
2023-07-01 15:34:21 +00:00
updateData ( id , ModelList : : DefaultRole , isDefault ) ;
updateData ( id , ModelList : : DescriptionRole , description ) ;
updateData ( id , ModelList : : RequiresVersionRole , requiresVersion ) ;
2024-03-06 19:12:21 +00:00
updateData ( id , ModelList : : VersionRemovedRole , versionRemoved ) ;
2023-07-01 15:34:21 +00:00
updateData ( id , ModelList : : UrlRole , url ) ;
updateData ( id , ModelList : : DisableGUIRole , disableGUI ) ;
updateData ( id , ModelList : : OrderRole , order ) ;
updateData ( id , ModelList : : RamrequiredRole , ramrequired ) ;
updateData ( id , ModelList : : ParametersRole , parameters ) ;
updateData ( id , ModelList : : QuantRole , quant ) ;
updateData ( id , ModelList : : TypeRole , type ) ;
if ( obj . contains ( " temperature " ) )
updateData ( id , ModelList : : TemperatureRole , obj [ " temperature " ] . toDouble ( ) ) ;
if ( obj . contains ( " topP " ) )
updateData ( id , ModelList : : TopPRole , obj [ " topP " ] . toDouble ( ) ) ;
2024-02-24 22:51:34 +00:00
if ( obj . contains ( " minP " ) )
updateData ( id , ModelList : : MinPRole , obj [ " minP " ] . toDouble ( ) ) ;
2023-07-01 15:34:21 +00:00
if ( obj . contains ( " topK " ) )
updateData ( id , ModelList : : TopKRole , obj [ " topK " ] . toInt ( ) ) ;
if ( obj . contains ( " maxLength " ) )
updateData ( id , ModelList : : MaxLengthRole , obj [ " maxLength " ] . toInt ( ) ) ;
if ( obj . contains ( " promptBatchSize " ) )
updateData ( id , ModelList : : PromptBatchSizeRole , obj [ " promptBatchSize " ] . toInt ( ) ) ;
2023-12-16 22:58:15 +00:00
if ( obj . contains ( " contextLength " ) )
updateData ( id , ModelList : : ContextLengthRole , obj [ " contextLength " ] . toInt ( ) ) ;
2024-01-31 19:17:44 +00:00
if ( obj . contains ( " gpuLayers " ) )
updateData ( id , ModelList : : GpuLayersRole , obj [ " gpuLayers " ] . toInt ( ) ) ;
2023-07-01 15:34:21 +00:00
if ( obj . contains ( " repeatPenalty " ) )
updateData ( id , ModelList : : RepeatPenaltyRole , obj [ " repeatPenalty " ] . toDouble ( ) ) ;
if ( obj . contains ( " repeatPenaltyTokens " ) )
updateData ( id , ModelList : : RepeatPenaltyTokensRole , obj [ " repeatPenaltyTokens " ] . toInt ( ) ) ;
if ( obj . contains ( " promptTemplate " ) )
updateData ( id , ModelList : : PromptTemplateRole , obj [ " promptTemplate " ] . toString ( ) ) ;
if ( obj . contains ( " systemPrompt " ) )
updateData ( id , ModelList : : SystemPromptRole , obj [ " systemPrompt " ] . toString ( ) ) ;
2023-06-28 15:13:33 +00:00
}
const QString chatGPTDesc = tr ( " <ul><li>Requires personal OpenAI API key.</li><li>WARNING: Will send "
" your chats to OpenAI!</li><li>Your API key will be stored on disk</li><li>Will only be used "
" to communicate with OpenAI</li><li>You can apply for an API key "
" <a href= \" https://platform.openai.com/account/api-keys \" >here.</a></li> " ) ;
{
2023-07-01 15:34:21 +00:00
const QString modelName = " ChatGPT-3.5 Turbo " ;
const QString id = modelName ;
2023-06-28 15:13:33 +00:00
const QString modelFilename = " chatgpt-gpt-3.5-turbo.txt " ;
2023-07-10 20:14:57 +00:00
if ( contains ( modelFilename ) )
changeId ( modelFilename , id ) ;
2023-07-01 15:34:21 +00:00
if ( ! contains ( id ) )
addModel ( id ) ;
updateData ( id , ModelList : : NameRole , modelName ) ;
updateData ( id , ModelList : : FilenameRole , modelFilename ) ;
updateData ( id , ModelList : : FilesizeRole , " minimal " ) ;
2024-01-22 17:36:01 +00:00
updateData ( id , ModelList : : OnlineRole , true ) ;
2023-07-01 15:34:21 +00:00
updateData ( id , ModelList : : DescriptionRole ,
2023-06-28 15:13:33 +00:00
tr ( " <strong>OpenAI's ChatGPT model GPT-3.5 Turbo</strong><br> " ) + chatGPTDesc ) ;
2023-07-01 15:34:21 +00:00
updateData ( id , ModelList : : RequiresVersionRole , " 2.4.2 " ) ;
updateData ( id , ModelList : : OrderRole , " ca " ) ;
updateData ( id , ModelList : : RamrequiredRole , 0 ) ;
updateData ( id , ModelList : : ParametersRole , " ? " ) ;
updateData ( id , ModelList : : QuantRole , " NA " ) ;
updateData ( id , ModelList : : TypeRole , " GPT " ) ;
2023-06-28 15:13:33 +00:00
}
{
2023-07-11 19:35:10 +00:00
const QString chatGPT4Warn = tr ( " <br><br><i>* Even if you pay OpenAI for ChatGPT-4 this does not guarantee API key access. Contact OpenAI for more info. " ) ;
2023-07-01 15:34:21 +00:00
const QString modelName = " ChatGPT-4 " ;
const QString id = modelName ;
2023-06-28 15:13:33 +00:00
const QString modelFilename = " chatgpt-gpt-4.txt " ;
2023-07-10 20:14:57 +00:00
if ( contains ( modelFilename ) )
changeId ( modelFilename , id ) ;
2023-07-01 15:34:21 +00:00
if ( ! contains ( id ) )
addModel ( id ) ;
updateData ( id , ModelList : : NameRole , modelName ) ;
updateData ( id , ModelList : : FilenameRole , modelFilename ) ;
updateData ( id , ModelList : : FilesizeRole , " minimal " ) ;
2024-01-22 17:36:01 +00:00
updateData ( id , ModelList : : OnlineRole , true ) ;
2023-07-01 15:34:21 +00:00
updateData ( id , ModelList : : DescriptionRole ,
2023-07-11 19:35:10 +00:00
tr ( " <strong>OpenAI's ChatGPT model GPT-4</strong><br> " ) + chatGPTDesc + chatGPT4Warn ) ;
2023-07-01 15:34:21 +00:00
updateData ( id , ModelList : : RequiresVersionRole , " 2.4.2 " ) ;
updateData ( id , ModelList : : OrderRole , " cb " ) ;
updateData ( id , ModelList : : RamrequiredRole , 0 ) ;
updateData ( id , ModelList : : ParametersRole , " ? " ) ;
updateData ( id , ModelList : : QuantRole , " NA " ) ;
updateData ( id , ModelList : : TypeRole , " GPT " ) ;
2024-01-22 17:36:01 +00:00
}
{
const QString nomicEmbedDesc = tr ( " <ul><li>For use with LocalDocs feature</li> "
" <li>Used for retrieval augmented generation (RAG)</li> "
" <li>Requires personal Nomic API key.</li> "
" <li>WARNING: Will send your localdocs to Nomic Atlas!</li> "
" <li>You can apply for an API key <a href= \" https://atlas.nomic.ai/ \" >with Nomic Atlas.</a></li> " ) ;
const QString modelName = " Nomic Embed " ;
const QString id = modelName ;
const QString modelFilename = " nomic-embed-text-v1.txt " ;
if ( contains ( modelFilename ) )
changeId ( modelFilename , id ) ;
if ( ! contains ( id ) )
addModel ( id ) ;
updateData ( id , ModelList : : NameRole , modelName ) ;
updateData ( id , ModelList : : FilenameRole , modelFilename ) ;
updateData ( id , ModelList : : FilesizeRole , " minimal " ) ;
updateData ( id , ModelList : : OnlineRole , true ) ;
updateData ( id , ModelList : : DisableGUIRole , true ) ;
updateData ( id , ModelList : : DescriptionRole ,
tr ( " <strong>LocalDocs Nomic Atlas Embed</strong><br> " ) + nomicEmbedDesc ) ;
updateData ( id , ModelList : : RequiresVersionRole , " 2.6.3 " ) ;
updateData ( id , ModelList : : OrderRole , " na " ) ;
updateData ( id , ModelList : : RamrequiredRole , 0 ) ;
updateData ( id , ModelList : : ParametersRole , " ? " ) ;
updateData ( id , ModelList : : QuantRole , " NA " ) ;
updateData ( id , ModelList : : TypeRole , " Bert " ) ;
2023-06-28 15:13:33 +00:00
}
}
2023-07-01 15:34:21 +00:00
2024-03-05 16:31:31 +00:00
void ModelList : : updateDiscoveredInstalled ( const ModelInfo & info )
{
updateData ( info . id ( ) , ModelList : : InstalledRole , true ) ;
updateData ( info . id ( ) , ModelList : : IsDiscoveredRole , true ) ;
updateData ( info . id ( ) , ModelList : : NameRole , info . name ( ) ) ;
updateData ( info . id ( ) , ModelList : : FilenameRole , info . filename ( ) ) ;
updateData ( info . id ( ) , ModelList : : DescriptionRole , info . description ( ) ) ;
updateData ( info . id ( ) , ModelList : : UrlRole , info . url ( ) ) ;
updateData ( info . id ( ) , ModelList : : LikesRole , info . likes ( ) ) ;
updateData ( info . id ( ) , ModelList : : DownloadsRole , info . downloads ( ) ) ;
updateData ( info . id ( ) , ModelList : : RecencyRole , info . recency ( ) ) ;
updateData ( info . id ( ) , ModelList : : QuantRole , info . quant ( ) ) ;
updateData ( info . id ( ) , ModelList : : TypeRole , info . type ( ) ) ;
}
2023-07-01 15:34:21 +00:00
void ModelList : : updateModelsFromSettings ( )
{
QSettings settings ;
settings . sync ( ) ;
QStringList groups = settings . childGroups ( ) ;
for ( const QString g : groups ) {
if ( ! g . startsWith ( " model- " ) )
continue ;
const QString id = g . sliced ( 6 ) ;
if ( contains ( id ) )
continue ;
2024-03-05 16:31:31 +00:00
addModel ( id ) ;
if ( settings . contains ( g + " /name " ) ) {
const QString name = settings . value ( g + " /name " ) . toString ( ) ;
updateData ( id , ModelList : : NameRole , name ) ;
}
if ( settings . contains ( g + " /filename " ) ) {
const QString filename = settings . value ( g + " /filename " ) . toString ( ) ;
updateData ( id , ModelList : : FilenameRole , filename ) ;
}
if ( settings . contains ( g + " /description " ) ) {
const QString d = settings . value ( g + " /description " ) . toString ( ) ;
updateData ( id , ModelList : : DescriptionRole , d ) ;
}
if ( settings . contains ( g + " /url " ) ) {
const QString u = settings . value ( g + " /url " ) . toString ( ) ;
updateData ( id , ModelList : : UrlRole , u ) ;
}
if ( settings . contains ( g + " /quant " ) ) {
const QString q = settings . value ( g + " /quant " ) . toString ( ) ;
updateData ( id , ModelList : : QuantRole , q ) ;
}
if ( settings . contains ( g + " /type " ) ) {
const QString t = settings . value ( g + " /type " ) . toString ( ) ;
updateData ( id , ModelList : : TypeRole , t ) ;
}
if ( settings . contains ( g + " /isClone " ) ) {
const bool b = settings . value ( g + " /isClone " ) . toBool ( ) ;
updateData ( id , ModelList : : IsCloneRole , b ) ;
}
if ( settings . contains ( g + " /isDiscovered " ) ) {
const bool b = settings . value ( g + " /isDiscovered " ) . toBool ( ) ;
updateData ( id , ModelList : : IsDiscoveredRole , b ) ;
}
if ( settings . contains ( g + " /likes " ) ) {
const int l = settings . value ( g + " /likes " ) . toInt ( ) ;
updateData ( id , ModelList : : LikesRole , l ) ;
}
if ( settings . contains ( g + " /downloads " ) ) {
const int d = settings . value ( g + " /downloads " ) . toInt ( ) ;
updateData ( id , ModelList : : DownloadsRole , d ) ;
}
if ( settings . contains ( g + " /recency " ) ) {
const QDateTime r = settings . value ( g + " /recency " ) . toDateTime ( ) ;
updateData ( id , ModelList : : RecencyRole , r ) ;
}
if ( settings . contains ( g + " /temperature " ) ) {
const double temperature = settings . value ( g + " /temperature " ) . toDouble ( ) ;
updateData ( id , ModelList : : TemperatureRole , temperature ) ;
}
if ( settings . contains ( g + " /topP " ) ) {
const double topP = settings . value ( g + " /topP " ) . toDouble ( ) ;
updateData ( id , ModelList : : TopPRole , topP ) ;
}
if ( settings . contains ( g + " /minP " ) ) {
const double minP = settings . value ( g + " /minP " ) . toDouble ( ) ;
updateData ( id , ModelList : : MinPRole , minP ) ;
}
if ( settings . contains ( g + " /topK " ) ) {
const int topK = settings . value ( g + " /topK " ) . toInt ( ) ;
updateData ( id , ModelList : : TopKRole , topK ) ;
}
if ( settings . contains ( g + " /maxLength " ) ) {
const int maxLength = settings . value ( g + " /maxLength " ) . toInt ( ) ;
updateData ( id , ModelList : : MaxLengthRole , maxLength ) ;
}
if ( settings . contains ( g + " /promptBatchSize " ) ) {
const int promptBatchSize = settings . value ( g + " /promptBatchSize " ) . toInt ( ) ;
updateData ( id , ModelList : : PromptBatchSizeRole , promptBatchSize ) ;
}
if ( settings . contains ( g + " /contextLength " ) ) {
const int contextLength = settings . value ( g + " /contextLength " ) . toInt ( ) ;
updateData ( id , ModelList : : ContextLengthRole , contextLength ) ;
}
if ( settings . contains ( g + " /gpuLayers " ) ) {
const int gpuLayers = settings . value ( g + " /gpuLayers " ) . toInt ( ) ;
updateData ( id , ModelList : : GpuLayersRole , gpuLayers ) ;
}
if ( settings . contains ( g + " /repeatPenalty " ) ) {
const double repeatPenalty = settings . value ( g + " /repeatPenalty " ) . toDouble ( ) ;
updateData ( id , ModelList : : RepeatPenaltyRole , repeatPenalty ) ;
}
if ( settings . contains ( g + " /repeatPenaltyTokens " ) ) {
const int repeatPenaltyTokens = settings . value ( g + " /repeatPenaltyTokens " ) . toInt ( ) ;
updateData ( id , ModelList : : RepeatPenaltyTokensRole , repeatPenaltyTokens ) ;
}
if ( settings . contains ( g + " /promptTemplate " ) ) {
const QString promptTemplate = settings . value ( g + " /promptTemplate " ) . toString ( ) ;
updateData ( id , ModelList : : PromptTemplateRole , promptTemplate ) ;
}
if ( settings . contains ( g + " /systemPrompt " ) ) {
const QString systemPrompt = settings . value ( g + " /systemPrompt " ) . toString ( ) ;
updateData ( id , ModelList : : SystemPromptRole , systemPrompt ) ;
}
}
}
int ModelList : : discoverLimit ( ) const
{
return m_discoverLimit ;
}
void ModelList : : setDiscoverLimit ( int limit )
{
if ( m_discoverLimit = = limit )
return ;
m_discoverLimit = limit ;
emit discoverLimitChanged ( ) ;
}
int ModelList : : discoverSortDirection ( ) const
{
return m_discoverSortDirection ;
}
void ModelList : : setDiscoverSortDirection ( int direction )
{
if ( m_discoverSortDirection = = direction | | ( direction ! = 1 & & direction ! = - 1 ) )
return ;
m_discoverSortDirection = direction ;
emit discoverSortDirectionChanged ( ) ;
resortModel ( ) ;
}
ModelList : : DiscoverSort ModelList : : discoverSort ( ) const
{
return m_discoverSort ;
}
void ModelList : : setDiscoverSort ( DiscoverSort sort )
{
if ( m_discoverSort = = sort )
return ;
m_discoverSort = sort ;
emit discoverSortChanged ( ) ;
resortModel ( ) ;
}
void ModelList : : clearDiscoveredModels ( )
{
// NOTE: This could be made much more efficient
QList < ModelInfo > infos ;
{
QMutexLocker locker ( & m_mutex ) ;
for ( ModelInfo * info : m_models )
if ( info - > isDiscovered ( ) )
infos . append ( * info ) ;
}
for ( ModelInfo & info : infos )
removeInternal ( info ) ;
emit layoutChanged ( ) ;
}
float ModelList : : discoverProgress ( ) const
{
if ( ! m_discoverNumberOfResults )
return 0.0f ;
return m_discoverResultsCompleted / float ( m_discoverNumberOfResults ) ;
}
bool ModelList : : discoverInProgress ( ) const
{
return m_discoverInProgress ;
}
void ModelList : : discoverSearch ( const QString & search )
{
Q_ASSERT ( ! m_discoverInProgress ) ;
clearDiscoveredModels ( ) ;
m_discoverNumberOfResults = 0 ;
m_discoverResultsCompleted = 0 ;
discoverProgressChanged ( ) ;
if ( search . isEmpty ( ) ) {
return ;
}
m_discoverInProgress = true ;
emit discoverInProgressChanged ( ) ;
QStringList searchParams = search . split ( QRegularExpression ( " \\ s+ " ) ) ; // split by whitespace
QString searchString = QString ( " search=%1& " ) . arg ( searchParams . join ( ' + ' ) ) ;
QString limitString = m_discoverLimit > 0 ? QString ( " limit=%1& " ) . arg ( m_discoverLimit ) : QString ( ) ;
QString sortString ;
switch ( m_discoverSort ) {
case Default : break ;
case Likes :
sortString = " sort=likes& " ; break ;
case Downloads :
sortString = " sort=downloads& " ; break ;
case Recent :
sortString = " sort=lastModified& " ; break ;
}
QString directionString = ! sortString . isEmpty ( ) ? QString ( " direction=%1& " ) . arg ( m_discoverSortDirection ) : QString ( ) ;
QUrl hfUrl ( QString ( " https://huggingface.co/api/models?filter=gguf&%1%2%3%4full=true&config=true " ) . arg ( searchString ) . arg ( limitString ) . arg ( sortString ) . arg ( directionString ) ) ;
QNetworkRequest request ( hfUrl ) ;
request . setHeader ( QNetworkRequest : : ContentTypeHeader , " application/json " ) ;
QNetworkReply * reply = m_networkManager . get ( request ) ;
connect ( qApp , & QCoreApplication : : aboutToQuit , reply , & QNetworkReply : : abort ) ;
connect ( reply , & QNetworkReply : : finished , this , & ModelList : : handleDiscoveryFinished ) ;
connect ( reply , & QNetworkReply : : errorOccurred , this , & ModelList : : handleDiscoveryErrorOccurred ) ;
}
void ModelList : : handleDiscoveryFinished ( )
{
QNetworkReply * jsonReply = qobject_cast < QNetworkReply * > ( sender ( ) ) ;
if ( ! jsonReply )
return ;
QByteArray jsonData = jsonReply - > readAll ( ) ;
parseDiscoveryJsonFile ( jsonData ) ;
jsonReply - > deleteLater ( ) ;
}
void ModelList : : handleDiscoveryErrorOccurred ( QNetworkReply : : NetworkError code )
{
QNetworkReply * reply = qobject_cast < QNetworkReply * > ( sender ( ) ) ;
if ( ! reply )
return ;
qWarning ( ) < < QString ( " ERROR: Discovery failed with error code \" %1-%2 \" " )
. arg ( code ) . arg ( reply - > errorString ( ) ) . toStdString ( ) ;
}
enum QuantType {
Q4_0 = 0 ,
Q4_1 ,
F16 ,
F32 ,
Unknown
} ;
QuantType toQuantType ( const QString & filename )
{
QString lowerCaseFilename = filename . toLower ( ) ;
if ( lowerCaseFilename . contains ( " q4_0 " ) ) return Q4_0 ;
if ( lowerCaseFilename . contains ( " q4_1 " ) ) return Q4_1 ;
if ( lowerCaseFilename . contains ( " f16 " ) ) return F16 ;
if ( lowerCaseFilename . contains ( " f32 " ) ) return F32 ;
return Unknown ;
}
QString toQuantString ( const QString & filename )
{
QString lowerCaseFilename = filename . toLower ( ) ;
if ( lowerCaseFilename . contains ( " q4_0 " ) ) return " q4_0 " ;
if ( lowerCaseFilename . contains ( " q4_1 " ) ) return " q4_1 " ;
if ( lowerCaseFilename . contains ( " f16 " ) ) return " f16 " ;
if ( lowerCaseFilename . contains ( " f32 " ) ) return " f32 " ;
return QString ( ) ;
}
void ModelList : : parseDiscoveryJsonFile ( const QByteArray & jsonData )
{
QJsonParseError err ;
QJsonDocument document = QJsonDocument : : fromJson ( jsonData , & err ) ;
if ( err . error ! = QJsonParseError : : NoError ) {
qWarning ( ) < < " ERROR: Couldn't parse: " < < jsonData < < err . errorString ( ) ;
m_discoverNumberOfResults = 0 ;
m_discoverResultsCompleted = 0 ;
discoverProgressChanged ( ) ;
m_discoverInProgress = false ;
emit discoverInProgressChanged ( ) ;
return ;
}
QJsonArray jsonArray = document . array ( ) ;
for ( const QJsonValue & value : jsonArray ) {
QJsonObject obj = value . toObject ( ) ;
QJsonDocument jsonDocument ( obj ) ;
QByteArray jsonData = jsonDocument . toJson ( ) ;
QString repo_id = obj [ " id " ] . toString ( ) ;
QJsonArray siblingsArray = obj [ " siblings " ] . toArray ( ) ;
QList < QPair < QuantType , QString > > filteredAndSortedFilenames ;
for ( const QJsonValue & sibling : siblingsArray ) {
QJsonObject s = sibling . toObject ( ) ;
QString filename = s [ " rfilename " ] . toString ( ) ;
if ( ! filename . endsWith ( " gguf " ) )
continue ;
QuantType quant = toQuantType ( filename ) ;
if ( quant ! = Unknown )
filteredAndSortedFilenames . append ( qMakePair ( quant , filename ) ) ;
}
if ( filteredAndSortedFilenames . isEmpty ( ) )
2023-07-01 15:34:21 +00:00
continue ;
2024-03-05 16:31:31 +00:00
std : : sort ( filteredAndSortedFilenames . begin ( ) , filteredAndSortedFilenames . end ( ) ,
[ ] ( const QPair < QuantType , QString > & a , const QPair < QuantType , QString > & b ) {
return a . first < b . first ;
} ) ;
QPair < QuantType , QString > file = filteredAndSortedFilenames . first ( ) ;
QString filename = file . second ;
+ + m_discoverNumberOfResults ;
QUrl url ( QString ( " https://huggingface.co/%1/resolve/main/%2 " ) . arg ( repo_id ) . arg ( filename ) ) ;
QNetworkRequest request ( url ) ;
request . setRawHeader ( " Accept-Encoding " , " identity " ) ;
request . setAttribute ( QNetworkRequest : : RedirectPolicyAttribute , QNetworkRequest : : ManualRedirectPolicy ) ;
request . setAttribute ( QNetworkRequest : : User , jsonData ) ;
request . setAttribute ( QNetworkRequest : : UserMax , filename ) ;
QNetworkReply * reply = m_networkManager . head ( request ) ;
connect ( qApp , & QCoreApplication : : aboutToQuit , reply , & QNetworkReply : : abort ) ;
connect ( reply , & QNetworkReply : : finished , this , & ModelList : : handleDiscoveryItemFinished ) ;
connect ( reply , & QNetworkReply : : errorOccurred , this , & ModelList : : handleDiscoveryItemErrorOccurred ) ;
}
2023-07-01 15:34:21 +00:00
2024-03-05 16:31:31 +00:00
emit discoverProgressChanged ( ) ;
if ( ! m_discoverNumberOfResults ) {
m_discoverInProgress = false ;
emit discoverInProgressChanged ( ) ; ;
}
}
void ModelList : : handleDiscoveryItemFinished ( )
{
QNetworkReply * reply = qobject_cast < QNetworkReply * > ( sender ( ) ) ;
if ( ! reply )
return ;
QVariant replyCustomData = reply - > request ( ) . attribute ( QNetworkRequest : : User ) ;
QByteArray customDataByteArray = replyCustomData . toByteArray ( ) ;
QJsonDocument customJsonDocument = QJsonDocument : : fromJson ( customDataByteArray ) ;
QJsonObject obj = customJsonDocument . object ( ) ;
QString repo_id = obj [ " id " ] . toString ( ) ;
QString modelName = obj [ " modelId " ] . toString ( ) ;
QString author = obj [ " author " ] . toString ( ) ;
QDateTime lastModified = QDateTime : : fromString ( obj [ " lastModified " ] . toString ( ) , Qt : : ISODateWithMs ) ;
int likes = obj [ " likes " ] . toInt ( ) ;
int downloads = obj [ " downloads " ] . toInt ( ) ;
QJsonObject config = obj [ " config " ] . toObject ( ) ;
QString type = config [ " model_type " ] . toString ( ) ;
QByteArray repoCommitHeader = reply - > rawHeader ( " X-Repo-Commit " ) ;
QByteArray linkedSizeHeader = reply - > rawHeader ( " X-Linked-Size " ) ;
QByteArray linkedEtagHeader = reply - > rawHeader ( " X-Linked-Etag " ) ;
// For some reason these seem to contain quotation marks ewww
linkedEtagHeader . replace ( " \" " , " " ) ;
linkedEtagHeader . replace ( " \' " , " " ) ;
QString locationHeader = reply - > header ( QNetworkRequest : : LocationHeader ) . toString ( ) ;
QString repoCommit = QString : : fromUtf8 ( repoCommitHeader ) ;
QString linkedSize = QString : : fromUtf8 ( linkedSizeHeader ) ;
QString linkedEtag = QString : : fromUtf8 ( linkedEtagHeader ) ;
QString url = locationHeader ;
QString modelFilename = reply - > request ( ) . attribute ( QNetworkRequest : : UserMax ) . toString ( ) ;
QString modelFilesize = linkedSize ;
modelFilesize = ModelList : : toFileSize ( modelFilesize . toULongLong ( ) ) ;
QString description = tr ( " <strong>Created by %1.</strong><br><ul> "
" <li>Published on %2. "
" <li>This model has %3 likes. "
" <li>This model has %4 downloads. "
" <li>More info can be found <a href= \" https://huggingface.co/%5 \" >here.</a></ul> " )
. arg ( author )
. arg ( lastModified . toString ( " ddd MMMM d, yyyy " ) )
. arg ( likes )
. arg ( downloads )
. arg ( repo_id ) ;
const QString id = modelFilename ;
Q_ASSERT ( ! id . isEmpty ( ) ) ;
if ( contains ( modelFilename ) )
changeId ( modelFilename , id ) ;
if ( ! contains ( id ) )
2023-07-01 15:34:21 +00:00
addModel ( id ) ;
2024-03-05 16:31:31 +00:00
QVector < QPair < int , QVariant > > data ;
data . append ( qMakePair ( ModelList : : NameRole , modelName ) ) ;
data . append ( qMakePair ( ModelList : : FilenameRole , modelFilename ) ) ;
data . append ( qMakePair ( ModelList : : FilesizeRole , modelFilesize ) ) ;
data . append ( qMakePair ( ModelList : : DescriptionRole , description ) ) ;
data . append ( qMakePair ( ModelList : : IsDiscoveredRole , true ) ) ;
data . append ( qMakePair ( ModelList : : UrlRole , url ) ) ;
data . append ( qMakePair ( ModelList : : LikesRole , likes ) ) ;
data . append ( qMakePair ( ModelList : : DownloadsRole , downloads ) ) ;
data . append ( qMakePair ( ModelList : : RecencyRole , lastModified ) ) ;
data . append ( qMakePair ( ModelList : : QuantRole , toQuantString ( modelFilename ) ) ) ;
data . append ( qMakePair ( ModelList : : TypeRole , type ) ) ;
data . append ( qMakePair ( ModelList : : HashRole , linkedEtagHeader ) ) ;
data . append ( qMakePair ( ModelList : : HashAlgorithmRole , ModelInfo : : Sha256 ) ) ;
updateData ( id , data ) ;
+ + m_discoverResultsCompleted ;
emit discoverProgressChanged ( ) ;
if ( discoverProgress ( ) > = 1.0 ) {
emit layoutChanged ( ) ;
m_discoverInProgress = false ;
emit discoverInProgressChanged ( ) ; ;
2023-07-01 15:34:21 +00:00
}
2024-03-05 16:31:31 +00:00
reply - > deleteLater ( ) ;
}
void ModelList : : handleDiscoveryItemErrorOccurred ( QNetworkReply : : NetworkError code )
{
QNetworkReply * reply = qobject_cast < QNetworkReply * > ( sender ( ) ) ;
if ( ! reply )
return ;
qWarning ( ) < < QString ( " ERROR: Discovery item failed with error code \" %1-%2 \" " )
. arg ( code ) . arg ( reply - > errorString ( ) ) . toStdString ( ) ;
2023-07-01 15:34:21 +00:00
}