mirror of
https://github.com/nomic-ai/gpt4all
synced 2024-11-10 01:10:35 +00:00
Allow unloading/loading/changing of models.
This commit is contained in:
parent
8a4f7897f4
commit
2b1cae5a7e
91
llm.cpp
91
llm.cpp
@ -18,7 +18,7 @@ static LLModel::PromptContext s_ctx;
|
|||||||
|
|
||||||
LLMObject::LLMObject()
|
LLMObject::LLMObject()
|
||||||
: QObject{nullptr}
|
: QObject{nullptr}
|
||||||
, m_llmodel(new GPTJ)
|
, m_llmodel(nullptr)
|
||||||
, m_responseTokens(0)
|
, m_responseTokens(0)
|
||||||
, m_responseLogits(0)
|
, m_responseLogits(0)
|
||||||
{
|
{
|
||||||
@ -30,19 +30,24 @@ LLMObject::LLMObject()
|
|||||||
|
|
||||||
bool LLMObject::loadModel()
|
bool LLMObject::loadModel()
|
||||||
{
|
{
|
||||||
if (isModelLoaded())
|
return loadModelPrivate(modelList().first());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LLMObject::loadModelPrivate(const QString &modelName)
|
||||||
|
{
|
||||||
|
if (isModelLoaded() && m_modelName == modelName)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
if (isModelLoaded()) {
|
||||||
dir.setNameFilters(QStringList() << "ggml-*.bin");
|
delete m_llmodel;
|
||||||
QStringList fileNames = dir.entryList();
|
m_llmodel = nullptr;
|
||||||
if (fileNames.isEmpty()) {
|
emit isModelLoadedChanged();
|
||||||
qDebug() << "ERROR: Could not find any applicable models in directory"
|
|
||||||
<< QCoreApplication::applicationDirPath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString modelName = fileNames.first();
|
m_llmodel = new GPTJ;
|
||||||
QString filePath = QCoreApplication::applicationDirPath() + QDir::separator() + modelName;
|
|
||||||
|
QString filePath = QCoreApplication::applicationDirPath() + QDir::separator() +
|
||||||
|
"ggml-" + modelName + ".bin";
|
||||||
QFileInfo info(filePath);
|
QFileInfo info(filePath);
|
||||||
if (info.exists()) {
|
if (info.exists()) {
|
||||||
|
|
||||||
@ -51,17 +56,15 @@ bool LLMObject::loadModel()
|
|||||||
emit isModelLoadedChanged();
|
emit isModelLoadedChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_llmodel) {
|
if (m_llmodel)
|
||||||
m_modelName = info.completeBaseName().remove(0, 5); // remove the ggml- prefix
|
setModelName(info.completeBaseName().remove(0, 5)); // remove the ggml- prefix
|
||||||
emit modelNameChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_llmodel;
|
return m_llmodel;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LLMObject::isModelLoaded() const
|
bool LLMObject::isModelLoaded() const
|
||||||
{
|
{
|
||||||
return m_llmodel->isModelLoaded();
|
return m_llmodel && m_llmodel->isModelLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLMObject::regenerateResponse()
|
void LLMObject::regenerateResponse()
|
||||||
@ -119,6 +122,46 @@ QString LLMObject::modelName() const
|
|||||||
return m_modelName;
|
return m_modelName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLMObject::setModelName(const QString &modelName)
|
||||||
|
{
|
||||||
|
m_modelName = modelName;
|
||||||
|
emit modelNameChanged();
|
||||||
|
emit modelListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLMObject::modelNameChangeRequested(const QString &modelName)
|
||||||
|
{
|
||||||
|
if (!loadModelPrivate(modelName))
|
||||||
|
qWarning() << "ERROR: Could not load model" << modelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QString> LLMObject::modelList() const
|
||||||
|
{
|
||||||
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
|
dir.setNameFilters(QStringList() << "ggml-*.bin");
|
||||||
|
QStringList fileNames = dir.entryList();
|
||||||
|
if (fileNames.isEmpty()) {
|
||||||
|
qWarning() << "ERROR: Could not find any applicable models in directory"
|
||||||
|
<< QCoreApplication::applicationDirPath();
|
||||||
|
return QList<QString>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QString> list;
|
||||||
|
for (QString f : fileNames) {
|
||||||
|
QString filePath = QCoreApplication::applicationDirPath() + QDir::separator() + f;
|
||||||
|
QFileInfo info(filePath);
|
||||||
|
QString name = info.completeBaseName().remove(0, 5);
|
||||||
|
if (info.exists()) {
|
||||||
|
if (name == m_modelName)
|
||||||
|
list.prepend(name);
|
||||||
|
else
|
||||||
|
list.append(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
bool LLMObject::handleResponse(const std::string &response)
|
bool LLMObject::handleResponse(const std::string &response)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
@ -172,8 +215,12 @@ LLM::LLM()
|
|||||||
connect(m_llmodel, &LLMObject::responseStarted, this, &LLM::responseStarted, Qt::QueuedConnection);
|
connect(m_llmodel, &LLMObject::responseStarted, this, &LLM::responseStarted, Qt::QueuedConnection);
|
||||||
connect(m_llmodel, &LLMObject::responseStopped, this, &LLM::responseStopped, Qt::QueuedConnection);
|
connect(m_llmodel, &LLMObject::responseStopped, this, &LLM::responseStopped, Qt::QueuedConnection);
|
||||||
connect(m_llmodel, &LLMObject::modelNameChanged, this, &LLM::modelNameChanged, Qt::QueuedConnection);
|
connect(m_llmodel, &LLMObject::modelNameChanged, this, &LLM::modelNameChanged, Qt::QueuedConnection);
|
||||||
|
connect(m_llmodel, &LLMObject::modelListChanged, this, &LLM::modelListChanged, Qt::QueuedConnection);
|
||||||
connect(this, &LLM::promptRequested, m_llmodel, &LLMObject::prompt, Qt::QueuedConnection);
|
connect(this, &LLM::promptRequested, m_llmodel, &LLMObject::prompt, Qt::QueuedConnection);
|
||||||
|
connect(this, &LLM::modelNameChangeRequested, m_llmodel, &LLMObject::modelNameChangeRequested, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
// The following are blocking operations and will block the gui thread, therefore must be fast
|
||||||
|
// to respond to
|
||||||
connect(this, &LLM::regenerateResponseRequested, m_llmodel, &LLMObject::regenerateResponse, Qt::BlockingQueuedConnection);
|
connect(this, &LLM::regenerateResponseRequested, m_llmodel, &LLMObject::regenerateResponse, Qt::BlockingQueuedConnection);
|
||||||
connect(this, &LLM::resetResponseRequested, m_llmodel, &LLMObject::resetResponse, Qt::BlockingQueuedConnection);
|
connect(this, &LLM::resetResponseRequested, m_llmodel, &LLMObject::resetResponse, Qt::BlockingQueuedConnection);
|
||||||
connect(this, &LLM::resetContextRequested, m_llmodel, &LLMObject::resetContext, Qt::BlockingQueuedConnection);
|
connect(this, &LLM::resetContextRequested, m_llmodel, &LLMObject::resetContext, Qt::BlockingQueuedConnection);
|
||||||
@ -232,6 +279,18 @@ QString LLM::modelName() const
|
|||||||
return m_llmodel->modelName();
|
return m_llmodel->modelName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLM::setModelName(const QString &modelName)
|
||||||
|
{
|
||||||
|
// doesn't block but will unload old model and load new one which the gui can see through changes
|
||||||
|
// to the isModelLoaded property
|
||||||
|
emit modelNameChangeRequested(modelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QString> LLM::modelList() const
|
||||||
|
{
|
||||||
|
return m_llmodel->modelList();
|
||||||
|
}
|
||||||
|
|
||||||
bool LLM::checkForUpdates() const
|
bool LLM::checkForUpdates() const
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_LINUX)
|
#if defined(Q_OS_LINUX)
|
||||||
|
19
llm.h
19
llm.h
@ -8,15 +8,15 @@
|
|||||||
class LLMObject : public QObject
|
class LLMObject : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QList<QString> modelList READ modelList NOTIFY modelListChanged)
|
||||||
Q_PROPERTY(bool isModelLoaded READ isModelLoaded NOTIFY isModelLoadedChanged)
|
Q_PROPERTY(bool isModelLoaded READ isModelLoaded NOTIFY isModelLoadedChanged)
|
||||||
Q_PROPERTY(QString response READ response NOTIFY responseChanged)
|
Q_PROPERTY(QString response READ response NOTIFY responseChanged)
|
||||||
Q_PROPERTY(QString modelName READ modelName NOTIFY modelNameChanged)
|
Q_PROPERTY(QString modelName READ modelName WRITE setModelName NOTIFY modelNameChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LLMObject();
|
LLMObject();
|
||||||
|
|
||||||
bool loadModel();
|
|
||||||
bool isModelLoaded() const;
|
bool isModelLoaded() const;
|
||||||
void regenerateResponse();
|
void regenerateResponse();
|
||||||
void resetResponse();
|
void resetResponse();
|
||||||
@ -26,9 +26,14 @@ public:
|
|||||||
QString response() const;
|
QString response() const;
|
||||||
QString modelName() const;
|
QString modelName() const;
|
||||||
|
|
||||||
|
QList<QString> modelList() const;
|
||||||
|
void setModelName(const QString &modelName);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
bool prompt(const QString &prompt, const QString &prompt_template, int32_t n_predict, int32_t top_k, float top_p,
|
bool prompt(const QString &prompt, const QString &prompt_template, int32_t n_predict, int32_t top_k, float top_p,
|
||||||
float temp, int32_t n_batch);
|
float temp, int32_t n_batch);
|
||||||
|
bool loadModel();
|
||||||
|
void modelNameChangeRequested(const QString &modelName);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void isModelLoadedChanged();
|
void isModelLoadedChanged();
|
||||||
@ -36,8 +41,10 @@ Q_SIGNALS:
|
|||||||
void responseStarted();
|
void responseStarted();
|
||||||
void responseStopped();
|
void responseStopped();
|
||||||
void modelNameChanged();
|
void modelNameChanged();
|
||||||
|
void modelListChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool loadModelPrivate(const QString &modelName);
|
||||||
bool handleResponse(const std::string &response);
|
bool handleResponse(const std::string &response);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -53,9 +60,10 @@ private:
|
|||||||
class LLM : public QObject
|
class LLM : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QList<QString> modelList READ modelList NOTIFY modelListChanged)
|
||||||
Q_PROPERTY(bool isModelLoaded READ isModelLoaded NOTIFY isModelLoadedChanged)
|
Q_PROPERTY(bool isModelLoaded READ isModelLoaded NOTIFY isModelLoadedChanged)
|
||||||
Q_PROPERTY(QString response READ response NOTIFY responseChanged)
|
Q_PROPERTY(QString response READ response NOTIFY responseChanged)
|
||||||
Q_PROPERTY(QString modelName READ modelName NOTIFY modelNameChanged)
|
Q_PROPERTY(QString modelName READ modelName WRITE setModelName NOTIFY modelNameChanged)
|
||||||
Q_PROPERTY(bool responseInProgress READ responseInProgress NOTIFY responseInProgressChanged)
|
Q_PROPERTY(bool responseInProgress READ responseInProgress NOTIFY responseInProgressChanged)
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -72,7 +80,10 @@ public:
|
|||||||
QString response() const;
|
QString response() const;
|
||||||
bool responseInProgress() const { return m_responseInProgress; }
|
bool responseInProgress() const { return m_responseInProgress; }
|
||||||
|
|
||||||
|
QList<QString> modelList() const;
|
||||||
|
|
||||||
QString modelName() const;
|
QString modelName() const;
|
||||||
|
void setModelName(const QString &modelName);
|
||||||
|
|
||||||
Q_INVOKABLE bool checkForUpdates() const;
|
Q_INVOKABLE bool checkForUpdates() const;
|
||||||
|
|
||||||
@ -85,7 +96,9 @@ Q_SIGNALS:
|
|||||||
void regenerateResponseRequested();
|
void regenerateResponseRequested();
|
||||||
void resetResponseRequested();
|
void resetResponseRequested();
|
||||||
void resetContextRequested();
|
void resetContextRequested();
|
||||||
|
void modelNameChangeRequested(const QString &modelName);
|
||||||
void modelNameChanged();
|
void modelNameChanged();
|
||||||
|
void modelListChanged();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void responseStarted();
|
void responseStarted();
|
||||||
|
41
main.qml
41
main.qml
@ -32,18 +32,47 @@ Window {
|
|||||||
visible: LLM.isModelLoaded
|
visible: LLM.isModelLoaded
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
id: modelNameField
|
id: modelLabel
|
||||||
color: "#d1d5db"
|
color: "#d1d5db"
|
||||||
padding: 20
|
padding: 20
|
||||||
font.pixelSize: 24
|
font.pixelSize: 24
|
||||||
text: "GPT4ALL Model: " + LLM.modelName
|
text: ""
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: "#202123"
|
color: "#202123"
|
||||||
}
|
}
|
||||||
horizontalAlignment: TextInput.AlignHCenter
|
horizontalAlignment: TextInput.AlignRight
|
||||||
Accessible.role: Accessible.Heading
|
}
|
||||||
Accessible.name: text
|
|
||||||
Accessible.description: qsTr("Displays the model name that is currently loaded")
|
ComboBox {
|
||||||
|
id: comboBox
|
||||||
|
width: 400
|
||||||
|
anchors.top: modelLabel.top
|
||||||
|
anchors.bottom: modelLabel.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
font.pixelSize: 24
|
||||||
|
spacing: 0
|
||||||
|
model: LLM.modelList
|
||||||
|
Accessible.role: Accessible.ComboBox
|
||||||
|
Accessible.name: qsTr("ComboBox for displaying/picking the current model")
|
||||||
|
Accessible.description: qsTr("Use this for picking the current model to use; the first item is the current model")
|
||||||
|
contentItem: Text {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
leftPadding: 10
|
||||||
|
rightPadding: 10
|
||||||
|
text: comboBox.displayText
|
||||||
|
font: comboBox.font
|
||||||
|
color: "#d1d5db"
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
background: Rectangle {
|
||||||
|
color: "#242528"
|
||||||
|
}
|
||||||
|
|
||||||
|
onActivated: {
|
||||||
|
LLM.modelName = comboBox.currentText
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user